############################################################################
#
# File Name: 		DictionaryBase.py
#
# Documentation:	http://docs.ftsuite.com/4ODS/CollectionBase.py.html
#
"""
Base dictionary class.
WWW: http://4suite.org/4ODS         e-mail: support@4suite.org

Copyright (c) 1999 Fourthought, Inc., USA.   All Rights Reserved.
See  http://4suite.org/COPYRIGHT  for license and copyright information
"""

from Ft.Ods.Collections import Iterator
from Ft.Ods.Collections import BidirectionalIterator
from Ft.Ods.Collections import CollectionBase
from Ft.Ods import Dictionary, Exception

from Ft.Ods.Exception import FtodsUnknownError, FtodsUnsupportedError

class Association:
    def __init__(self,key,value):
        self.key = key
        self.value = value

class DictionaryBase(Dictionary.Dictionary):

    DuplicateName = Exception.DuplicateName
    KeyNotFound = Exception.KeyNotFound

    def __init__(self,db,did,keyType,keyRepoId,subType,subRepoId,values):

        self.__dict__['_subType'] = subType
        self.__dict__['_keyType'] = keyType
        self.__dict__['_subRepoId'] = subRepoId
        self.__dict__['_keyRepoId'] = keyRepoId

        if values:
            self.__dict__['_values'] = values.copy()
        else:
            self.__dict__['_values'] = {}

        self.__dict__['_dbChanges'] = []


        Dictionary.Dictionary.__init__(self,db,did)

        if values:
            self._4ods_initValueKeys()
            self._4ods_initValueValues()

    def _4ods_getSubType(self):
        return self._subType

    def _4ods_getKeyType(self):
        return self._keyType

    def _4ods_getSubRepositoryId(self):
        return self._subRepoId

    def _4ods_getKeyRepositoryId(self):
        return self._keyRepoId


    def _4ods_getChanges(self):
        self._4ods_prepareKeyChanges()
        self._4ods_prepareValueChanges()
        return self._dbChanges

    #The pythonic interface (defined first 
    def __cmp__(self, other):
        if isinstance(other, DictionaryBase):
            if self._4ods_getId() and other._4ods_getId():
                return cmp(self._4ods_getId(), other._4ods_getId())
            return cmp(self.values(), other.values())
        elif type(other) == type({}):
            return cmp(self.items(), other.items())
        else:
            return cmp(self, other)

    def __len__(self): return len(self._values)

    def __getitem__(self, i):
        value = self._4ods_getByKey(i)
        rt = self._4ods_prepareValue(value)
        return rt

    def __setitem__(self, i, item):
        value = self._4ods_unprepareValue(item)
        self._4ods_setByKey(i,value)

    def __delitem__(self, i):
        self._4ods_deleteByKey(i)

    def has_key(self,key):
        raise FtodsUnknownError(msg='Subclass must override')

    def keys(self):
        raise FtodsUnknownError(msg='Subclass must override')

    def values(self):
        raise FtodsUnknownError(msg='Subclass must override')

    def items(self):
        return map(None,self.keys(),self.values())

    def get(self, key, defaultValue=None):
        if self.has_key(key):
            return self[key]
        return defaultValue

##    Clashes with ODMG Interface
##    def copy(self):
##        res = {}
##        for name,value in self.values():
##            res[name] = value
##        return res

    def update(self,other):
        for name,value in other.values():
            self[name] = value

    #The collection interface
    cardinality = __len__

    def is_empty(self):
        return len(self) == 0

    def is_ordered(self):
        return 0

    def allows_duplicates(self):
        return 0

    def contains_element(self, element):
        if not isinstance(element,Association):
            return 0
        return self.has_key(element.key) and self[element.key] == element.value

    def insert_element(self, element):
        if not isinstance(element,Association):
            #????
            return None
        self[element.key] = element.value

    def remove_element(self, element):
        if not isinstance(element,Association) or not self.contains_element(element):
            #????
            raise self.ElementNotFound(element)
        del self[element.key]

    def copy(self,deep=1):
        other = apply(self.__class__,(self._db,None,self._keyType,self._keyRepoId,self._subType,self._subRepoId,None))
        if deep:
            for v in self.keys():
               other[v] = self[v]
        return other


    def create_iterator(self, stable):
        return Iterator.Iterator(self, stable)

    def create_bidirectional_iterator(self, stable):
        return BidirectionalIterator.BidirectionalIterator(self, stable)

    def select_element(self,OQL_predicate):
        raise FtodsUnsupportedError(feature="select_element")

    def select(self,OQL_predicate):
        raise FtodsUnsupportedError(feature="select")

    def query(self,OQL_predicate):
        raise FtodsUnsupportedError(featre="select_element")

    def exists_element(self,OQL_predicate):
        raise FtodsUnsupportedError(feature="select_element")

    def _pseudo_del(self):
        self.__dict__['_values'] = {}
    

    def _4ods_isModified(self):
        return len(self._dbChanges) > 0
