# Originally written by Armin Rigo
# http://codespeak.net/svn/user/arigo/hack/pyfuse/OrderedDict.py

from UserDict import DictMixin


DELETED = object()


class OrderedDict(DictMixin):

    def __init__(self, *args, **kwds):
        self.clear()
        self.update(*args, **kwds)

    def clear(self):
        self._keys = []
        self._content = {}    # {key: (index, value)}
        self._deleted = 0

    def copy(self):
        return OrderedDict(self)

    def __iter__(self):
        for key in self._keys:
            if key is not DELETED:
                yield key

    def keys(self):
        return [key for key in self._keys if key is not DELETED]

    def popitem(self):
        while 1:
            try:
                k = self._keys.pop()
            except IndexError:
                raise KeyError, 'OrderedDict is empty'
            if k is not DELETED:
                return k, self._content.pop(k)[1]

    def __getitem__(self, key):
        index, value = self._content[key]
        return value

    def __setitem__(self, key, value):
        try:
            index, oldvalue = self._content[key]
        except KeyError:
            index = len(self._keys)
            self._keys.append(key)
        self._content[key] = index, value

    def __delitem__(self, key):
        index, oldvalue = self._content.pop(key)
        self._keys[index] = DELETED
        if self._deleted <= len(self._content):
            self._deleted += 1
        else:
            # compress
            newkeys = []
            for k in self._keys:
                if k is not DELETED:
                    i, value = self._content[k]
                    self._content[k] = len(newkeys), value
                    newkeys.append(k)
            self._keys = newkeys
            self._deleted = 0

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

    def __repr__(self):
        res = ['%r: %r' % (key, self._content[key][1]) for key in self]
        return 'OrderedDict(%s)' % (', '.join(res),)

    def __cmp__(self, other):
        if not isinstance(other, OrderedDict):
            return NotImplemented
        keys = self.keys()
        r = cmp(keys, other.keys())
        if r:
            return r
        for k in keys:
            r = cmp(self[k], other[k])
            if r:
                return r
        return 0
