##
# File:    CaseNormalizedDict.py
# Author:  J. Westbrook
# Date:    4-Sep-2018
# Version: 0.001
#
# Updates:
##
"""
Dictionary container with case insensitive key comparison preserving the
case of the input keys.
"""

__docformat__ = "restructuredtext en"
__author__ = "John Westbrook"
__email__ = "jwest@rcsb.rutgers.edu"
__license__ = "Apache 2.0"

import collections
import logging

logger = logging.getLogger(__name__)


class CaseNormalizedDict(dict):

    """ Dictionary container with case insensitive key comparison preserving the
        case of the input keys.

    """

    # This example subclasses dict directly following the example from the requests module.
    # proxy = {}

    def __init__(self, data):
        super(CaseNormalizedDict, self).__init__(data)
        self.__local = dict((k.lower(), k) for k in data)
        # for k in data:
        #    self[k] = data[k]

    def __contains__(self, k):
        return k.lower() in self.__local

    def __delitem__(self, k):
        key = self.__local[k.lower()]
        super(CaseNormalizedDict, self).__delitem__(key)
        del self.__local[k.lower()]

    def __getitem__(self, k):
        key = self.__local[k.lower()]
        return super(CaseNormalizedDict, self).__getitem__(key)

    def get(self, k, default=None):
        return self[k] if k in self else default

    def __setitem__(self, k, v):
        super(CaseNormalizedDict, self).__setitem__(k, v)
        self.__local[k.lower()] = k


class CaseNormalizedDict2(collections.MutableMapping):

    """ Dictionary container with case insensitive key comparison preserving the
        case of the input keys.

    """

    # This example subclasses the abstract base class MutableMapping.

    def __init__(self, *args, **kwargs):
        self.__dict__.update(*args, **kwargs)
        self.__local = dict((k.lower(), k) for k in self.__dict__)

    def __contains__(self, k):
        return k.lower() in self.__local

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

    def __iter__(self):
        return iter(self.__local)

    def __getitem__(self, k):
        return self.__dict__[self.__local[k.lower()]]

    def __setitem__(self, k, val):
        self.__dict__[k] = val
        self.__local[k.lower()] = k

    def __delitem__(self, k):
        del self.__dict__[k]
        del self.__local[k.lower()]

    def pop(self, k):
        kp = self.__local.pop(k.lower())
        return self.__dict__.pop(kp)

    def getKey(self, k):
        return self.__local.get(k.lower())

    #
    def __str__(self):
        return str(self.__dict__)

    def __repr__(self):
        return "{}, ({})".format(super(CaseNormalizedDict2, self).__repr__(), self.__dict__)
