# shamelessly scrubbed (and renamed) from:
#   http://code.activestate.com/recipes/66315/
# ==> updated with __contains__

class idict:
  """Dictionary, that has case-insensitive keys.
  
  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)."""
    k = key.lower()
    return self._dict[k][1]

  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 __delitem__(self, key):
    """Deletes the 'value' associated with 'key'."""
    k = key.lower()
    del self._dict[k]

  def __contains__(self, key):
    """Support for "in" operator."""
    return self.has_key(key)

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

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

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

  def items(self):
    """List of (key,value) pairs."""
    return 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 not self.has_key(key):
      self[key] = default
    return self[key]

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

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

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