from collections import OrderedDict

from multidict import MultiDict, CIMultiDict


class BaseMultiDict(MultiDict):
    """
    Base class for all MultiDicts.
    """


class HTTPHeadersDict(CIMultiDict, BaseMultiDict):
    """
    Headers are case-insensitive and multiple values are supported
    through the `add()` API.
    """

    def add(self, key, value):
        """
        Add or update a new header.

        If the given `value` is `None`, then all the previous
        values will be overwritten and the value will be set
        to `None`.
        """
        if value is None:
            self[key] = value
            return None

        # If the previous value for the given header is `None`
        # then discard it since we are explicitly giving a new
        # value for it.
        if key in self and self.getone(key) is None:
            self.popone(key)

        super().add(key, value)

    def remove_item(self, key, value):
        """
        Remove a (key, value) pair from the dict.
        """
        existing_values = self.popall(key)
        existing_values.remove(value)

        for value in existing_values:
            self.add(key, value)


class RequestJSONDataDict(OrderedDict):
    pass


class MultiValueOrderedDict(OrderedDict):
    """Multi-value dict for URL parameters and form data."""

    def __setitem__(self, key, value):
        """
        If `key` is assigned more than once, `self[key]` holds a
        `list` of all the values.

        This allows having multiple fields with the same name in form
        data and URL params.

        """
        assert not isinstance(value, list)
        if key not in self:
            super().__setitem__(key, value)
        else:
            if not isinstance(self[key], list):
                super().__setitem__(key, [self[key]])
            self[key].append(value)

    def items(self):
        for key, values in super().items():
            if not isinstance(values, list):
                values = [values]
            for value in values:
                yield key, value


class RequestQueryParamsDict(MultiValueOrderedDict):
    pass


class RequestDataDict(MultiValueOrderedDict):
    pass


class MultipartRequestDataDict(MultiValueOrderedDict):
    pass


class RequestFilesDict(RequestDataDict):
    pass


class NestedJSONArray(list):
    """Denotes a top-level JSON array."""
