try:
    from UserDict import UserDict     # Python 2
except ImportError:
    from collections import UserDict  # Python 3


# ['__cmp__', '__contains__', '__delitem__', '__doc__', '__getitem__', '__init__', '__len__', '__module__', '__repr__', '__setitem__', 'clear', 'copy', 'data', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']


class CrateDict(UserDict):

    def __init__(self, dict=None, keys=None):
        """
        Initializes the ordered Crate dictionary.

        dict   = a dictionary
        keys   = a list of items contained in the dictionary
                 in the specified order
        """
        if keys is not None:
            self._keys = keys
        else: 
            self._keys = []

        UserDict.__init__(self, dict)


    def __clear__(self):
        """
        Removes all items from the key list and the dictionary.
        """
        self._keys = []
        UserDict.clear(self)


    def __delitems__(self, itemname):
        """
        Deletes an existing item from the key list and the dictionary.
        """
        if itemname in self._keys:
            UserDict.__delitem__(self, itemname)
            self._keys.remove(itemname)


    def __setitem__(self, key, item):
        """
        Adds or appends an item to the key list and the dictionary.
        """
        UserDict.__setitem__(self, key, item)
        
        # remove key if it already exists
        if key in self._keys: 
            self._keys.remove(key)

        # add key to the end of the list
        self._keys.append(key)


    def keys(self):
        """
        Returns an ordered, immutable list of dictionary keys.
        """
        return self._keys[:]


    def nkeys(self):
        """
        Returns the number of items in the dictionary.
        """
        return len(self._keys)


    def update(self, dict):
        UserDict.update(self, dict)
        for key in dict.keys():
            if key not in self._keys: 
                self._keys.append(key)


    def values(self):
        """
        Lists the values in the dictionary.
        """
        return map(self.get, self._keys)


    def remove(self, itemname):
        """
        Removes an item from the key list and the dictionary.
        """
        self.__delitems__(itemname)


    def insert(self, key, item, index):
        """
        Inserts an item into the list at the specified index.
        """
        UserDict.__setitem__(self, key, item)

        # remove key if it already exists
        if key in self._keys:
            self._keys.remove(key)
            
        # insert key at the specified index
        self._keys.insert(index, key)


    def copy(self):
        """
        Returns a copy of the ordered dictionary.
        """
        dict = UserDict.copy(self)
        dict._keys = self._keys[:]
        return dict



