import copy

from django import forms
from django.forms.forms import pretty_name
from django.core.exceptions import ValidationError, ImproperlyConfigured
from django.db.models import Q
from collections import OrderedDict
from django.utils import six
from django.utils.six.moves import reduce
from django.utils.http import urlencode

from .forms import BetterForm


def construct_querystring(data, **kwargs):
    params = copy.copy(data)

    # We can't call update here because QueryDict extends rather than replaces.
    for key, value in kwargs.items():
        params[key] = value

    if hasattr(params, 'urlencode'):
        return params.urlencode()
    else:
        return urlencode(params)


class IterDict(OrderedDict):
    """
    Extension of djangos built in sorted dictionary class which iterates
    through the values rather than keys.
    """
    def __iter__(self):
        for key in super(IterDict, self).__iter__():
            yield self[key]


class BaseChangeListForm(BetterForm):
    """
    Base class for all ``ChangeListForms``.
    """
    def __init__(self, *args, **kwargs):
        """
        Takes an option named argument ``queryset`` as the base queryset used in
        the ``get_queryset`` method.
        """
        try:
            self.base_queryset = kwargs.pop('queryset', None)
            if self.base_queryset is None:
                self.base_queryset = self.model.objects.all()
        except AttributeError:
            raise AttributeError('`ChangeListForm`s must be instantiated with a\
                                 queryset, or have a `model` attribute set on\
                                 them')
        super(BaseChangeListForm, self).__init__(*args, **kwargs)

    def get_queryset(self):
        """
        If the form was initialized with a queryset, this method returns that
        queryset.  Otherwise it returns ``Model.objects.all()`` for whatever
        model was defined for the form.
        """
        return self.base_queryset


class SearchForm(BaseChangeListForm):
    SEARCH_FIELDS = None
    CASE_SENSITIVE = False
    q = forms.CharField(label="Search", required=False)

    def __init__(self, *args, **kwargs):
        self.SEARCH_FIELDS = kwargs.pop('search_fields', self.SEARCH_FIELDS)
        super(SearchForm, self).__init__(*args, **kwargs)

        if self.SEARCH_FIELDS is None:
            raise ImproperlyConfigured('`SearchForm`s must be instantiated with an\
                                       iterable of fields to search over, or have \
                                       a `SEARCH_FIELDS` attribute set on them.')

    def get_queryset(self):
        """
        Constructs an '__contains' or '__icontains' filter across all of the
        fields listed in ``SEARCH_FIELDS``.
        """
        qs = super(SearchForm, self).get_queryset()