'''
Created on Mar 26, 2014

@author: LAB_ADM
'''
from django.utils.translation import ugettext_lazy as _
from xadmin.filters import manager,MultiSelectFieldListFilter
from xadmin.plugins.filters import *
from xadmin.compatibility import filter

@manager.register
class QuickFilterMultiSelectFieldListFilter(MultiSelectFieldListFilter):
    """ Delegates the filter to the default filter and ors the results of each
     
    Lists the distinct values of each field as a checkbox
    Uses the default spec for each 
     
    """
    template = 'xadmin/filters/quickfilter.html'

class QuickFilterPlugin(BaseAdminPlugin):
    """ Add a filter menu to the left column of the page """
    list_quick_filter = () # these must be a subset of list_filter to work
    quickfilter = {} 
    search_fields = ()
    free_query_filter = True
    
    def init_request(self, *args, **kwargs):
        menu_style_accordian = hasattr(self.admin_view,'menu_style') and self.admin_view.menu_style == 'accordion'
        return bool(self.list_quick_filter) and not menu_style_accordian
    
    # Media
    def get_media(self, media):
        return media + self.vendor('xadmin.plugin.quickfilter.js','xadmin.plugin.quickfilter.css')
    
    def lookup_allowed(self, lookup, value):
        model = self.model
        # Check FKey lookups that are allowed, so that popups produced by
        # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to,
        # are allowed to work.
        for l in model._meta.related_fkey_lookups:
            for k, v in widgets.url_params_from_lookup_dict(l).items():
                if k == lookup and v == value:
                    return True
 
        parts = lookup.split(LOOKUP_SEP)
 
        # Last term in lookup is a query term (__exact, __startswith etc)
        # This term can be ignored.
        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
            parts.pop()
 
        # Special case -- foo__id__exact and foo__id queries are implied
        # if foo has been specificially included in the lookup list; so
        # drop __id if it is the last part. However, first we need to find
        # the pk attribute name.
        rel_name = None
        for part in parts[:-1]:
            try:
                field, _, _, _ = model._meta.get_field_by_name(part)
            except FieldDoesNotExist:
                # Lookups on non-existants fields are ok, since they're ignored
                # later.
                return True
            if field.is_relation:
                model = field.related_model
                rel_name = field.rel.get_related_field().name
            elif isinstance(field, ForeignObjectRel):
                model = field.model
                rel_name = model._meta.pk.name
            else:
                rel_name = None
        if rel_name and len(parts) > 1 and parts[-1] == rel_name:
            parts.pop()
 
        if len(parts) == 1:
            return True
        clean_lookup = LOOKUP_SEP.join(parts)
        return clean_lookup in self.list_quick_filter
 
    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items() if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in six.iteritems(lookup_params):
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False
        
        if not hasattr(self.admin_view,'quickfilter'):
            self.admin_view.quickfilter = {}
 
        # for clean filters
        self.admin_view.quickfilter['has_query_param'] = bool(lookup_params)
        self.admin_view.quickfilter['clean_query_url'] = self.admin_view.get_query_string(remove=[k for k in self.request.GET.keys() if k.startswith(FILTER_PREFIX)])
 
        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation("Filtering by %s not allowed" % key)
 
        self.filter_specs = []
        if self.list_quick_filter:
            for list_quick_filter in self.list_quick_filter:
                field_path = None
                field_order_by = None
                field_limit = None
                field_parts = []
                sort_key = None 
                cache_config = None
                
                if type(list_quick_filter)==dict and 'field' in list_quick_filter:
                    field = list_quick_filter['field']
                    if 'order_by' in list_quick_filter:
                        field_order_by = list_quick_filter['order_by']
                    if 'limit' in list_quick_filter:
                        field_limit = list_quick_filter['limit']
                    if 'sort' in list_quick_filter and callable(list_quick_filter['sort']):
                        sort_key = list_quick_filter['sort']
                    if 'cache' in list_quick_filter and type(list_quick_filter)==dict:
                        cache_config = list_quick_filter['cache']
                        
                else:        
                    field = list_quick_filter # This plugin only uses MultiselectFieldListFilter
                
                if not isinstance(field, models.Field):
                    field_path = field
                    field_parts = get_fields_from_path(self.model, field_path)
                    field = field_parts[-1]
                spec = QuickFilterMultiSelectFieldListFilter(field, self.request, lookup_params,self.model, self.admin_view, field_path=field_path,field_order_by=field_order_by,field_limit=field_limit,sort_key=sort_key,cache_config=cache_config)
                 
                if len(field_parts)>1:
                    spec.title = "%s %s"%(field_parts[-2].name,spec.title) 
                 
                # Check if we need to use distinct()
                use_distinct = True#(use_distinct orlookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError:
                        import sys
                        e =  sys.exc_info()[1]
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs
 
                    self.filter_specs.append(spec)
 
        self.has_filters = bool(self.filter_specs)
        self.admin_view.quickfilter['filter_specs'] = self.filter_specs
        self.admin_view.quickfilter['used_filter_num'] = len(filter(lambda f: f.is_used, self.filter_specs))
 
        if use_distinct:
            return queryset.distinct()
        else:
            return queryset
    
    def block_left_navbar(self, context, nodes):
        nodes.append(loader.render_to_string('xadmin/blocks/modal_list.left_navbar.quickfilter.html',context))
        
site.register_plugin(QuickFilterPlugin, ListAdminView)