import os

from Ft.Ods import Collections
from Ft.Ods.Collections import CollectionBase, DictionaryBase


odl_string = '''
module Test {

class Other {
  attribute string name;
};


class Foo {

  /*Primitive Types*/
  attribute set<string> ss;
  typedef set<string> tss;

  /*literals */
  attribute set<date> sd;
  typedef set<date> tsd;
  

  /*Objects*/
  attribute set<Other> so;
  typedef set<Other> tso;


  /*Dictionaries*/
  attribute dictionary <string,string> dss;
  typedef dictionary <string,string> tdss;

  attribute dictionary <string,date> dsd;
  typedef dictionary <string,date> tdsd;

  attribute dictionary <string,Other> dso;
  typedef dictionary <string,Other> tdso;

  attribute dictionary <date,string> dds;
  typedef dictionary <date,string> tdds;

  attribute dictionary <date,date> ddd;
  typedef dictionary <date,date> tddd;

  attribute dictionary <date,Other> ddo;
  typedef dictionary <date,Other> tddo;

  attribute dictionary <Other,string> dos;
  typedef dictionary <Other,string> tdos;

  attribute dictionary <Other,date> dod;
  typedef dictionary <Other,date> tdod;

  attribute dictionary <Other,Other> doo;
  typedef dictionary <Other,Other> tdoo;
  

  /*Collections of collections*/
  attribute list<tss> ltss;
  attribute list<tsd> ltsd;
  attribute list<tso> ltso;

  attribute list<tdss> ltdss;
  attribute list<tdsd> ltdsd;
  attribute list<tdso> ltdso;

  attribute list<tdds> ltdds;
  attribute list<tddd> ltddd;
  attribute list<tddo> ltddo;

  attribute list<tdos> ltdos;
  attribute list<tdod> ltdod;
  attribute list<tdoo> ltdoo;

  attribute dictionary<string,tss> dstss;
  attribute dictionary<string,tdss> dstdss;

  attribute dictionary<tss,string> dtsss;
  attribute dictionary<tdss,string> dtdsss;

  attribute dictionary<tdss,tdss> dtdsstdss;
  attribute dictionary<tdss,tss> dtdsstss;
  attribute dictionary<tss,tdss> dtsstdss;
  attribute dictionary<tss,tss> dtsstss;

};



};
'''


class OtherFactory:
    ctr = 0
    def next(self,db):
        from Test import Other
        reload(Other)
        m = Other.new(db)
        m.name = "Other %d" % self.ctr
        self.ctr = self.ctr + 1
        return m

    def recreate(self,db,v):
        return db._4ods_getPersistentObjectById(Constants.Types.POBJECT,v._4ods_getId())
    def reset(self):
        self.ctr = 0

class SetOfPrimitivesFactory:
    ctr = 0
    def next(self,db):

        from Test import Foo
        reload(Foo)

        coll = Foo.tss(db)

        coll.insert_element("String %d" % self.ctr)
        self.ctr = self.ctr + 1
        return coll

    def recreate(self,db,v):
        return db._4ods_getPersistentObjectById(Constants.Types.SET_COLLECTION,v._4ods_getId())
    def reset(self):
        self.ctr = 0

class SetOfLiteralsFactory:
    ctr = 0
    def next(self,db):
        from Ft.Ods import DateFactory
        from Test import Foo
        reload(Foo)

        coll = Foo.tsd(db)
        rt = DateFactory.calendar_date(2001,05,self.ctr)
        coll.insert_element(rt)
        self.ctr = self.ctr + 1
        return coll

    def recreate(self,db,v):
        return db._4ods_getPersistentObjectById(Constants.Types.SET_COLLECTION,v._4ods_getId())
    def reset(self):
        self.ctr = 0

class SetOfObjectsFactory:
    ctr = 0
    of = OtherFactory()
    def next(self,db):
        from Ft.Ods import DateFactory
        from Test import Foo
        reload(Foo)

        coll = Foo.tso(db)
        o = self.of.next(db)
        coll.insert_element(o)
        self.ctr = self.ctr + 1
        return coll

    def recreate(self,db,v):
        return db._4ods_getPersistentObjectById(Constants.Types.SET_COLLECTION,v._4ods_getId())
    def reset(self):
        self.ctr = 0


class DictionaryFactory:
    def __init__(self,kfac,vfac,attr):
        self.kfac = kfac
        self.vfac = vfac
        self.attr = attr
    ctr = 0
    of = OtherFactory()
    def next(self,db):
        from Test import Foo
        reload(Foo)

        key = self.kfac.next(db)
        val = self.vfac.next(db)

        dict = getattr(Foo,self.attr)(db)
        dict[key] = val

        self.ctr = self.ctr + 1
        return dict

    def recreate(self,db,v):
        return db._4ods_getPersistentObjectById(Constants.Types.DICTIONARY_COLLECTION,v._4ods_getId())
    def reset(self):
        self.ctr = 0



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

import sys, test_util
from Ft.Ods import Database
from Ft.Ods.StorageManager.Adapters import Constants


def test_collection(tester,db,name,attr,fac):

    tester.startGroup("Collection of %s" % name)

    #First make sure it is empty

    tx = db.new()
    tx.begin()

    f = db.lookup("Foo")

    tester.startTest("Test empty")
    tester.compare(1,isinstance(getattr(f,attr),CollectionBase.CollectionBase))
    tester.testDone()

    #Now set it with all of the values
    tester.startTest("Test Insert")
    val1,val2 = fac.next(db),fac.next(db)

    getattr(f,attr).insert_element(val1)
    tester.testDone()

    tester.startTest("Verify Insert")
    #Verify that all values are in the collection
    tester.compare(1,getattr(f,attr).contains_element(val1))
    tester.compare(0,getattr(f,attr).contains_element(val2))
    tx.commit()
    tester.testDone()

    #Now reload an retest
    tx = db.new()
    tx.begin()
    f = db.lookup("Foo")

    #Verify that all values are in the collection
    tester.startTest("Verify the write/read")
    val1,val2 = fac.recreate(db,val1),fac.recreate(db,val2)
    tester.compare(1,getattr(f,attr).contains_element(val1))
    tester.compare(0,getattr(f,attr).contains_element(val2))
    tester.testDone()


    tester.startTest("Add a second")
    getattr(f,attr).insert_element(val2)
    tester.testDone()
                   
    tester.startTest("Verify")
    tester.compare(1,getattr(f,attr).contains_element(val1))
    tester.compare(1,getattr(f,attr).contains_element(val2))
    tester.testDone()
    tx.commit()


    #Now reload an retest
    tx = db.new()
    tx.begin()
    f = db.lookup("Foo")
    val1,val2 = fac.recreate(db,val1),fac.recreate(db,val2)
    
    #Make sure it is empty
    tester.startTest("Reload")
    tester.compare(1,getattr(f,attr).contains_element(val1))
    tester.compare(1,getattr(f,attr).contains_element(val2))
    tester.testDone()

    tester.startTest("Remove")
    getattr(f,attr).remove_element(val1)
    tester.compare(0,getattr(f,attr).contains_element(val1))
    tester.compare(1,getattr(f,attr).contains_element(val2))
    tester.testDone()
    tx.commit()

    tx = db.new()
    tx.begin()
    f = db.lookup("Foo")
    val1,val2 = fac.recreate(db,val1),fac.recreate(db,val2)

    tester.startTest("Verify")
    tester.compare(0,getattr(f,attr).contains_element(val1))
    tester.compare(1,getattr(f,attr).contains_element(val2))
    tester.testDone()
    tx.commit()

    tester.groupDone()


def test_dictionary(tester,db,name,attr,kfac,vfac):

    tester.startGroup("Dictionary of %s" % name)

    #First make sure it is empty

    tx = db.new()
    tx.begin()

    f = db.lookup("Foo")

    tester.startTest("Test empty")
    tester.compare(1,isinstance(getattr(f,attr),DictionaryBase.DictionaryBase))
    tester.testDone()

    #Now set it with all of the values
    tester.startTest("Test Insert")
    key1,key2 = kfac.next(db),kfac.next(db)
    val1,val2 = vfac.next(db),vfac.next(db)

    getattr(f,attr)[key1] = val1
    tester.testDone()

    tester.startTest("Verify Insert")
    #Verify that all values are in the collection
    tester.compare(1,getattr(f,attr).has_key(key1))
    tester.compare(val1,getattr(f,attr)[key1])
    tester.compare(0,getattr(f,attr).has_key(key2))
    tx.commit()
    tester.testDone()

    #Now reload an retest
    tx = db.new()
    tx.begin()
    f = db.lookup("Foo")

    #Verify that all values are in the collection
    tester.startTest("Verify the write/read")
    key1,key2 = kfac.recreate(db,key1),kfac.recreate(db,key2)
    val1,val2 = vfac.recreate(db,val1),vfac.recreate(db,val2)
    tester.compare(1,getattr(f,attr).has_key(key1))
    tester.compare(val1,getattr(f,attr)[key1])
    tester.compare(0,getattr(f,attr).has_key(key2))
    tester.testDone()


    tester.startTest("Add a second")
    getattr(f,attr)[key2] = val2
    tester.testDone()
                   
    tester.startTest("Verify")
    tester.compare(1,getattr(f,attr).has_key(key1))
    tester.compare(val1,getattr(f,attr)[key1])
    tester.compare(1,getattr(f,attr).has_key(key2))
    tester.compare(val2,getattr(f,attr)[key2])
    tester.testDone()
    tx.commit()


    #Now reload an retest
    tx = db.new()
    tx.begin()
    f = db.lookup("Foo")
    key1,key2 = kfac.recreate(db,key1),kfac.recreate(db,key2)
    val1,val2 = vfac.recreate(db,val1),vfac.recreate(db,val2)
    
    #Make sure it is empty
    tester.startTest("Reload")
    tester.compare(1,getattr(f,attr).has_key(key1))
    tester.compare(val1,getattr(f,attr)[key1])
    tester.compare(1,getattr(f,attr).has_key(key2))
    tester.compare(val2,getattr(f,attr)[key2])
    tester.testDone()

    tester.startTest("Remove")
    del getattr(f,attr)[key1]
    tester.compare(0,getattr(f,attr).has_key(key1))
    tester.compare(1,getattr(f,attr).has_key(key2))
    tester.compare(val2,getattr(f,attr)[key2])
    tester.testDone()
    tx.commit()

    tx = db.new()
    tx.begin()
    f = db.lookup("Foo")
    key1,key2 = kfac.recreate(db,key1),kfac.recreate(db,key2)
    val1,val2 = vfac.recreate(db,val1),vfac.recreate(db,val2)

    tester.startTest("Verify")
    tester.compare(0,getattr(f,attr).has_key(key1))
    tester.compare(1,getattr(f,attr).has_key(key2))
    tester.compare(val2,getattr(f,attr)[key2])
    tester.testDone()
    tx.commit()

    tester.groupDone()


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

import sys, test_util
from Ft.Ods import Database
from Ft.Ods.StorageManager.Adapters import Constants

from Ft.Lib import Uuid

from Ods.Collections import test_collection_util

def Test(tester):
    try:
        _Test(tester)
    finally:
        if os.path.exists('Test'):
            from distutils import dir_util
            dir_util.remove_tree('Test')
        pass

def _Test(tester):

    tester.startGroup("Collections %s Driver" % tester.test_data['driver'])

    test_util.DbInit(DBNAME,odl_string)

    tester.startTest('Testing Generated syntax')
    try:
        from Test import Foo
        reload(Foo)
    except:
        tester.error('Error in syntax', 1)


    tester.testDone()

    db = Database.Database()
    db.open(DBNAME)

    try:
        tx = db.new()
        tx.begin()

        #Create an instance of Foo to play with

        f = Foo.new(db)

        db.bind(f,"Foo")

        tx.commit()

        for name,attr,fac in [('Primitives','ss',test_collection_util.StringFactory()),
                              ('Literals','sd',test_collection_util._DateFactory()),
                              ('Objects','so',OtherFactory()),
                              ('Set of Primitives','ltss',SetOfPrimitivesFactory()),
                              ('Set of Literals','ltsd',SetOfLiteralsFactory()),
                              ('Set of Objects','ltso',SetOfObjectsFactory()),
                              ]:
            test_collection(tester,db,name,attr,fac)

        for name,attr,kfac,vfac in [('Primitives-Primitives','dss',test_collection_util.StringFactory(),test_collection_util.StringFactory()),
                                    ('Primitives-Literals','dsd',test_collection_util.StringFactory(),test_collection_util._DateFactory()),
                                    ('Primitives-Objects','dso',test_collection_util.StringFactory(),OtherFactory()),

                                    ('Literals-Primitives','dds',test_collection_util._DateFactory(),test_collection_util.StringFactory()),
                                    ('Literals-Literals','ddd',test_collection_util._DateFactory(),test_collection_util._DateFactory()),
                                    ('Literals-Objects','ddo',test_collection_util._DateFactory(),OtherFactory()),
                                    ('Objects-Primitives','dos',OtherFactory(),test_collection_util.StringFactory()),
                                    ('Objects-Literals','dod',OtherFactory(),test_collection_util._DateFactory()),
                                    ('Objects-Objects','doo',OtherFactory(),OtherFactory()),
                                    ]:

            test_dictionary(tester,db,name,attr,kfac,vfac)


        for name,attr,fac in [('Dictionary P,P',
                               'ltdss',
                               DictionaryFactory(test_collection_util.StringFactory(),
                                                 test_collection_util.StringFactory(),
                                                 'tdss')
                               ),
                              ('Dictionary P,L',
                               'ltdsd',
                               DictionaryFactory(test_collection_util.StringFactory(),
                                                 test_collection_util._DateFactory(),
                                                 'tdsd')
                               ),
                              ('Dictionary P,O',
                               'ltdso',
                               DictionaryFactory(test_collection_util.StringFactory(),
                                                 OtherFactory(),
                                                 'tdso')
                               ),
                              ('Dictionary L,P',
                               'ltdds',
                               DictionaryFactory(test_collection_util._DateFactory(),
                                                 test_collection_util.StringFactory(),
                                                 'tdds')
                               ),
                              ('Dictionary L,L',
                               'ltddd',
                               DictionaryFactory(test_collection_util._DateFactory(),
                                                 test_collection_util._DateFactory(),
                                                 'tddd')
                               ),
                              ('Dictionary L,O',
                               'ltddo',
                               DictionaryFactory(test_collection_util._DateFactory(),
                                                 OtherFactory(),
                                                 'tddo')
                               ),
                              ('Dictionary O,P',
                               'ltdos',
                               DictionaryFactory(OtherFactory(),
                                                 test_collection_util.StringFactory(),
                                                 'tdos')
                               ),
                              ('Dictionary O,L',
                               'ltdod',
                               DictionaryFactory(OtherFactory(),
                                                 test_collection_util._DateFactory(),
                                                 'tdod')
                               ),
                              ('Dictionary O,O',
                               'ltdoo',
                               DictionaryFactory(OtherFactory(),
                                                 OtherFactory(),
                                                 'tdoo')
                               ),
                              ]:
            test_collection(tester,db,name,attr,fac)




        for name,attr,kfac,vfac in [('Dictionary P,SOS',
                                     'dstss',
                                     test_collection_util.StringFactory(),
                                     SetOfPrimitivesFactory(),
                                     ),
                                    ('Dictionary P,D-SS',
                                     'dstdss',
                                     test_collection_util.StringFactory(),
                                     DictionaryFactory(test_collection_util.StringFactory(),
                                                       test_collection_util.StringFactory(),
                                                       'tdss')
                                     ),                                
                                    ('Dictionary SOS,P',
                                     'dtsss',
                                     SetOfPrimitivesFactory(),
                                     test_collection_util.StringFactory()
                                     ),
                                    ('Dictionary D-SS,P',
                                     'dtdsss',
                                     DictionaryFactory(test_collection_util.StringFactory(),
                                                       test_collection_util.StringFactory(),
                                                       'tdss'),
                                     test_collection_util.StringFactory()

                                     ),
                                    ('Dictionary D-SS,D-SS',
                                     'dtdsstdss',
                                     DictionaryFactory(test_collection_util.StringFactory(),
                                                       test_collection_util.StringFactory(),
                                                       'tdss'),
                                     DictionaryFactory(test_collection_util.StringFactory(),
                                                       test_collection_util.StringFactory(),
                                                       'tdss'),
                                     ),
                                    ('Dictionary D-SS,SOS',
                                     'dtdsstss',
                                     DictionaryFactory(test_collection_util.StringFactory(),
                                                       test_collection_util.StringFactory(),
                                                       'tdss'),
                                     SetOfPrimitivesFactory(),
                                     ),
                                    ('Dictionary SOS,D-SS',
                                     'dtsstdss',
                                     SetOfPrimitivesFactory(),
                                     DictionaryFactory(test_collection_util.StringFactory(),
                                                       test_collection_util.StringFactory(),
                                                       'tdss'),
                                     ),
                                    ('Dictionary SOS,SOS',
                                     'dtsstss',
                                     SetOfPrimitivesFactory(),
                                     SetOfPrimitivesFactory(),
                                     ),
                                    ]:

            test_dictionary(tester,db,name,attr,kfac,vfac)



    finally:
        db.close()
    tester.groupDone()

