
__author__ = "Charlie Taylor (charlietaylor@sourceforge.net)"
__version__ = " 1.0 "
__date__ = "Oct 21, 2005"
__copyright__ = "Copyright (c) 2009 Charlie Taylor"
__license__ = "BSD"

class LikeDict:
    """
    Dictionary, that has case-insensitive keys. (see SQL LIKE command)
    
    Keys are retained in their original form
    when queried with .keys() or .items().

    Implementation: An internal dictionary maps lowercase
    keys to (key,value) pairs. All key lookups are done
    against the lowercase keys, but all methods that expose
    keys to the user retrieve the original keys.
    """
    
    def __init__(self, dict=None):
        """Create an empty dictionary, or update from 'dict'."""
        self._dict = {}
        if dict:
            self.update(dict)

    def __getitem__(self, key):
        """Retrieve the value associated with 'key' (in any case)."""
        try:
            k = key.lower()
        except:
            k = key
        return self._dict[k][1]

    def __contains__(self, key):
        k = key.lower()
        return k in self._dict
    
    def __setitem__(self, key, value):
        """Associate 'value' with 'key'. If 'key' already exists, but
        in different case, it will be replaced."""
        k = key.lower()
        self._dict[k] = (key, value)

    def has_key(self, key):
        """Case insensitive test wether 'key' exists."""
        k = key.lower()
        return k in self._dict

    def keys(self):
        """List of keys in their original case."""
        return [v[0] for v in list(self._dict.values())]

    def values(self):
        """List of values."""
        return [v[1] for v in list(self._dict.values())]

    def items(self):
        """List of (key,value) pairs."""
        return list(self._dict.values())

    def get(self, key, default=None):
        """Retrieve value associated with 'key' or return default value
        if 'key' doesn't exist."""
        try:
            return self[key]
        except KeyError:
            return default

    def setdefault(self, key, default):
        """If 'key' doesn't exists, associate it with the 'default' value.
        Return value associated with 'key'."""
        if key not in self:
            self[key] = default
        return self[key]

    def update(self, dict):
        """Copy (key,value) pairs from 'dict'."""
        for k,v in list(dict.items()):
            self[k] = v

    def __repr__(self):
        """String representation of the dictionary."""
        items = ", ".join([("%r: %r" % (k,v)) for k,v in list(self.items())])
        return "{%s}" % items

    def __str__(self):
        """String representation of the dictionary."""
        return repr(self)
