Attribute VB_Name = "ObjectsAndPropertiesTree"
Option Explicit

Private o_indent$
Private in_dent&
Public Interrupted$
Public nDB As Database
Public DBForImportIsOpen As Boolean
Public DisplayImportedData As Boolean

Private m1$, m2$, m3$, b1$, b2$, b3$

Public DP As Boolean
Private plist$, plistf$

Private TDB$  'text version
Public ExportDb$

Public ImportFileName$
Public ImportHandler%
Public ImportFile$
Public IPos&, ILen&

Public espot$



Public Function AddEs$(s$)
Dim ss$

ss = Replace(s, "\", "\\")
ss = Replace(ss, "=", "\e")
ss = Replace(ss, vbCrLf, "\l")
ss = Replace(ss, vbCr, "\r")
ss = Replace(ss, vbLf, "\n")
AddEs = Replace(ss, Chr(0), "\z")

End Function

Private Sub AddK(s$, ss$)
  append_loosely ExportDb, _
      AddEs(s) & "=" & AddEs(ss) & vbCrLf
End Sub






'ADDK AND SKIP = FOR EMPTY VALUE
'
Private Sub AddKS(s$, ss$)
Select Case Len(ss)
      Case 0: append_loosely ExportDb, _
                 AddEs(s) & vbCrLf
      Case Else
           append_loosely ExportDb, _
                 AddEs(s) & "=" & AddEs(ss) & vbCrLf
  End Select
End Sub


Private Sub AddL()
 append_loosely ExportDb, vbCrLf
End Sub


Private Sub AddNull(s$)
 append_loosely ExportDb, AddEs(s) & "=\N" & vbCrLf
End Sub

Private Sub AddP(s$, ss$)
  plistf = Replace(plistf, "," & UCase(s) & ", ", "")
  If DisplayImportedData Then ri s & " = " & ss
  LableProgress s
  AddK s, ss
End Sub


Public Function DbString2Type&(s$)
Dim n&

Select Case s
    
    Case "dbBigInt": n = dbBigInt
    Case "dbBinary": n = dbBinary
    Case "dbBoolean": n = dbBoolean
    Case "dbByte": n = dbByte
    Case "dbChar":  n = dbChar
    Case "dbCurrency":  n = dbCurrency
    Case "dbDate": n = dbDate
    Case "dbDecimal": n = dbDecimal
    Case "dbDouble": n = dbDouble
    Case "dbFloat": n = dbFloat
    Case "dbGUID": n = dbGUID
    Case "dbInteger": n = dbInteger
    Case "dbLong": n = dbLong
    Case "dbLong": n = dbLong
    Case "dbMemo": n = dbMemo
    Case "dbNumeric": n = dbNumeric
    Case "dbSingle": n = dbSingle
    Case "dbText": n = dbText
    Case "dbTime": n = dbTime
    Case "dbTimeStamp": n = dbTimeStamp
    Case "dbVarBinary": n = dbVarBinary

'For a QueryDef object, the possible settings and return values are shown in the following table.

    Case "dbQAction": n = dbQAction
    Case "dbQAppend": n = dbQAppend
    Case "dbQCompound": n = dbQCompound
    Case "dbQCrosstab": n = dbQCrosstab
    Case "dbQDDL": n = dbQDDL
    Case "dbQDelete": n = dbQDelete
    Case "dbQMakeTable": n = dbQMakeTable
    Case "dbQProcedure": n = dbQProcedure
    Case "dbQSelect": n = dbQSelect
    Case "dbQSetOperation": n = dbQSetOperation
    Case "dbQSPTBulk": n = dbQSPTBulk
    Case "dbQSQLPassThrough": n = dbQSQLPassThrough
    Case "dbQUpdate": n = dbQUpdate

          'Note   To create an SQL pass-through query in a Microsoft Jet workspace, you don't need to           'explicitly 'set the Type property to dbQSQLPassThrough. The Microsoft Jet database engine           'automatically sets this 'when you create a QueryDef object and set the Connect property.

          'For a Recordset object, the possible settings and return values are as follows.


    Case "dbOpenTable": n = dbOpenTable
    Case "dbOpenDynamic": n = dbOpenDynamic
    Case "dbOpenDynaset": n = dbOpenDynaset
    Case "dbOpenSnapshot": n = dbOpenSnapshot
    Case "dbOpenForwardOnly": n = dbOpenForwardOnly
         'For a Workspace object, the possible settings and return values are as follows.


    Case "dbUseJet": n = dbUseJet
    Case "dbUseODBC": n = "dbUseODBC"
    Case Else:  Err.Raise 2096, , "Unknown db type " & s & _
                                  "im my program DbString2Type."
End Select

DbString2Type = n


End Function

Public Function DBType2String$(n&)
Dim s$
Select Case n
    Case dbBigInt: s = "dbBigInt"
    Case dbBinary: s = "dbBinary"
    Case dbBoolean: s = "dbBoolean"
    Case dbByte: s = "dbByte"
    Case dbChar: s = "dbChar"
    Case dbCurrency: s = "dbCurrency"
    Case dbDate: s = "dbDate"
    Case dbDecimal: s = "dbDecimal"
    Case dbDouble: s = "dbDouble"
    Case dbFloat: s = "dbFloat"
    Case dbGUID: s = "dbGUID"
    Case dbInteger: s = "dbInteger"
    Case dbLong: s = "dbLong"
    Case dbLongBinary: s = "dbLongBinary"
    Case dbMemo: s = "dbMemo"
    Case dbNumeric: s = "dbNumeric"
    Case dbSingle: s = "dbSingle"
    Case dbText: s = "dbText"
    Case dbTime: s = "dbTime"
    Case dbTimeStamp: s = "dbTimeStamp"
    Case dbVarBinary: s = "dbVarBinary"

'For a QueryDef object, the possible settings and return values are shown in the following table.

    Case dbQAction: s = "dbQAction"
    Case dbQAppend: s = "dbQAppend"
    Case dbQCompound: s = "dbQCompound"
    Case dbQCrosstab: s = "dbQCrosstab"
    Case dbQDDL: s = "dbQDDL"
    Case dbQDelete: s = "dbQDelete"
    Case dbQMakeTable: s = "dbQMakeTable"
    Case dbQProcedure: s = "dbQProcedure"
    Case dbQSelect: s = "dbQSelect"
    Case dbQSetOperation: s = "dbQSetOperation"
    Case dbQSPTBulk: s = "dbQSPTBulk"
    Case dbQSQLPassThrough: s = "dbQSQLPassThrough"
    Case dbQUpdate: s = "dbQUpdate"

          'Note   To create an SQL pass-through query in a Microsoft Jet workspace, you don't need to           'explicitly 'set the Type property to dbQSQLPassThrough. The Microsoft Jet database engine           'automatically sets this 'when you create a QueryDef object and set the Connect property.

          'For a Recordset object, the possible settings and return values are as follows.


    Case dbOpenTable: s = "dbOpenTable"
    Case dbOpenDynamic: s = "dbOpenDynamic"
    Case dbOpenDynaset: s = "dbOpenDynaset"
    Case dbOpenSnapshot: s = "dbOpenSnapshot"
    Case dbOpenForwardOnly: s = "dbOpenForwardOnly"
                               'For a Workspace object, the possible settings and return values are as follows.


    Case dbUseJet:  s = "dbUseJet"
    Case dbUseODBC: s = "dbUseODBC"
    Case Else:      s = "UnknownDbType"

End Select

DBType2String = s

End Function


Private Sub DelAndNotify(s$)
 plistf = Replace(plistf, "," & UCase(s) & ", ", "")
 If DisplayImportedData Then ri s & " - property is not exported."
End Sub

'DeleteProcessedName from plistf
'
Private Sub DelPN(s$)
  plistf = Replace(plistf, "," & UCase(s) & ", ", "")
End Sub


'DeleteProcessedName from plistf
'and type value v.
Private Sub DelPNP(s$, v$)
  plistf = Replace(plistf, "," & UCase(s) & ", ", "")
  If DisplayImportedData Then ri s & " = " & v
End Sub

Public Function DescribeDbType(n&)
Dim s$
Select Case n
    Case dbBigInt: s = "Big Integer"
    Case dbBinary: s = "  Binary"
    Case dbBoolean: s = " Boolean"
    Case dbByte: s = "    Byte"
    Case dbChar: s = "    Char"
    Case dbCurrency: s = "    Currency"
    Case dbDate: s = "    Date/Time"
    Case dbDecimal: s = " Decimal"
    Case dbDouble: s = "  Double"
    Case dbFloat: s = "   Float"
    Case dbGUID: s = "    GUID"
    Case dbInteger: s = " Integer"
    Case dbLong: s = "    Long"
    Case dbLongBinary: s = "  Long Binary (OLE Object)"
    Case dbMemo: s = "    Memo"
    Case dbNumeric: s = " Numeric"
    Case dbSingle: s = "  Single"
    Case dbText: s = "    Text"
    Case dbTime: s = "    Time"
    Case dbTimeStamp: s = "   Time Stamp"
    Case dbVarBinary: s = "   VarBinary"

'For a QueryDef object, the possible settings and return values are shown in the following table.

    Case dbQAction: s = " Action"
    Case dbQAppend: s = " Append"
    Case dbQCompound: s = "   Compound"
    Case dbQCrosstab: s = "   Crosstab"
    Case dbQDDL: s = "    Data-definition"
    Case dbQDelete: s = " Delete"
    Case dbQMakeTable: s = "  Make-table"
    Case dbQProcedure: s = "  Procedure (ODBCDirect workspaces only)"
    Case dbQSelect: s = " Select"
    Case dbQSetOperation: s = "   Union"
    Case dbQSPTBulk: s = "    Used with dbQSQLPassThrough to specify a query that doesn't return records (Microsoft Jet workspaces only)."
    Case dbQSQLPassThrough: s = " Pass-through (Microsoft Jet workspaces only)"
    Case dbQUpdate: s = " Update"

          'Note   To create an SQL pass-through query in a Microsoft Jet workspace, you don't need to           'explicitly 'set the Type property to dbQSQLPassThrough. The Microsoft Jet database engine           'automatically sets this 'when you create a QueryDef object and set the Connect property.

          'For a Recordset object, the possible settings and return values are as follows.


    Case dbOpenTable: s = "   Table (Microsoft Jet workspaces only)"
    Case dbOpenDynamic: s = " Dynamic (ODBCDirect workspaces only)"
    Case dbOpenDynaset: s = " Dynaset"
    Case dbOpenSnapshot: s = "    Snapshot"
    Case dbOpenForwardOnly: s = " Forward-only"
                               'For a Workspace object, the possible settings and return values are as follows.


    Case dbUseJet: s = "  The Workspace is connected to the Microsoft Jet database engine."
    Case dbUseODBC: s = " The Workspace is connected to an ODBC data source."
    Case Else
         s = "Unknown db type."

End Select

DescribeDbType = s

End Function


Public Sub ExportDatabase()
Dim td As TableDef
Dim nTD As TableDef
Dim FLD As Field
Dim nFLD As Field
Dim INDX As Index
Dim nINDX As Index
Dim v, s$, ss$, ws$, wi&, wj&, i&, j&
Dim p As Property

Dim NotHandledType$
Dim WhereTypeMet$
Dim Ty_pe$

Dim Rs As Recordset

Dim EC&  ' exceptions counter
EC = 0

Dim EX$        'Exceptions
DP = False

If "" = ExportDb Then
   MsgBox "New name is empty."
   Exit Sub
End If

If Not DBOpen Then
   MsgBox "Database is not open."
   Exit Sub
End If
    
On Error Resume Next
If Dir(ExportDb) <> "" Then
   Kill ExportDb
   If Err.Number > 0 Then
      MsgBox "Cannot remove database " & ExportDb
      Exit Sub
   End If
End If

'Dim nWS As Workspace

'Set nWS = DBEngine.Workspaces(1)
'Set nWS = DBEngine.CreateWorkspace("moo_name", "umoo", "")
'If Err.Number > 0 Then
'   MsgBox CStr(Err.Number) & " " & Err.Description
'   Exit Sub
'End If


'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' Create database.
'------------------------------------------------------------
On Error Resume Next
Dim DBVersion$
'string:
DBVersion = Trim(MyDB.Version)

'adds L
AddK "DBVersion", DBVersion
'------------------------------------------------------------
' ef database creation
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm



'============================================================
' set db properties
'------------------------------------------------------------
'Dim nTransactions As Boolean  '- not a table related
'phs, not important:
'nTransactions = MyDB.Transactions
'read-only:
'nDB.Transactions = nTransactions

'Dim nUpdatable As Boolean
'nUpdatable = MyDB.Updatable
'read-only:
'nDB.Updatable = nUpdatable


'CollatingOrder is already set by dbLangGeneral

Dim nQueryTimeOut%
nQueryTimeOut = MyDB.QueryTimeout
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   'Exit Sub
Else
   AddK "QueryTimeout", CStr(nQueryTimeOut)
End If


Dim nConnect$
nConnect = MyDB.Connect
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   'Exit Sub
Else
   AddK "Connect", nConnect
End If


'nRecordsAffected = MyDB.RecordsAffected
'read-only:
'nDB.RecordsAffected = nRecordsAffected


'Needs 16 bytes. Assume that string:
'phs, not important:
'Dim nReplicaID$
'nReplicaID = MyDB.ReplicaID
'read-only:
'nDB.ReplicaID = nReplicaID


'needs 16 bit:
'Dim nDesignMasterID$
'gives message: ... cannot be replicated ....
'nDesignMasterID = MyDB.DesignMasterID
'nDB.DesignMasterID = nDesignMasterID

'Dim nConnection
'nConnection = MyDB.connection

'v = TypeName(MyDB.connection)
'does not work:
'Set nDB.connection = nConnection

'---------------------------------------------------------
' ef db properties
'=========================================================




      
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
' LOOP VIA TABLES
'=============================================================

AddL  'line - mark the end of db properties

plist = ""
For Each td In MyDB.TableDefs


If "MSYS" = UCase(Left(td.Name, 4)) Then _
   GoTo SkippedSystemTables

ri ve & ve & "Table" & td.Name
AddK "Table Name", td.Name









ri ""
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
ri "FIELD LOOP"
 DP = False
 For Each FLD In td.Fields
'========================================================
   On Error Resume Next
                     
    If uInterrupted Then Exit Sub
    plistf = ""
    For Each p In FLD.Properties
        plistf = plistf & "," & UCase(p.Name) & ", "
    Next
        
    With FLD
        
    On Error GoTo AbsorbExceptions
    
    '=======================================================
    ' setting field name:
    '-------------------------------------------------------
    'string
    s = "Name"
    ss = .Name
    If DisplayImportedData Then ri ""
    ri "Field Name=" & ss
    If "" <> s Then
      plistf = Replace(plistf, "," & UCase(s) & ", ", "")
      AddK "Field Name", ss
    End If
    '=======================================================
    
    'string
    DelPN "Value"
    
    'assuming that int or long:
    'nFLD.Type = FLD.Properties("Type") '  .Type
    'nFLD.Properties("Type") = FLD.Properties("Type") '  .Type
    s = "Type"
    wi = .Type
    If "" <> s Then
    
       ss = DBType2String(wi)
       AddP s, ss
       
       Select Case wi
         Case dbLong, dbInteger
         Case dbText, dbMemo, dbChar
         Case dbDouble, dbSingle
         
         'case dbfloat
         'case dbNumeric
         'Case dbCurrency
         Case dbDate
         Case dbTime
         
         Case dbBoolean
         Case Else
              'this check is moved to a real data transfer
              'because data may be empty.
              'EC = EC + 1
              'ws = ss & " - " & DescribeDbType(.Type)
              'EX = EX & ve & "Correct conversion of type " & _
              '               ws & " to text is not guaranteed."
       End Select
       
    End If
        
    'assuming that int or long:
    '"not set" wim? -1, 0 ?
    s = "Size"
    If dbText = .Type Then
     ss = CStr(.Size)
     If "" <> s Then AddP s, ss
    Else
     DelPN s
    End If
            
    'boolean:
    s = "AllowZeroLength"
    If dbText = .Type Or dbMemo = .Type Then
       ss = CStr(.AllowZeroLength)
       If "" <> s Then AddP s, ss
    Else
       DelPN s
    End If
        
    
    'long:
    s = "Attributes"
    
    'this include: dbFixedField
    '              dbAutoIncrField
    '              dbVariableField
    ss = CStr(.Attributes)
    If "" <> s Then AddP s, ss
       
    
    'string
    'in some cases, can function as rundom ID;
    s = "DefaultValue"
    ss = .DefaultValue
    If "" <> s Then AddP s, ss
      
      
    'integer
    s = "OrdinalPosition"
    ss = CStr(.OrdinalPosition)
    If "" <> s Then AddP s, ss
    
    'boolean
    s = "Required"
    ss = .Required
    If "" <> s Then AddP s, ss
        
                 
    'string
    s = "ValidationRule"
    ss = .ValidationRule
    If "" <> s Then AddP s, ss
    
    
    'string
    s = "ValidationText"
    ss = .ValidationText
    If "" <> s Then AddP s, ss
           
    
    '=======================================
    ' disabled import for properties:
    '---------------------------------------
    
    '---------------------------------------
    ' clearly, cannot be imported:
    '---------------------------------------
    
    'assuming that valid only for text:
    'long:
    s = "CollatingOrder"
    If dbText = .Type Then
       'COMPIELER "CANNOT ASSIGN TO READ-ONLY PROPERTY":
       'nFLD.CollatingOrder = .CollatingOrder
    End If
    DelPN s
    
    'string
    'disabled by syntax:
    DelAndNotify "ValidateOnSet"
    
    'boolean
    'COMPIELER "CANNOT ASSIGN TO READ-ONLY PROPERTY":
    '(perhaps by syntax:)
    s = "DataUpdatable"
    DelPN s
    '--------------------------------------------------
    
    DelAndNotify "SourceField"
    DelAndNotify "SourceTable"
        
    'string
    DelAndNotify "ForeignName"
    
    DelAndNotify "ORIGINALVALUE"
    'belongs to RecordSet object:
    DelAndNotify "FIELDSIZE"
    'not sure what is this:
    DelAndNotify "VISIBLEVALUE"
           
    DelAndNotify "ColumnOrder"
    DelAndNotify "ColumnWidth"
    DelAndNotify "ColumnHidden"
    DelAndNotify "DecimalPlaces"
    DelAndNotify "DisplayControl"
    '=======================================
       
    End With
    
    If DisplayImportedData Then ri ve & ve
    If "" <> plistf Then plist = plist & ve & ve & _
                                 td.Name & ve & plistf

    On Error Resume Next
    AddL ' before next field, index, or end of table
'==================================================
Next 'ef FIELD LOOP
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm





'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' INDEXES
'==================================================
Dim IndxName$

On Error GoTo he
s = "INDEXES"
ri ve & s
If 0 = td.Indexes.Count Then GoTo SkippedIndexes

For Each INDX In td.Indexes
    On Error GoTo AbsorbIndexExceptions
    If uInterrupted Then Exit Sub
       
    s = "IndexName"
    v = INDX.Name 'critical
    
    IndxName = v
    s = s & " " & v
    AddK "IndexName", IndxName
    
    ri "IndexName: " & IndxName
        
    With INDX
      s = "Fields "
      ss = .Fields  '+f;+g
      s = s & ss
      AddK "Fields", Replace(ss, "+", "") '=f;g
      
      'this is too long method:
      'Dim IndexField As Field
      'Dim IndexFieldList$
      'IndexFieldList = ""
      'For Each IndexField In INDX.Fields
      '    s = IndexField.Name
      ' Next
      
      s = "Unique"  'boolean:
      ss = .Unique
      AddK s, ss
      

      s = "Primary"   'boolean:
      ss = .Primary
      AddK s, ss
      

      s = "IgnoreNulls" 'boolean
      ss = .IgnoreNulls
      AddK s, ss
      s = "Clustered" 'boolean:
      ss = .Clustered
      AddK s, ss

      
      's = "Required"  'boolean:
      'ss = .Required
      
      's = "Foreign"  'boolean:
      AddL  ' after each index
 End With
    
 s = "Appending " & IndxName
 ri s
Next
SkippedIndexes:
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm


If 0 = EC Then
   On Error GoTo he
   s = "Appending table " & td.Name
   ri ve & ve & "Table" & td.Name & " appended."
End If

SkippedSystemTables:
'=============================================================
Next 'EF LOOP VIA TABLES
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM


    
If 0 <> EC Then
   MsgBox "Exceptions: " & ve & Left(EX, 300) & " ... "
   ri EX
   Exit Sub
End If


If "" <> Replace(plist, ve, "") Then _
   ri "Not-replicated properties: " & plist



ri ""
ri ""
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
ri "MOVING DATA"
'=============================================================
AddKS "Data", ""

On Error GoTo MovingDataExceptions
For Each td In MyDB.TableDefs
    If uInterrupted Then Exit Sub
    
    If "MSYS" = UCase(Left(td.Name, 4)) Then GoTo SkipDummies
        
        wi = td.Fields.Count - 1
        If 0 = wi Then GoTo NoFieldsSkipped
        
        j = 0
        Set Rs = MyDB.OpenRecordset(td.Name, dbOpenTable)
        'dbOpenTable    Opens a table-type Recordset object
                        '(Microsoft Jet workspaces only).
        'dbOpenDynamic  Opens a dynamic-type Recordset object, which is similar to an ODBC dynamic cursor. '(ODBCDirect workspaces only)
        'dbOpenDynaset  Opens a dynaset-type Recordset object, which is similar to an ODBC keyset cursor.
        'dbOpenSnapshot Opens a snapshot-type Recordset object,
                        ' which is similar to an ODBC static cursor.
        'dbOpenForwardOnly  Opens a forward-only-type Recordset object.
        Do Until Rs.EOF
           If uInterrupted Then Exit Sub
           
           If 0 = j Then
              ri ve & ve & "Table" & td.Name
              AddK "Table", td.Name
              AddK "FieldsNumber", CStr(wi + 1)
              For i = 0 To wi
                  AddK "Field", td.Fields(i).Name
              Next
              AddL
              ri ve & "Updating table " & td.Name
           End If
           
           AddK "R", CStr(j + 1)
           For i = 0 To wi
               If IsNull(Rs(i)) Then
                  AddNull ""
               Else
                  wj = td.Fields(i).Type
                  Ty_pe = CStr(wj) & ", "
                  Select Case wj
                      Case dbText, dbMemo
                           ss = Rs(i)
                      Case dbChar
                           ss = Left(Rs(i), td.Fields(i).Size)
                      Case dbBoolean
                           ss = CStr(Rs(i))
                      Case dbDate
                           ss = Format(Rs(i), "mm/dd/yyyy")
                      Case dbTime
                           ss = Format(Rs(i), "Hh:mm:Ss")
                      Case dbLong, dbInteger, dbDouble, dbSingle
                           ss = CStr(Rs(i))
                      Case Else:
                           If InStr(NotHandledType, _
                              Ty_pe) = 0 Then
                              NotHandledType = _
                                NotHandledType & Ty_pe
                              WhereTypeMet = WhereTypeMet & _
                                 Ty_pe & DescribeDbType(wj) & ve & _
                                "Table Name=" & td.Name & ve & _
                                "Field Name=" & td.Fields(i).Name & ve & _
                                "Record Number=" & CStr(j + 1)
                           End If
                           ss = CStr(Rs(i))
                  End Select
                  AddK "", ss
               End If
           Next
           AddL
           Rs.MoveNext
           j = j + 1
           LableProgress CStr(j)
        Loop
        If "" <> NotHandledType Then
           EC = EC + 1
           ws = "Correct handling of " & _
                "this types is not quaranteed: " & ve & _
                WhereTypeMet
           EX = EX & ve & ws
           WhereTypeMet = ""
           NotHandledType = ""
        End If
        ri CStr(j) & " records moved to table " & td.Name
 

NoFieldsSkipped:
SkipDummies:
Next
Set Rs = Nothing
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

AddKS "EndOfDatabase", ""

'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' ADDITIONAL CHECKS
'-------------------------------------------------------------
If MyDB.Recordsets.Count > 0 Then
   EC = EC + 1
   EX = EX & ve & EC & " There are " & _
           MyDB.Recordsets.Count & " RecordSets which are ignored. "
End If

If MyDB.QueryDefs.Count > 0 Then
   EC = EC + 1
   EX = EX & ve & EC & " There are " & _
           MyDB.Recordsets.Count & " QueryDefinitions which are ignored. "
End If

If MyDB.Relations.Count > 0 Then
   EC = EC + 1
   EX = EX & ve & EC & " There are " & _
           MyDB.Recordsets.Count & " Relations which are ignored. "
End If
'-------------------------------------------------------------
' ef ADDITIONAL CHECKS
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm




'-------------------------------------------------------------
'  FINAL REPORT
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If 0 <> EC Then
   
   s = "Export attemt is done. Exceptions are: " & ve & EX
   ri s
   MsgBox Left(s, 500) & " ... "

Else
   
   s = "Database " & ImportFromDatabaseName & ve & _
       "has been succesfully exported to" & ve & _
       ExportDb
   ri ve & s
   MsgBox s

End If
'-------------------------------------------------------------

    
    
Exit Sub

AbsorbExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Field Property = " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
AbsorbIndexExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Index = " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
    
MovingDataExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Moving data: " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       ri EX
       Exit Sub
       'Resume Next
    
    
    
    
he: s = s & ve & "Process Terminated: " & ve & _
        Err.Number & " " & Err.Description & ve & _
        espot
    If "" <> EX Then
       s = s & ve & "Another exceptions: " & ve & EX
    End If
    ri s
    MsgBox s
    Exit Sub
    

End Sub

Public Sub ImportDatabase(NewPath$)
Dim nTD As TableDef
Dim NewTableName$
Dim nFLD As Field
Dim nINDX As Index
Dim v, s$, ss$, sss$, i&, ii&, j&
Dim ws$
Dim IndxName$

Dim Rs As Recordset
Dim nRS As Recordset

Dim wi&, SavedFields$(), CurrentFI&()

Dim EC&  ' exceptions counter
EC = 0

Dim EX$        'Exceptions
DP = False

If "" = NewPath Then
   MsgBox "New name is empty."
   Exit Sub
End If

On Error Resume Next
If Dir(NewPath) <> "" Then
   Kill NewPath
   If Err.Number > 0 Then
      MsgBox "Cannot remove database " & NewPath
      Exit Sub
   End If
End If

If MyWs Is Nothing Then
  'name, user, password
  Set MyWs = DBEngine.CreateWorkspace("MyNewWorkspace", "admin", "")
End If
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Exit Sub
End If


'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' Create database.
'------------------------------------------------------------
On Error Resume Next
Dim DBVersion$
'string:

If "X" = ReadKC("DBVersion", DBVersion) Then Exit Sub

'adds L

Select Case DBVersion
  Case "1.0": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion10)
  Case "1.1": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion11)
  Case "2.0": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion20)
  Case "3.0": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion30)
End Select
If Err.Number > 0 Then
   MsgBox "Database creation exception." & ve & _
          Err.Number & " " & Err.Description
   Exit Sub
End If
DBForImportIsOpen = True
'------------------------------------------------------------
' ef database creation
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm



'============================================================
' set db properties
'------------------------------------------------------------

Dim nQueryTimeOut%
If "X" = ReadKC("QueryTimeOut", ss) Then Exit Sub
nDB.QueryTimeout = CInt(ss)
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   Exit Sub
End If


Dim nConnect$
If "X" = ReadKC("Connect", nConnect) Then Exit Sub
nDB.Connect = nConnect
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   Exit Sub
End If
'---------------------------------------------------------
' ef db properties
'=========================================================



If "X" = ReadOneOrMoreLines(s, ss) Then Exit Sub
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
LOOP_VIA_TABLES:
'=============================================================
If UCase(s) <> "TABLE NAME" Then GoTo MOVE_DATA
NewTableName = ss
ri ve & ve & "Table " & NewTableName

Set nTD = nDB.CreateTableDef()
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Exit Sub
End If


nTD.Name = NewTableName
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Exit Sub
End If


ri ""
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
ri "FIELD LOOP"
If "X" = ReadK(s, ss) Then Exit Sub
FieldLoop:
'========================================================
    
    On Error Resume Next
                     
    '=======================================================
    ' setting field name:
    '-------------------------------------------------------
    If "FIELD NAME" <> UCase(s) Then GoTo Indexes
    Set nFLD = nTD.CreateField
    nFLD.Name = ss
    '=======================================================
        
    On Error GoTo AbsorbExceptions
    With nFLD
    
    'assuming that int or long:
    If "X" = ReadKC("Type", ss) Then Exit Sub
    .Type = DbString2Type(ss)  'CLng(ss)
        
    
    'assuming that int or long:
    '"not set" wim? -1, 0 ?
    If dbText = .Type Then
     If "X" = ReadKC("Size", ss) Then Exit Sub
     .Size = CLng(.Size)
    End If
            
    'boolean:
    If dbText = .Type Or dbMemo = .Type Then
       If "X" = ReadKC("AllowZeroLength", ss) Then Exit Sub
       .AllowZeroLength = CBool(ss)
    End If
        
    
    'long:
    ss = CStr(.Attributes)
    If "X" = ReadKC("Attributes", ss) Then Exit Sub
    nFLD.Attributes = CLng(ss)
    
    
    'string
    'in some cases, can function as rundom ID;
    If "X" = ReadKC("DefaultValue", ss) Then Exit Sub
    .DefaultValue = ss
       
      
    'integer
    If "X" = ReadKC("OrdinalPosition", ss) Then Exit Sub
    .OrdinalPosition = CInt(ss)
    
    'boolean
    If "X" = ReadKC("Required", ss) Then Exit Sub
    .Required = CBool(ss)
        
    'string
    If "X" = ReadKC("ValidationRule", ss) Then Exit Sub
    .ValidationRule = ss
    
    'string
    If "X" = ReadKC("ValidationText", ss) Then Exit Sub
    .ValidationText = ss
      
   
    On Error Resume Next
    If 0 = EC Then
       nTD.Fields.Append nFLD
    End If
    If Err.Number > 0 Then Err.Clear
                   
    If "X" = ReadOneOrMoreLines(s, ss) Then Exit Sub
    End With
    
'==================================================
GoTo FieldLoop
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm



'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
Indexes: If "INDEXNAME" <> UCase(s) Then
           If 0 = EC Then
              On Error GoTo he
              espot = "Appending table " & NewTableName
              nDB.TableDefs.Append nTD
              ri ve & ve & "Table" & NewTableName & " appended."
              GoTo LOOP_VIA_TABLES
           End If
         End If
'==================================================

  On Error GoTo AbsorbIndexExceptions

    v = ss  'critical
    IndxName = ss
    
    s = IndxName
    ri "Index: " & IndxName
    Set nINDX = nTD.CreateIndex(v)
        
        
    With nINDX
      s = "Fields"
      If "X" = ReadKC(s, ss) Then Exit Sub
      .Fields = ss '=f;g
      
      s = "Unique"  'boolean:
      If "X" = ReadKC(s, ss) Then Exit Sub
      .Unique = CBool(ss)
      
      s = "Primary"   'boolean:
      If "X" = ReadKC(s, ss) Then Exit Sub
      .Primary = CBool(ss)
      
      s = "IgnoreNulls" 'boolean
      If "X" = ReadKC(s, ss) Then Exit Sub
      .IgnoreNulls = CBool(ss)
      
      s = "Clustered" 'boolean:
      If "X" = ReadKC(s, ss) Then Exit Sub
      .Clustered = CBool(ss)

 End With
    
 espot = "Appending " & IndxName
 ri espot
 nTD.Indexes.Append nINDX
 If "X" = ReadOneOrMoreLines(s, ss) Then Exit Sub
 GoTo Indexes
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm








'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MOVE_DATA:

  nDB.Close
  DBForImportIsOpen = False
  If 0 <> EC Then
     MsgBox "Exceptions: " & ve & Left(EX, 300) & " ... "
     ri EX
     Exit Sub
  End If

  ri ""
  ri ""
  ri "MOVING DATA"
  '=============================================================
  If "DATA" <> UCase(s) Then
      MsgBox "Corrupted data part: missed title ""Data""."
      Exit Sub
  End If
   
On Error GoTo he
Set nDB = MyWs.OpenDatabase(NewPath)
DBForImportIsOpen = True

On Error GoTo MovingDataExceptions

If "X" = ReadK(s, ss) Then Exit Sub

MoveTableAgain:
     If "TABLE" <> UCase(s) Then GoTo END_OF_DATA

Set nTD = nDB.TableDefs(ss)
If uInterrupted Then Exit Sub
ri ve & ve & "Table" & nTD.Name
    
            
If "X" = ReadKC("FieldsNumber", ss) Then Exit Sub

wi = nTD.Fields.Count - 1
j = 0
        
ReDim SavedFields(wi)
ReDim CurrentFI(wi)
For i = 0 To wi
    If "X" = ReadKC("Field", ss) Then Exit Sub
    SavedFields(i) = ss
Next
        
For i = 0 To wi
    For ii = 0 To wi
        If UCase(SavedFields(ii)) = UCase(nTD.Fields(i).Name) Then
           CurrentFI(ii) = i
        End If
    Next
Next
          
      
        
MoveNextRecord:
   
   If uInterrupted Then Exit Sub
           
   If "X" = ReadOneOrMoreLines(s, ss) Then Exit Sub
   If "R" <> UCase(s) Then
      If 0 <> j Then ri CStr(j) & _
         " record(s) moved to table " & nTD.Name
      GoTo MoveTableAgain
   End If
           
   If j + 1 <> CLng(ss) Then
      MsgBox "Records numbers do not match. Corrupted Import File."
      Exit Sub
   End If
           
   If DisplayImportedData Then ri "Record " & ss
           
   If 0 = j Then
      Set nRS = nDB.OpenRecordset(nTD.Name, dbOpenDynaset)
      ri ve & "Updating table " & nTD.Name
   End If
           
   nRS.AddNew
              
   For ii = 0 To wi
               'I DID NOT FIND NOTE IN MS DOCUMENTATION
               'THAT THIS ENUMERATION IS CONSISTENT FROM
               'RECORD TO RECORD, BUT I AM ASSUMING IT
               'AddK "", Rs(i)
               sss = ReadK("", ss)
               Select Case sss
                      Case "X": Exit Sub
                      Case "N": 'null, do nothing
                      Case "K":  'not corrupted file
                           i = CurrentFI(ii)
                           Select Case nTD.Fields(i).Type
                                  
                                  Case dbText, dbMemo
                                       nRS.Fields(i) = ss
                                  
                                  Case dbChar
                                       'hope this is a correct conversion:
                                       ws = String(nTD.Fields(i).Size, " ")
                                       LSet ws = ss
                                       nRS.Fields(i) = ss
                                  
                                  Case dbBoolean
                                       nRS.Fields(i) = CBool(ss)
                                  Case dbSingle
                                       nRS.Fields(i) = CSng(ss)
                                  Case dbDouble
                                       nRS.Fields(i) = CDbl(ss)
                                       
                                  Case dbFloat
                                       'not sure:
                                       nRS.Fields(i) = CSng(ss)
                                  
                                  Case dbLong
                                       nRS.Fields(i) = CLng(ss)
                                  Case dbInteger
                                       nRS.Fields(i) = CInt(ss)
                                  Case Else: nRS.Fields(i) = ss
                           End Select
               End Select
           Next
           nRS.Update
           j = j + 1

   If DisplayImportedData Then ri CStr(j) & " record(s) were moved."
   LableProgress CStr(j)
   GoTo MoveNextRecord

'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
END_OF_DATA:

Set nRS = Nothing
Set Rs = Nothing
nDB.Close
DBForImportIsOpen = False

If "ENDOFDATABASE" <> UCase(s) Then
   MsgBox "Missed ""EndOfDatabase"" last line."
End If


'-------------------------------------------------------------
'  FINAL REPORT
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If 0 <> EC Then
   
   s = "Import attemt is done. Exceptions are: " & ve & EX
   MsgBox Left(s, 500) & " ... "
   ri s

Else

   MsgBox "Database " & ImportFileName & ve & _
          "has been succesfully imported to " & ve & NewPath

End If
'-------------------------------------------------------------

    
    
Exit Sub

AbsorbExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Field Property = " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
AbsorbIndexExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Index = " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
    
MovingDataExceptions:
       ws = " Exc in Moving data: " & s & ve & _
            Err.Number & " " & Err.Description & ve
       ri ws
       EC = EC + 1
       EX = EX & EC & ws
       s = ""
       Resume Next
    
    
    
    
he: s = s & ve & "Process Terminated: " & ve & _
        Err.Number & " " & Err.Description & ve & espot
    If "" <> EX Then
       s = s & ve & "Another exceptions: " & ve & EX
    End If
    ri s
    MsgBox s
    Exit Sub
    
End Sub


Private Sub LableProgress(s$)
frmMain.lblProgress = s
End Sub

Public Function OpenImportFile$()

On Error GoTo he
ImportHandler = FreeFile

ILen = FileLen(ImportFileName)
ImportFile = String(ILen, " ")

Open ImportFileName For Binary Access Read Shared As ImportHandler
Get #ImportHandler, 1, ImportFile
Close ImportHandler
IPos = 1
Exit Function

he:
  MsgBox "Exception " & Err.Number & " " & _
         Err.Description & vbCrLf & _
         "when opening " & ImportFileName
  Exit Function
  
End Function

Public Function ListDbTypes$()
Dim s$

s = "MJ - Microsoft Jet.  DS - Data Source." & ve
s = s & ve & dbBigInt & "  - dbBigInt - Big Integer"

    s = s & ve & dbBinary & "  - dbBinary - Binary"
    s = s & ve & dbBoolean & "  - dbBoolean - Boolean"
    s = s & ve & dbByte & "  - dbByte - Byte"
    s = s & ve & dbChar & "  - dbChar - Char"
    s = s & ve & dbCurrency & "  - dbCurrency - Currency"
    s = s & ve & dbDate & "  - dbDate - Date/Time"
    s = s & ve & dbDecimal & "  - dbDecimal - Decimal"
    s = s & ve & dbDouble & "  - dbDouble - Double"
    s = s & ve & dbFloat & "  - dbFloat - Float"
    s = s & ve & dbGUID & "  - dbGUID - GUID"
    s = s & ve & dbInteger & "  - dbInteger - Integer"
    s = s & ve & dbLong & "  - dbLong - Long"
    s = s & ve & dbLongBinary & "  - dbLongBinary - Long Binary (OLE Object)"
    s = s & ve & dbMemo & "  - dbMemo - Memo"
    s = s & ve & dbNumeric & "  - dbNumeric - Numeric"
    s = s & ve & dbSingle & "  - dbSingle - Single"
    s = s & ve & dbText & "  - dbText - Text"
    s = s & ve & dbTime & "  - dbTime - Time"
    s = s & ve & dbTimeStamp & "  - dbTimeStamp - Time Stamp"
    s = s & ve & dbVarBinary & "  - dbVarBinary - VarBinary"

s = s & ve & ve & "QueryDef object.  Settings and return alues: "

    s = s & ve & dbQAction & "  - dbQAction - Action"
    s = s & ve & dbQAppend & "  - dbQAppend - Append"
    s = s & ve & dbQCompound & "  - dbQCompound - Compound"
    s = s & ve & dbQCrosstab & "  - dbQCrosstab - Crosstab"
    s = s & ve & dbQDDL & "  - dbQDDL - Data-definition"
    s = s & ve & dbQDelete & "  - dbQDelete - Delete"
    s = s & ve & dbQMakeTable & "  - dbQMakeTable - Make-table"
    s = s & ve & dbQProcedure & "  - dbQProcedure - Procedure (ODBCDirect Workspaces)"
    s = s & ve & dbQSelect & "  - dbQSelect - Select"
    s = s & ve & dbQSetOperation & "  - dbQSetOperation - Union"
    s = s & ve & dbQSPTBulk & "  - dbQSPTBulk - Used with dbQSQLPassThrough." & ve & _
                 "MJ Workspaces only. Specifying a query that doesn't return records."
    s = s & ve & dbQSQLPassThrough & "  - dbQSQLPassThrough - MJ Workspaces. Pass-through."
    s = s & ve & dbQUpdate & "  - dbQUpdate - Update"




 s = s & ve & ve & "Recordset Object:"


    s = s & ve & dbOpenTable & "  - dbOpenTable - Table. MJ Workspaces."
    s = s & ve & dbOpenDynamic & "  - dbOpenDynamic - Dynamic. ODBCDirect Workspaces."
    s = s & ve & dbOpenDynaset & "  - dbOpenDynaset - Dynaset"
    s = s & ve & dbOpenSnapshot & "  - dbOpenSnapshot - Snapshot"
    s = s & ve & dbOpenForwardOnly & "  - dbOpenForwardOnly - Forward-only"


    s = s & ve & dbUseJet & "  - dbUseJet - The WS is connected to the MJD engine."
    s = s & ve & dbUseODBC & "  - dbUseODBC - The WS is connected to an ODBC DS."

ListDbTypes = s

End Function

Private Function ReadK$(s$, ss$)
Dim ws$, pos&
Dim NL As Boolean

ReadK = "K"  'normal parsing

If IPos > ILen Then
   'end found:
   ReadK = "E"
   Exit Function
End If

pos = InStr(IPos, ImportFile, vbCrLf)
If 0 = pos Then
   pos = ILen + 1
End If
ws = Mid(ImportFile, IPos, pos - IPos)
IPos = pos + 2

If "" = ws Then
   ReadK = "L"
   s = ""
   ss = ""
   Exit Function
End If

pos = InStr(ws, "=")
If 0 = pos Then
   s = ws
   ss = ""
Else
   s = Mid(ws, 1, pos - 1)
   ss = Mid(ws, pos + 1)
End If

ss = StripEs(ss, NL)
If NL Then ReadK = "N"
s = StripEs(s, NL)
If NL Then ReadK = "N"

If DisplayImportedData Then ri "K: " & s & " = " & ss

End Function




Public Function ReadKC$(s$, ss$)
Dim c$, sc$, ws$
sc = s
c = ReadK(s, ss)

Select Case c
   Case "K": 'good
       If UCase(s) <> UCase(sc) Then
          c = "X"
          ws = "Key " & sc & " is expected." & ve & _
               "Key " & s & " is encountered."
       End If
   Case Else:
        Select Case c
             Case "E": ws = "End of file encoutered."
             Case "N": ws = "NULL value encountered."
             Case "L": ws = "Empty line encountered."
        End Select
        c = "X"
End Select

If "K" <> c Then
   ws = "Corrupted key=value pair encoutered " & ve & _
          ws & ve & _
          "key:" & s & _
          "possible value:" & ss
   ri ws
   MsgBox ws
   Interrupted = "Y"
End If
ReadKC = c


End Function


Public Function ReadL$()
Dim s$, ss$, c$, ws$
c = ReadK(s, ss)
If "L" <> c Then
   ws = "Missed Line in import file."
   ri ws
   MsgBox ws
   ReadL = "X"
   Interrupted = "Y"
End If
End Function



Public Function ReadOneOrMoreLines$(s$, ss$)
Dim c$

c = ReadL

If "X" = s Then GoTo ExitFunction
c = ReadSkippingLines(s, ss)

ExitFunction:
ReadOneOrMoreLines = c

End Function

Public Function ReadSkippingLines$(s$, ss$)
Dim c$

again:
If uInterrupted Then
   ReadSkippingLines = "X"
   Exit Function
End If

c = ReadK(s, ss)
If "L" = c Then GoTo again

ReadSkippingLines = c

End Function



Public Function StripEs$(s$, NL As Boolean)
Dim ss$

If InStr(s, "\N") > 0 Then
   NL = True
   Exit Function
Else
   NL = False
End If

ss = Replace(s, "\z", Chr(0))
ss = Replace(ss, "\n", vbLf)
ss = Replace(ss, "\r", vbCr)
ss = Replace(ss, "\l", vbCrLf)
StripEs = Replace(ss, "\\", "\")

End Function




'MyWs must aready exist
'MyDb must be already open.
'
'
'EXCEPTIONS NUMBERS:
       'vital to find: in Platform SDK/Database and Messaging Services/
       '                  /Trappable Microsoft Jet and DAO Errors
'
Public Sub RecreateDatabase(NewPath$)
Dim td As TableDef
Dim nTD As TableDef
Dim FLD As Field
Dim nFLD As Field
Dim INDX As Index
Dim nINDX As Index
Dim nDB As Database
Dim v, s$, ss$, i&, j&
Dim p As Property

Dim EC&  ' exceptions counter
EC = 0

Dim ve, vr, vl
ve = vbCrLf
vr = vbCr
vl = vbLf

Dim EX$        'Exceptions
DP = False

If "" = NewPath Then
   MsgBox "New name is empty."
   Exit Sub
End If

If Not DBOpen Then
   MsgBox "Database is not open."
   Exit Sub
End If
    
On Error Resume Next
If Dir(NewPath) <> "" Then
   Kill NewPath
   If Err.Number > 0 Then
      MsgBox "Cannot remove database " & NewPath
      Exit Sub
   End If
End If

Dim nWS As Workspace

'Set nWS = DBEngine.Workspaces(1)
'Set nWS = DBEngine.CreateWorkspace("moo_name", "umoo", "")
'If Err.Number > 0 Then
'   MsgBox CStr(Err.Number) & " " & Err.Description
'   Exit Sub
'End If


'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' Create database.
'------------------------------------------------------------
On Error Resume Next
Dim DBVersion$
'string:
DBVersion = Trim(MyDB.Version)
Select Case DBVersion
  Case "1.0": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion10)
  Case "1.1": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion11)
  Case "2.0": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion20)
  Case "3.0": Set nDB = _
     MyWs.CreateDatabase(NewPath, dbLangGeneral, dbVersion30)
End Select
If Err.Number > 0 Then
   MsgBox "Database creation exception." & ve & _
          Err.Number & " " & Err.Description
   Exit Sub
End If
'------------------------------------------------------------
' ef database creation
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm



'============================================================
' set db properties
'------------------------------------------------------------
Dim nTransactions As Boolean  '- not a table related
'phs, not important:
nTransactions = MyDB.Transactions
'read-only:
'nDB.Transactions = nTransactions

Dim nUpdatable As Boolean
Dim nQueryTimeOut%
'nUpdatable = MyDB.Updatable
'read-only:
'nDB.Updatable = nUpdatable


'CollatingOrder is already set by dbLangGeneral

nQueryTimeOut = MyDB.QueryTimeout
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   'Exit Sub
End If


Dim nConnect$
nConnect = MyDB.Connect
nDB.Connect = nConnect
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   'Exit Sub
End If



Dim nRecordsAffected&
'nRecordsAffected = MyDB.RecordsAffected
'read-only:
'nDB.RecordsAffected = nRecordsAffected
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   'Exit Sub
End If



'Needs 16 bytes. Assume that string:
'phs, not important:
'Dim nReplicaID$
'nReplicaID = MyDB.ReplicaID
'read-only:
'nDB.ReplicaID = nReplicaID
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Err.Clear
   'Exit Sub
End If


'needs 16 bit:
Dim nDesignMasterID$
'gives message: ... cannot be replicated ....
nDesignMasterID = MyDB.DesignMasterID
'nDB.DesignMasterID = nDesignMasterID
If Err.Number > 0 Then
   MsgBox "DesignMasterID exception" & ve & _
          Err.Number & " " & Err.Description
   Err.Clear
   'Exit Sub
End If

'Dim nConnection
'nConnection = MyDB.connection

'v = TypeName(MyDB.connection)
'does not work:
'Set nDB.connection = nConnection

'---------------------------------------------------------
' ef db properties
'=========================================================




      
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
' LOOP VIA TABLES
'=============================================================
plist = ""
For Each td In MyDB.TableDefs


ri ve & ve & "Table" & td.Name
If "MSYS" = UCase(Left(td.Name, 4)) Then _
   GoTo SkippedSystemTables

Set nTD = nDB.CreateTableDef()
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Exit Sub
End If

nTD.Name = td.Name
If Err.Number > 0 Then
   MsgBox CStr(Err.Number) & " " & Err.Description
   Exit Sub
End If


ri ""
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
ri "FIELD LOOP"
 DP = False
 For Each FLD In td.Fields
'========================================================
   On Error Resume Next
                     
                     
    plistf = ""
    For Each p In FLD.Properties
        plistf = plistf & "^" & UCase(p.Name) & ", "
    Next
        
        
    Set nFLD = nTD.CreateField
    
    With FLD
        
    On Error GoTo AbsorbExceptions
    
    '=======================================================
    ' setting field name:
    '-------------------------------------------------------
    'string
    s = "Name"
    nFLD.Name = .Name
    If "" <> s Then DelPNP s, .Name
    '=======================================================
    
    'string
    DelPN "Value"
    
    'assuming that int or long:
    'nFLD.Type = FLD.Properties("Type") '  .Type
    'nFLD.Properties("Type") = FLD.Properties("Type") '  .Type
    s = "Type"
    nFLD.Type = .Type
    If "" <> s Then DelPNP s, CStr(.Type)
        
    'assuming that int or long:
    '"not set" wim? -1, 0 ?
    s = "Size"
    If dbText = .Type Then
     nFLD.Size = .Size
     If "" <> s Then DelPNP s, CStr(.Size)
    Else
     DelPN s
    End If
            
    'boolean:
    s = "AllowZeroLength"
    If dbText = .Type Or dbMemo = .Type Then
       nFLD.AllowZeroLength = .AllowZeroLength
       If "" <> s Then DelPNP s, CStr(.AllowZeroLength)
    Else
       DelPN s
    End If
        
        

    'assuming that valid only for text:
    'long:
    s = "CollatingOrder"
    If dbText = .Type Then
       'COMPIELER "CANNOT ASSIGN TO READ-ONLY PROPERTY":
       'nFLD.CollatingOrder = .CollatingOrder
       DelPN s
    Else
       DelPN s
    End If
        
    
    'long:
    s = "Attributes"
    nFLD.Attributes = .Attributes
    If "" <> s Then DelPNP s, CStr(.Attributes)
       
    
    'boolean
    'COMPIELER "CANNOT ASSIGN TO READ-ONLY PROPERTY":
    '(perhaps by syntax:)
    s = "DataUpdatable"
    'nFLD.DataUpdatable = .DataUpdatable
    DelPN s
    
    
    'string
    'in some cases, can function as rundom ID;
    s = "DefaultValue"
    nFLD.DefaultValue = .DefaultValue
    If "" <> s Then
       plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
       ri s & " = " & .DefaultValue
    End If
       
      
    'integer
    s = "OrdinalPosition"
    nFLD.OrdinalPosition = .OrdinalPosition
    If "" <> s Then
       plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
       ri s & " = " & .OrdinalPosition
    End If
        
    
    'boolean
    s = "Required"
    nFLD.Required = .Required
    If "" <> s Then
       plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
       ri s & " = " & .Required
    End If
        
    s = "SourceField"
    plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
    s = "SourceTable"
    plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
    
                  
    'string
    s = "ValidationRule"
    nFLD.ValidationRule = .ValidationRule
    If "" <> s Then
       plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
       ri s & " = " & .ValidationRule
    End If
        
    'string
    s = "ValidationText"
    nFLD.ValidationText = .ValidationText
    If "" <> s Then
       plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
       ri s & " = " & .ValidationText
    End If
        
    'this is part of relation object:
    'string
    s = "ForeignName"
    'nFLD.ForeignName = .ForeignName
    If "" <> s Then
       plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
    End If
    
    'string
    'disabled by syntax:
    s = "ValidateOnSet"
    'nFLD.ValidateOnSet = .ValidateOnSet
    'If "" <> s Then
    plistf = Replace(plistf, "^" & UCase(s) & ", ", "")
    '   'ri s & " = " & .ValidateOnSet
    'End If
           
    '=======================================
    ' disabled updates:
    plistf = Replace(plistf, "^" & "ORIGINALVALUE" & ", ", "")
    'belongs to RecordSet object:
    plistf = Replace(plistf, "^" & "FIELDSIZE" & ", ", "")
    'not sure what is this:
    plistf = Replace(plistf, "^" & "VISIBLEVALUE" & ", ", "")
    '=======================================
       
    End With
    
    ri ve & ve & ve
    If "" <> plistf Then plist = plist & ve & ve & _
                                 td.Name & ve & plistf

    On Error Resume Next
    If 0 = EC Then
       nTD.Fields.Append nFLD
    End If
    If Err.Number > 0 Then Err.Clear
                   
'==================================================
Next 'ef FIELD LOOP
DP = False
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm





'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' INDEXES
'==================================================
Dim IndxName$
On Error GoTo he
s = "INDEXES"
ri ve & s
If 0 = td.Indexes.Count Then GoTo SkippedIndexes

For Each INDX In td.Indexes
    On Error GoTo AbsorbIndexExceptions
       
    s = "IndexName "
    v = INDX.Name 'critical
    
    IndxName = v
    s = s & IndxName
    
    ri "Index: " & IndxName
    Set nINDX = nTD.CreateIndex(v)
        
    With INDX
      s = "Fields "
      ss = .Fields  '+f;+g
      s = s & ss
      'nINDX.Fields = .Fields
      nINDX.Fields = Replace(ss, "+", "") '=f;g
      
      'this is too long method:
      'Dim IndexField As Field
      'Dim IndexFieldList$
      'IndexFieldList = ""
      'For Each IndexField In INDX.Fields
      '    s = IndexField.Name
      ' Next
      
      s = "Unique"  'boolean:
      nINDX.Unique = .Unique
      s = "Primary"   'boolean:
      nINDX.Primary = .Primary
      s = "IgnoreNulls" 'boolean
      nINDX.IgnoreNulls = .IgnoreNulls
      s = "Clustered" 'boolean:
      nINDX.Clustered = .Clustered
      
      s = "Required"  'boolean:
      ss = .Required
      nINDX.Required = CBool(ss) ' .Required
      's = "Foreign"  'boolean:
      'nINDX.Foreign = .Foreign
 End With
    
 s = "Appending " & IndxName
 ri s
 nTD.Indexes.Append nINDX
Next
SkippedIndexes:
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm


If 0 = EC Then
   On Error GoTo he
   s = "Appending table " & td.Name
   nDB.TableDefs.Append nTD
   ri ve & ve & "Table" & td.Name & " appended."
End If


SkippedSystemTables:
'=============================================================
Next 'EF LOOP VIA TABLES
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM


    
If 0 <> EC Then
   MsgBox "Exceptions: " & ve & Left(EX, 300) & " ... "
   ri EX
   Exit Sub
End If
nDB.Close

If "" <> Replace(plist, ve, "") Then _
   ri "Not-replicated properties: " & plist



ri ""
ri ""
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
ri "MOVING DATA"
'=============================================================
On Error GoTo he
Set nDB = MyWs.OpenDatabase(NewPath)

On Error GoTo MovingDataExceptions
For Each td In MyDB.TableDefs
    If uInterrupted Then Exit Sub
    
    If "MSYS" = UCase(Left(td.Name, 4)) Then GoTo SkipDummies
    'If "TRANSACTION" = UCase(td.Name) Then GoTo SkipDummies
    ri ve & ve & "Table" & td.Name


    Dim Rs As Recordset
    Dim nRS As Recordset
        'dbOpenTable    Opens a table-type Recordset object
                        '(Microsoft Jet workspaces only).
        'dbOpenDynamic  Opens a dynamic-type Recordset object, which is similar to an ODBC dynamic cursor. '(ODBCDirect workspaces only)
        'dbOpenDynaset  Opens a dynaset-type Recordset object, which is similar to an ODBC keyset cursor.
        'dbOpenSnapshot Opens a snapshot-type Recordset object,
                        ' which is similar to an ODBC static cursor.
        'dbOpenForwardOnly  Opens a forward-only-type Recordset object.
        
        Dim wi&
        wi = td.Fields.Count - 1
        
        ri ve & "Updating table " & td.Name
        Set Rs = MyDB.OpenRecordset(td.Name, dbOpenTable)
        Set nRS = nDB.OpenRecordset(td.Name, dbOpenDynaset)
        j = 0
        Do Until Rs.EOF
           If uInterrupted Then Exit Sub
           nRS.AddNew
           For i = 0 To wi
               nRS(i) = Rs(i)
           Next
           nRS.Update
           Rs.MoveNext
           j = j + 1
        Loop
        ri CStr(j) & " records moved to table " & td.Name
SkipDummies:
Next
Set nRS = Nothing
Set Rs = Nothing
nDB.Close
'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM



'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
' ADDITIONAL CHECKS
'-------------------------------------------------------------
If MyDB.Recordsets.Count > 0 Then
   EC = EC + 1
   EX = EX & ve & EC & " There are " & _
           MyDB.Recordsets.Count & " RecordSets which are ignored. "
End If

If MyDB.QueryDefs.Count > 0 Then
   EC = EC + 1
   EX = EX & ve & EC & " There are " & _
           MyDB.Recordsets.Count & " QueryDefinitions which are ignored. "
End If

If MyDB.Relations.Count > 0 Then
   EC = EC + 1
   EX = EX & ve & EC & " There are " & _
           MyDB.Recordsets.Count & " Relations which are ignored. "
End If
'-------------------------------------------------------------
' ef ADDITIONAL CHECKS
'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm




'-------------------------------------------------------------
'  FINAL REPORT
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If 0 <> EC Then
   
   s = "Replication attemt is done. Exceptions are: " & ve & EX
   MsgBox Left(s, 500) & " ... "
   ri s

Else

   MsgBox "Database " & NewPath & ve & _
       "has been succesfully replicated."

End If
'-------------------------------------------------------------

    
    
Exit Sub

AbsorbExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Field Property = " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
AbsorbIndexExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Index = " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
    
MovingDataExceptions:
       EC = EC + 1
       EX = EX & EC & " Exc in Moving data: " & s & ve & _
            Err.Number & " " & Err.Description & ve
       s = ""
       Resume Next
    
    
    
    
he: s = s & ve & "Process Terminated: " & ve & _
        Err.Number & " " & Err.Description
    If "" <> EX Then
       s = s & ve & "Another exceptions: " & ve & EX
    End If
    ri s
    MsgBox s
    Exit Sub
    
End Sub


Public Sub ri(s$)
 o_indent = String(in_dent * 3, " ")
 If Not DP Then frmMain.rl _
    o_indent & Replace(s, ve, ve & o_indent)
End Sub

Public Function uInterrupted() As Boolean
DoEvents
uInterrupted = False
If "Y" = Interrupted Then
   uInterrupted = True
   If DBForImportIsOpen Then
      DBForImportIsOpen = False
      nDB.Close
   End If
End If
End Function