#
# This assumes that you have MSAccess and DAO installed.
#  You need to run makepy.py over "msaccess.tlb" and
#  "dao3032.dll", and ensure the generated files are on the
#  path.

# You can run this with no args, and a test database will be generated.
# You can optionally pass a dbname on the command line, in which case it will be dumped.

import os
import sys

import pythoncom
import win32api
from win32com.client import Dispatch, constants, gencache


def CreateTestAccessDatabase(dbname=None):
    # Creates a test access database - returns the filename.
    if dbname is None:
        dbname = os.path.join(win32api.GetTempPath(), "COMTestSuiteTempDatabase.mdb")

    access = Dispatch("Access.Application")
    dbEngine = access.DBEngine
    workspace = dbEngine.Workspaces(0)

    try:
        os.unlink(dbname)
    except OSError:
        print(
            "WARNING - Unable to delete old test database - expect a COM exception RSN!"
        )

    newdb = workspace.CreateDatabase(
        dbname, constants.dbLangGeneral, constants.dbEncrypt
    )

    # Create one test table.
    table = newdb.CreateTableDef("Test Table 1")
    table.Fields.Append(table.CreateField("First Name", constants.dbText))
    table.Fields.Append(table.CreateField("Last Name", constants.dbText))

    index = table.CreateIndex("UniqueIndex")
    index.Fields.Append(index.CreateField("First Name"))
    index.Fields.Append(index.CreateField("Last Name"))
    index.Unique = -1
    table.Indexes.Append(index)

    newdb.TableDefs.Append(table)

    # Create a second test table.
    table = newdb.CreateTableDef("Test Table 2")
    table.Fields.Append(table.CreateField("First Name", constants.dbText))
    table.Fields.Append(table.CreateField("Last Name", constants.dbText))

    newdb.TableDefs.Append(table)

    # Create a relationship between them
    relation = newdb.CreateRelation("TestRelationship")
    relation.Table = "Test Table 1"
    relation.ForeignTable = "Test Table 2"

    field = relation.CreateField("First Name")
    field.ForeignName = "First Name"
    relation.Fields.Append(field)

    field = relation.CreateField("Last Name")
    field.ForeignName = "Last Name"
    relation.Fields.Append(field)

    relation.Attributes = (
        constants.dbRelationDeleteCascade + constants.dbRelationUpdateCascade
    )

    newdb.Relations.Append(relation)

    # Finally we can add some data to the table.
    tab1 = newdb.OpenRecordset("Test Table 1")
    tab1.AddNew()
    tab1.Fields("First Name").Value = "Mark"
    tab1.Fields("Last Name").Value = "Hammond"
    tab1.Update()

    tab1.MoveFirst()
    # We do a simple bookmark test which tests our optimized VT_SAFEARRAY|VT_UI1 support.
    # The bookmark will be a buffer object - remember it for later.
    bk = tab1.Bookmark

    # Add a second record.
    tab1.AddNew()
    tab1.Fields("First Name").Value = "Second"
    tab1.Fields("Last Name").Value = "Person"
    tab1.Update()

    # Reset the bookmark to the one we saved.
    # But first check the test is actually doing something!
    tab1.MoveLast()
    assert (
        tab1.Fields("First Name").Value == "Second"
    ), "Unexpected record is last - makes bookmark test pointless!"

    tab1.Bookmark = bk
    assert tab1.Bookmark == bk, "The bookmark data is not the same"
    assert (
        tab1.Fields("First Name").Value == "Mark"
    ), "The bookmark did not reset the record pointer correctly"

    return dbname


def DoDumpAccessInfo(dbname):
    from . import daodump

    a = forms = None
    try:
        sys.stderr.write("Creating Access Application...\n")
        a = Dispatch("Access.Application")
        print("Opening database %s" % dbname)
        a.OpenCurrentDatabase(dbname)
        db = a.CurrentDb()
        daodump.DumpDB(db, 1)
        forms = a.Forms
        print("There are %d forms open." % (len(forms)))
        # Uncommenting these lines means Access remains open.
        # for form in forms:
        #     print(f" {form.Name}")
        reports = a.Reports
        print("There are %d reports open" % (len(reports)))
    finally:
        if not a is None:
            sys.stderr.write("Closing database\n")
            try:
                a.CloseCurrentDatabase()
            except pythoncom.com_error:
                pass


# Generate all the support we can.
def GenerateSupport():
    # dao
    gencache.EnsureModule("{00025E01-0000-0000-C000-000000000046}", 0, 4, 0)
    # Access
    #       gencache.EnsureModule("{4AFFC9A0-5F99-101B-AF4E-00AA003F0F07}", 0, 8, 0)
    gencache.EnsureDispatch("Access.Application")


def DumpAccessInfo(dbname):
    amod = gencache.GetModuleForProgID("Access.Application")
    dmod = gencache.GetModuleForProgID("DAO.DBEngine.35")
    if amod is None and dmod is None:
        DoDumpAccessInfo(dbname)
        # Now generate all the support we can.
        GenerateSupport()
    else:
        sys.stderr.write(
            "testAccess not doing dynamic test, as generated code already exists\n"
        )
    # Now a generated version.
    DoDumpAccessInfo(dbname)


def test(dbname=None):
    if dbname is None:
        # We need makepy support to create a database (just for the constants!)
        try:
            GenerateSupport()
        except pythoncom.com_error:
            print("*** Can not import the MSAccess type libraries - tests skipped")
            return
        dbname = CreateTestAccessDatabase()
        print("A test database at '%s' was created" % dbname)

    DumpAccessInfo(dbname)


if __name__ == "__main__":
    from .util import CheckClean

    dbname = None
    if len(sys.argv) > 1:
        dbname = sys.argv[1]

    test(dbname)

    CheckClean()
