# by Michal migajek Gajek

class NBResource(ModelResource):
    class Meta:        
        abstract = True
        
        # there are three options for specifying filters.
        # it's either a dictionary of 'filter_name': queryset
        # or a tuple of filter names
        # in the second case, if the default_manager attribute is provided
        # the filter name is assumed to be Manager method, 
        # otherwise it's assumed to be QuerySet method
        default_manager = None 
        manager_filters = ()
        
    def prepend_urls(self):
        """ if there are allowed custom Manager methods, add special url for that"""
        return [
                 url(r"^(?P<resource_name>%s)/filtered_list/(?P<filter>\w+)%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list_filtered'), name="api_dispatch_list_filtered"),
        ] if self._meta.manager_filters else []
        
    def dispatch_list_filtered(self, request, **kwargs):
        """ check if the provided filter name is valid, and - if so - proceed to the get_object_list """ 
        mfilter = kwargs.pop('filter')
        filters = self._meta.manager_filters        
        if (isinstance(filters, dict) and not mfilter in filters.keys()) or \
            not mfilter in filters:
                raise Exception('Invalid filter (%s) name provided' % filter)
                
        request.custom_filter = mfilter
        return self.dispatch_list(request)
        
    def get_object_list(self, request):        
        """ applies custom filtering if the filter name was provided """
        if hasattr(request, 'custom_filter'):
            filters = self._meta.manager_filters
            if isinstance(filters, dict):
                # filter to apply is in fact a name of queryset specified in Resource 
                queryset = filters[request.custom_filter]._clone()
            else:
                # if there's a default_manager, filter is it's method
                # otherwise we assume filter is a method of default QuerySet
                manager_or_queryset = self._meta.default_manager or super(NBResource, self).get_object_list(request)
                method = getattr(manager_or_queryset, request.custom_filter)
                if not method:
                    raise Exception('Manager or QuerySet does not have method named %s' % request.custom_filter)
                
                #FIXME: very, very ugly trick...                
                kwargs = request.GET.dict()
                if 'format' in kwargs.keys():
                    kwargs = deepcopy(kwargs)
                    kwargs.pop('format')
                queryset = method(**kwargs) 
        else:
            queryset = super(NBResource, self).get_object_list(request)
        return queryset








#### example usage

# scenario one - simple - define filters as querysets directly in the ModelResource
class FooResource(NBResource)
    class Meta:
        queryset = Foo.objects.all() #standard definition for TastyPie
        manager_filters = {'active': Foo.objects.filter(active = True) }
# calling /api/foo/filtered_list/active 
# will return only items with active = True attribute
        



# scenario two - complex filtering based on custom Manager's method
class FooManager(models.Manager)
    def recent_active_items(some_parameter)
        return filteredQuerySet

class Foo(models.Model)
   ...
   objects = FooManager()


class FooResource(NBResource)
    class Meta:
        queryset = Foo.objects.all() #standard definition for TastyPie
        manager_filters = ('recent_active_items',)
        default_manager = Foo.objects 
# calling /api/foo/filtered_list/recent_active_items?some_parameter=value
# will call FooManager's method with some_parameter as keyword argument