import os, string, time
DBNAME=os.environ.get("ODS_TEST_DB","ods:test")
import time

from Ft.Ods.StorageManager.Adapters import Constants

class Foo:
    pass

class Foo2:
    pass


class DummyCollection:
    pass

class DummyDictionary:
    pass

def Test(tester):

    if tester.test_data['driver'] == 'Dbm':
        import test_dbm
        mang = test_dbm.DManager.DbManager()
        ad = test_dbm.DAdapter.DbAdapter()
        val = test_dbm.Validator()
    elif tester.test_data['driver'] == 'Postgres':
        import test_postgres
        mang = test_postgres.PManager.DbManager()
        ad = test_postgres.PAdapter.DbAdapter()
        val = test_postgres.Validator()
    else:
        tester.warning("Unknown Driver %s" % tester.test_data['driver'])
        return

    _Test(tester,mang,ad,val)


def _Test(tester,mang,adapter,validator):
    test_management(tester,mang,validator)
    test_python_classes(tester,mang,adapter,validator)
    test_literal_classes(tester,mang,adapter,validator)
    test_basic_repos(tester,mang,adapter,validator)
    test_extents(tester,mang,adapter,validator)
    test_bindings(tester,mang,adapter,validator)
    test_collections(tester,mang,adapter,validator)
    test_dictionaries(tester,mang,adapter,validator)
    test_blobs(tester,mang,adapter,validator) 
  
    
    

def test_management(tester,mang,val):

    tester.startTest("Low level management interfaces")
    #Create
    rt = mang.create(DBNAME)
    val.validateCreate(tester,DBNAME)

    #Destroy
    mang.destroy(DBNAME)
    val.validateDestroy(tester,DBNAME)

    #Exists
    if mang.exists(DBNAME):
        tester.error("Exists failed")



    #Test basic initialization
    mang.create(DBNAME)
    
    mang.init(DBNAME)
    val.validateInit(tester,DBNAME,mang)

    time.sleep(1)
    mang.destroy(DBNAME)
    
    tester.testDone()


def test_python_classes(tester,mang,adapter,val):

    tester.startTest("Low level Python classes")
    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    #Add a simple repository object (a primitive type)
    db = mang.connect(DBNAME)

    adapter.begin(db)

    pid = adapter.newPythonClass(db,Foo)
    pid2 = adapter.newPythonClass(db,Foo2)

    res1 = adapter.getPythonClass(db,pid)
    tester.compare('test_adapter',string.split(res1[0],'.')[-1])
    tester.compare('Foo',res1[1])
    res2 = adapter.getPythonClass(db,pid2)
    tester.compare('test_adapter',string.split(res2[0],'.')[-1])
    tester.compare('Foo2',res2[1])
    adapter.deletePythonClass(db,pid)
    tester.compare(None,adapter.getPythonClass(db,pid))
    adapter.commit(db)

    db = mang.connect(DBNAME)
    adapter.begin(db)
    res2 = adapter.getPythonClass(db,pid2)
    tester.compare('test_adapter',string.split(res2[0],'.')[-1])
    tester.compare('Foo2',res2[1])

    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()


def test_literal_classes(tester,mang,adapter,val):

    tester.startTest("Low level Python Literal classes")
    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)


    db = mang.connect(DBNAME)

    adapter.begin(db)

    adapter.newPythonLiteralClass(db,1,1,Foo)
    adapter.newPythonLiteralClass(db,1,-1,Foo2)

    res1 = adapter.getPythonLiteralClass(db,1,1)
    tester.compare('test_adapter',string.split(res1[0],'.')[-1])
    tester.compare('Foo',res1[1])
    res2 = adapter.getPythonLiteralClass(db,1,-1)
    tester.compare('test_adapter',string.split(res2[0],'.')[-1])
    tester.compare('Foo2',res2[1])


    adapter.deletePythonLiteralClass(db,1,1)
    tester.compare(None,adapter.getPythonLiteralClass(db,1,1))
    adapter.commit(db)

    db = mang.connect(DBNAME)
    adapter.begin(db)
    res2 = adapter.getPythonLiteralClass(db,1,-1)
    tester.compare('test_adapter',string.split(res2[0],'.')[-1])
    tester.compare('Foo2',res2[1])

    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()


def test_basic_repos(tester,mang,adapter,val):

    tester.startTest("Low Level repository Objects")
    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    #Add a simple repository object (a primitive type)
    db = mang.connect(DBNAME)

    adapter.begin(db)

    adapter.newPythonClass(db,Foo)

    types = ((Constants.Types.ROBJECT,),
             (Constants.Types.ENUMERATION,),
             (Constants.Types.STRING,),
             (Constants.Types.STRING,),
             (Constants.Types.ROBJECT,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.SET_COLLECTION,),
             (Constants.Types.ENUMERATION,),
             )
    Foo._tupleTypes = types
    
    rid = adapter.newRepositoryObjectId(db,14,Foo)
    rid2 = adapter.newRepositoryObjectId(db,14,Foo,12345)

    tester.compare(12345,rid2)

    names = (('_repoId',), ('meta_kind',), ('name',), ('comment',), ('definedIn',), ('collections',), ('dictionaries',), ('specifiers',), ('unions',), ('operations',), ('properties',), ('constants',), ('type_defs',), ('primitive_kind',))

    values = ((rid2,),(14,),("Test Type",),("Comment",),(0,),(0,),(0,),(0,),(0,),(0,),(0,),(0,),(0,),(3,))

    adapter.writeRepositoryObject(db,14,rid2,types,names,values)
    if not adapter.objectUptoDate(db,Constants.Types.ROBJECT,rid2,time.time()+.001):
        tester.error("Bad up-to-date")
    if adapter.objectUptoDate(db,Constants.Types.ROBJECT,rid2,time.time()-20):
        tester.error("Bad up-to-date")


    res = adapter.getRepositoryObject(db,rid2)
    tester.compare(2,len(res))
    tester.compare(Foo,res[0])
    tester.compare([(12345,), (14,), ('Test Type',), ('Comment',), (0,), (0,), (0,), (0,), (0,), (0,), (0,), (0,), (0,), (3,)],res[1])

    adapter.deleteRepositoryObject(db,rid,14)

    tester.compare(None,adapter.getRepositoryObject(db,rid))


    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()

def test_extents(tester,mang,adapter,val):
    tester.startTest("Low Level Extents")

    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    db = mang.connect(DBNAME)

    adapter.begin(db)


    adapter.addExtent(db,"test",Constants.Types.ROBJECT)

    tester.compare(['test'],adapter.extentNames(db))

    adapter.addExtentEntry(db,['test'],15)
    adapter.addExtentEntry(db,['test'],16)

    tester.compare((Constants.Types.ROBJECT,[15,16]),adapter.loadExtent(db,'test'))
    tester.compare(None,adapter.loadExtent(db,'foo'))


    adapter.dropExtentEntry(db,['test'],15)
    tester.compare((Constants.Types.ROBJECT,[16]),adapter.loadExtent(db,'test'))
    adapter.dropExtent(db,"test")
    tester.compare(None,adapter.loadExtent(db,'test'))


    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()

def test_bindings(tester,mang,adapter,val):

    tester.startTest("Low level binding test")

    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    db = mang.connect(DBNAME)

    adapter.begin(db)

    adapter.bind(db,15,'test1')
    adapter.bind(db,16,'test2')

    res = adapter.getAllBindings(db)
    tester.compare(2,len(res))
    tester.compareIn(res,'test2')
    tester.compareIn(res,'test1')
    tester.compare(['test1'],adapter.getObjectBindings(db,15))
    tester.compare(16,adapter.lookup(db,'test2'))
    tester.compare(None,adapter.lookup(db,'foo'))


    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()

def test_collections(tester,mang,adapter,val):

    tester.startTest("Low level Collections")
    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    db = mang.connect(DBNAME)

    adapter.begin(db)

    adapter.newPythonClass(db,DummyCollection)

    cid = adapter.newCollection(db,DummyCollection,None,Constants.Types.STRING,-1)

    changes = [(Constants.CollectionChanges.APPEND,[('1',0),('2',1)])]

    adapter.writeCollection(db,cid,changes,None,Constants.Types.STRING)

    res = adapter.getCollection(db,cid)

    tester.compare(DummyCollection,res[0])
    tester.compare(Constants.Types.STRING,res[1])
    tester.compare(-1,res[2])

    tester.compare(2,len(res[3].keys()))
    tester.compare(1,res[3].has_key(0))
    tester.compare('1',res[3][0])
    tester.compare(1,res[3].has_key(1))
    tester.compare('2',res[3][1])

    changes = [(Constants.CollectionChanges.INSERT,[('1.5',1)])]

    adapter.writeCollection(db,cid,changes,None,Constants.Types.STRING)

    res = adapter.getCollection(db,cid)


    tester.compare(DummyCollection,res[0])
    tester.compare(Constants.Types.STRING,res[1])
    tester.compare(-1,res[2])

    tester.compare(3,len(res[3].keys()))
    tester.compare(1,res[3].has_key(0))
    tester.compare('1',res[3][0])
    tester.compare(1,res[3].has_key(1))
    tester.compare('1.5',res[3][1])
    tester.compare(1,res[3].has_key(1))
    tester.compare('2',res[3][2])

    changes = [(Constants.CollectionChanges.REMOVE,[('1',0)])]

    adapter.writeCollection(db,cid,changes,None,Constants.Types.STRING)

    res = adapter.getCollection(db,cid)


    tester.compare(DummyCollection,res[0])
    tester.compare(Constants.Types.STRING,res[1])
    tester.compare(-1,res[2])

    tester.compare(2,len(res[3].keys()))
    tester.compare(1,res[3].has_key(0))
    tester.compare('1.5',res[3][0])
    tester.compare(1,res[3].has_key(1))
    tester.compare('2',res[3][1])

    adapter.deleteCollection(db,cid,None,Constants.Types.STRING)

    res = adapter.getCollection(db,cid)
    tester.compare(None,res)

    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()


def test_dictionaries(tester,mang,adapter,val):

    tester.startTest("Low level Dictionaries")
    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    db = mang.connect(DBNAME)

    adapter.begin(db)

    adapter.newPythonClass(db,DummyDictionary)

    cid = adapter.newDictionary(db,DummyDictionary,Constants.Types.STRING,-1,Constants.Types.STRING,-1)

    changes = [(Constants.DictionaryChanges.ADD,'1','1'),(Constants.DictionaryChanges.ADD,'2','2')]

    adapter.writeDictionary(db,cid,changes,Constants.Types.STRING,Constants.Types.STRING)

    res = adapter.getDictionary(db,cid)

    tester.compare(DummyDictionary,res[0])
    tester.compare(Constants.Types.STRING,res[1])
    tester.compare(-1,res[2])
    tester.compare(Constants.Types.STRING,res[3])
    tester.compare(-1,res[4])

    tester.compare(2,len(res[5].keys()))
    tester.compare(1,res[5].has_key('1'))
    tester.compare('1',res[5]['1'])
    tester.compare(1,res[5].has_key('2'))
    tester.compare('2',res[5]['2'])

    changes = [(Constants.DictionaryChanges.CHANGE,'1','4')]

    adapter.writeDictionary(db,cid,changes,Constants.Types.STRING,Constants.Types.STRING)

    res = adapter.getDictionary(db,cid)


    tester.compare(DummyDictionary,res[0])
    tester.compare(Constants.Types.STRING,res[1])
    tester.compare(-1,res[2])
    tester.compare(Constants.Types.STRING,res[3])
    tester.compare(-1,res[4])

    tester.compare(2,len(res[5].keys()))
    tester.compare(1,res[5].has_key('1'))
    tester.compare('4',res[5]['1'])
    tester.compare(1,res[5].has_key('2'))
    tester.compare('2',res[5]['2'])



    changes = [(Constants.DictionaryChanges.REMOVE,'1','4')]

    adapter.writeDictionary(db,cid,changes,Constants.Types.STRING,Constants.Types.STRING)

    res = adapter.getDictionary(db,cid)

    tester.compare(DummyDictionary,res[0])
    tester.compare(Constants.Types.STRING,res[1])
    tester.compare(-1,res[2])
    tester.compare(Constants.Types.STRING,res[3])
    tester.compare(-1,res[4])

    tester.compare(1,len(res[5].keys()))
    tester.compare(1,res[5].has_key('2'))
    tester.compare('2',res[5]['2'])

    adapter.deleteDictionary(db,cid,Constants.Types.STRING,Constants.Types.STRING)

    res = adapter.getDictionary(db,cid)
    tester.compare(None,res)

    adapter.commit(db)

    mang.destroy(DBNAME)

    tester.testDone()


def test_blobs(tester,mang,adapter,val):

    tester.startTest("Low Level Blobs")
    if mang.exists(DBNAME):
        mang.destroy(DBNAME)
    mang.create(DBNAME)
    mang.init(DBNAME)

    db = mang.connect(DBNAME)

    adapter.begin(db)

    bid = adapter.newBlob(db)

    t1 = "This is a test"*5000
    t2 = "Another TEst"
    
    adapter.writeBlob(db,bid,t1)
    tester.compare(t1,adapter.readBlob(db,bid))

    adapter.writeBlob(db,bid,t2)
    tester.compare(t2,adapter.readBlob(db,bid))

    adapter.deleteBlob(db,bid)

    tester.compare(None,adapter.readBlob(db,bid))

    adapter.commit(db)


    mang.destroy(DBNAME)


    tester.testDone()
