#!/usr/bin/env python
############################################################################
#
# File Name: 		Object.py
#
# Documentation:	http://docs.ftsuite.com/4ODS/Object.py.html
#


from Ft.Ods.StorageManager.Adapters import Constants

#Lock Types
class Lock_Type:
    def __init__(self, typeName):
	self.__typeName = typeName

    def conflictsWith(self, newMode):
        conflict = 1
        if self.__typeName == 'read' and newMode.__typeName == 'read':
            conflict = 0
        return conflict

    def __repr__(self):
	return self.__typeName

read = Lock_Type("read")
write = Lock_Type("write")
upgrade = Lock_Type("upgrade")

#Exception class
class LockNotGranted:
    pass


from Ft.Ods import PersistentObject
from Ft.Ods.PersistentObject import TupleDefinitions
from Ft.Ods.Exception import FtodsUnsupportedError

td = TupleDefinitions
class Object(PersistentObject.PersistentObject):

    def __init__(self, db, data):
        if not self.__dict__.has_key('_initialized'):
            PersistentObject.PersistentObject.__init__(self, db, data)

    def lock(self, mode):
        raise FtodsUnsupportedError(feature='Explict locks')

    def try_lock(self, mode):
        raise FtodsUnsupportedError(feature='Explict locks')

    def same_as(self, anObject):
        return isinstance(anObject, Object) and anObject._oid == self._oid

    def copy(self,deep=0,alreadyCloned=None):
        initArgs = (self._db,None)

        ac = alreadyCloned or {}

        Types = Constants.Types
        lists = Constants.g_listTypes
        primitives = Constants.g_primitiveTypes
        newSelf = apply(self.__class__,initArgs)
        ac[self] = newSelf

        #We need to walk all of the types and determine what to do in each case
        for name,data in self._tupleDefinitions.items():
            t = data[td.TYPE]
            if t in [Types.POBJECT,Types.ROBJECT]:
                #If it is an attribute, we copy it
                #If it is a relationship, we only copy it if they specify deep
                if data.get(td.RELATIONSHIP):
                    if deep:
                        #Clone the relationship as well
                        curobj = getattr(self,name)
                        if not curobj:
                            continue
                        newobj = ac.get(curobj)
                        if newobj is None:
                            #Has not been done yet so do the form
                            newobj = curobj.copy(deep,alreadyCloned=ac)
                            ac[curobj] = newobj
                        if not getattr(newSelf,name):
                            func = getattr(newSelf,'form_%s'%name)
                            apply(func,(newobj,0))
                else:
                    curobj = getattr(self,name)
                    if not curobj:
                        continue
                    newobj = ac.get(curobj)
                    if newobj is None:
                        #Has not been done yet so do the form
                        newobj = curobj.copy(deep,alreadyCloned=ac)
                    setattr(newSelf,name,newobj)

            elif lists[t]:
                if data.get(td.RELATIONSHIP):
                    if deep:
                        curcoll = getattr(self,name)
                        newcoll = getattr(newSelf,name)
                        for curobj in curcoll:
                            newobj = ac.get(curobj)
                            if newobj is None:
                                #Has not been done yet so do the add
                                newobj = curobj.copy(deep=0)
                                ac[curobj] = newobj
                            if not newcoll.contains_element(newobj):
                                func = getattr(newSelf,'add_%s'%name)
                                apply(func,(newobj,0))                        
                else:
                    #Just copy the list
                    curobj = getattr(self,name)
                    if not curobj:
                        continue
                    for v in curobj.value:
                        getattr(newSelf,name).insert_element(v)
                    
            elif primitives[t]:
                if name != '_oid':
                    setattr(newSelf,name,getattr(self,name))
            else:
                #It is a literal
                setattr(newSelf,name,getattr(self,name).copy())
                
        return newSelf

    def _4ods_getOid(self):
	return self.__dict__['_oid']

    def _4ods_setOid(self,id):
        self.__dict__['_oid'] = id

    def _4ods_setObjectId(self, id):
        self.__dict__['_oid'] = id

    def _4ods_getId(self):
	return self.__dict__['_oid']    

    def _4ods_getRepositoryObject(self):
        return self.__dict__['_db']._4ods_getPersistentObjectById(Constants.Types.ROBJECT,self.typeId)

    def _4ods_getOdsType(self):
        return Constants.Types.POBJECT

    
    _tupleDefinitions = {'_oid' : {TupleDefinitions.TYPE : Constants.Types.UNSIGNED_LONG,
                                   TupleDefinitions.READONLY : 1,
                                   },
                         }

    _tupleNames = (('_oid',),)
    _tupleTypes = ((Constants.Types.UNSIGNED_LONG,),)
    _typeIds = ()
    _extents = ()
