"Base classes for lookup creation."

import operator
import re

from django.conf import settings
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse
from django.db.models import Q
from django.utils import simplejson as json
from django.utils.encoding import smart_unicode
from django.utils.html import conditional_escape
from django.utils.translation import ugettext as _

from selectable.forms import BaseLookupForm


__all__ = (
    'LookupBase',
    'ModelLookup',
)


class LookupBase(object):
    "Base class for all django-selectable lookups."

    form = BaseLookupForm

    def _name(cls):
        app_name = cls.__module__.split('.')[-2].lower()
        class_name = cls.__name__.lower()
        name = u'%s-%s' % (app_name, class_name)       
        return name
    name = classmethod(_name)

    def _url(cls):
        return reverse('selectable-lookup', args=[cls.name()])
    url = classmethod(_url)

    def get_query(self, request, term):
        return []

    def get_item_label(self, item):
        return smart_unicode(item)

    def get_item_id(self, item):
        return smart_unicode(item)

    def get_item_value(self, item):
        return smart_unicode(item)

    def get_item(self, value):
        return value

    def create_item(self, value):
        raise NotImplemented()

    def format_item(self, item):
         return {
            'id': self.get_item_id(item),
            'value': self.get_item_value(item),
            'label': conditional_escape(self.get_item_label(item))
        }

    def paginate_results(self, request, results, limit):
        paginator = Paginator(results, limit)
        try:
            page = int(request.GET.get('page', '1'))
        except ValueError:
            page = 1
        try:
            results = paginator.page(page)
        except (EmptyPage, InvalidPage):
            results = paginator.page(paginator.num_pages)
        return results

    def results(self, request):
        data = []
        form = self.form(request.GET)
        if form.is_valid():
            term = form.cleaned_data.get('term', '')
            limit = form.cleaned_data.get('limit', None)
            raw_data = self.get_query(request, term)
            page_data = None      
            if limit:
                page_data = self.paginate_results(request, raw_data, limit)
                raw_data = page_data.object_list
            for item in raw_data:
                data.append(self.format_item(item))
            if page_data and hasattr(page_data, 'has_next') and page_data.has_next():
                data.append({
                    'id': '',
                    'value': '',
                    'label': _('Show more results'),
                    'page': page_data.next_page_number()
                })        
        content = json.dumps(data, cls=DjangoJSONEncoder, ensure_ascii=False)
        return HttpResponse(content, content_type='application/json')    


class ModelLookup(LookupBase):
    "Lookup class for easily defining lookups based on Django models."

    model = None
    filters = {}
    search_fields = ()

    def get_query(self, request, term):
        qs = self.get_queryset()
        if term:
            search_filters = []
            if self.search_fields:
                for field in self.search_fields:
                    search_filters.append(Q(**{field: term}))
            qs = qs.filter(reduce(operator.or_, search_filters))
        return qs

    def get_queryset(self):
        qs = self.model._default_manager.get_query_set()
        if self.filters:
            qs = qs.filter(**self.filters)
        return qs

    def get_item_id(self, item):
        return item.pk

    def get_item(self, value):
        item = None
        if value:
            try:
                item = self.get_queryset().filter(pk=value)[0]
            except IndexError:
                pass
        return item

    def create_item(self, value):
        data = {}
        if self.search_fields:
            field_name = re.sub(r'__\w+$', '',  self.search_fields[0])
            if field_name:
                data = {field_name: value}
        return self.model(**data)

@@ -895,23 +895,16 @@
 ss_name)
-       
 %0A       
@@ -1478,25 +1478,24 @@
 elf, item):%0A
- 
         retu

Clean up some PEP8 problems. These were pointed out by @slafs.