"""Destinfo managers"""
import operator
import types

from django.db import models
from django.db.models import Q
from tagging.models import Tag, TaggedItem

class SearchManager(models.Manager):
    """
    Extented manager
    """

    def search(self, search, tags=None, poi=None): # pylint: disable-msg=W0221
        """
        Filter by location and/or poi
        TODO add language through url ? en/
        """
        if not tags:
            tags = {}
        if tags or search or poi:
            query_set = self.get_query_set()
            for tag_group in tags: 
                tags_list = Tag.objects.filter(name__in=tags[tag_group])
                query_set = TaggedItem.objects.get_union_by_model(query_set, tags_list)

            if search:
                or_queries = self.get_or_queries(search)
                query_set = query_set.filter(reduce(operator.or_, or_queries))
            else:
                query_set = query_set.all()

            and_queries = []            
            if poi:
                and_queries = self.get_and_queries(poi)

            if and_queries:
                query_set = query_set.filter(reduce(operator.and_, and_queries))

            return query_set.order_by('name').distinct()
        else:
            return []
        # if self.model._meta.object_name == 'Location':
        #     return query_set.order_by('name').distinct()
        # else:
        #     # TODO: add to settings
        #     return query_set.order_by('location').distinct()

    def get_and_queries(self, poi):
        """
        Prepare and_queries.
        """
        and_queries = []
        for key, value in poi:
            and_queries.append(self.construct_q(key, value, base="poi"))
        # if location:
        #     for key, value in location:
        #         and_queries.append(construct_q(key, value))
        return and_queries

    def get_or_queries(self, search):
        """
        Prepare or_queries.
        """
        # TODO: add to settings
        or_queries = []
        model_search = ('name',)
        location_search = ('name', )
        poi_search = ('name',)
        # location_search = []
        poi_search = []

        
        
        base = ''
        if self.model._meta.object_name != 'Location':
            # we are not searching from Location model - add model search and set base
            for field in model_search:
                or_queries.append(self.construct_q(field, search,
                                                   base=base))
            base = 'location'

        for field in location_search:
            or_queries.append(self.construct_q(field, search,
                                               base=base))
        
        for field in poi_search:
            or_queries.append(self.construct_q(field, search,
                                               base=self.add_to_base("poi", base)))

        return or_queries

    def add_to_base(self, field, base=None):
        """
        Helper function to create valid search key.
        """
        if base:
            field  = '%s__%s' % (base, field)
        return field

    # def get_poi(self):
    #     """
    #     Get filtered poi to each Location
    #     """
    #     if getattr(self, poi_queries):
            
        
    def construct_q(self, field_name, value, base=None): # pylint: disable-msg=R0201
        """
        Helper method for construct Q objects
        """

        if field_name.startswith('^'):
            key = "%s__istartswith" % field_name[1:]
        elif field_name.startswith('='):
            key = "%s__iexact" % field_name[1:]
        elif field_name.startswith('@'):
            key = "%s__search" % field_name[1:]
        elif type(value) is types.ListType:
            key = "%s__in" % field_name
        else:
            key = "%s__icontains" % field_name
            
        if base:
            key = "%s__%s" % (base, key)
        return Q(**{key: value})
