# -*- coding: utf-8 -*-

import functools
import collections
import math
import peewee
import flask

from poobrains import app
import poobrains.helpers
import poobrains.form
import poobrains.storage
import poobrains.auth


class SearchField(poobrains.form.fields.Text):
    pass


@app.box('search')
def box_search():
    try:
        Search.permissions['read'].check(flask.g.user)
        return SearchForm(custom_id='box-search')
    except poobrains.auth.AccessDenied:
        return None


class SearchForm(poobrains.form.Form):

    pattern = SearchField()
    search = poobrains.form.Button('submit', value='search', label='Search')

    def __init__(self, *args, **kwargs):

        if not 'action' in kwargs:
            kwargs['action'] = app.site.get_view_url(Search, mode='full')

        if not self.fields['pattern'].value and 'search_pattern' in flask.session:
            self.fields['pattern'].value = flask.session['search_pattern']

        super(SearchForm, self).__init__(*args, **kwargs)


class Search(poobrains.auth.Protected):

    form = None
    offset = None
    results = None

    def __init__(self, handle='', offset=0, **kwargs):
        
        super(Search, self).__init__(name=self.__class__.__name__, handle=handle)

        self.form = SearchForm()
        self.form.fields['pattern'].value = self.handle_string
        self.form.clear = poobrains.form.Button('submit', value='clear', label='Clear')
        self.offset = offset
        self.results = []


    @poobrains.helpers.themed
    def view(self, mode='full', offset=0, **kwargs):

        if flask.request.method == 'POST':
            
            pattern = flask.request.form[self.form.name]['pattern']
            
            if 'clear' in flask.request.form:
                flask.session.pop('search_pattern', None)
                return flask.redirect(app.site.get_view_url(self.__class__, mode='full'))

            self.handle_string = pattern
            flask.session['search_pattern'] = pattern
            return flask.redirect(self.url('full'))

        if len(self.handle_string) == 0 and 'search_pattern' in flask.session:
            if len(flask.session['search_pattern']) >= 3:
                # redirect requests with empty search handle to the saved search
                self.handle_string = flask.session['search_pattern']
                return flask.redirect(self.url('full'))

        administerables = poobrains.auth.Administerable.class_children_keyed()
        readable_administerables = []

        if len(self.handle_string) >= 3:

            flask.session['search_pattern'] = self.handle_string

            for key in sorted(administerables):

                administerable = administerables[key]

                try:
                    administerable.permissions['read'].check(flask.g.user)
                    readable_administerables.append(administerable)

                except poobrains.auth.AccessDenied:
                    pass

            queries = []
            
            for administerable in readable_administerables:

                q = administerable.list('read', flask.g.user)
                clauses = []

                if isinstance(app.db, peewee.SqliteDatabase):
                    term = '*%s*' % self.handle_string.lower()
                else: # postgres
                    term = '%%%s%%' % self.handle_string.lower()

                if hasattr(administerable._meta, 'search_fields'):

                    for field_name in administerable._meta.search_fields:

                        field = getattr(administerable, field_name)
                        clauses.append((peewee.fn.Lower(field) % term))

                else:
                    
                    if isinstance(getattr(administerable, 'name', None), poobrains.storage.fields.CharField):
                        clauses.append((peewee.fn.Lower(administerable.name) % term))

                    if isinstance(getattr(administerable, 'title', None), poobrains.storage.fields.CharField):
                        clauses.append((peewee.fn.Lower(administerable.title) % term)) # LIKE clause
                    
                    if isinstance(getattr(administerable, 'text', None), poobrains.storage.fields.TextField):
                        clauses.append((peewee.fn.Lower(administerable.text) % term)) # LIKE clause

                if len(clauses):
                    queries.append(q.where(functools.reduce(peewee.operator.or_, clauses)))
                else:
                    continue


            pagination = poobrains.storage.Pagination(queries, offset, 'site.search_handle_offset', handle=self.handle_string)
            self.results = pagination.results
            self.pagination = pagination.menu


        elif len(self.handle_string) > 0:
            flask.flash(u"Search pattern has to be at least 3 characters long.", 'error')

        return self

app.site.add_view(Search, '/search/', mode='full', endpoint='search')
app.site.add_view(Search, '/search/<handle>/', mode='full', endpoint='search_handle')
app.site.add_view(Search, '/search/<handle>/+<int:offset>', mode='full', endpoint='search_handle_offset')
