"""Catalog and searching components for academics stuff.
"""
import grok
from hurry.query import Eq, Text
from hurry.query.query import Query
from zope.catalog.interfaces import ICatalog
from zope.component import getUtility
from zope.component.interfaces import ComponentLookupError
from zope.index.text.parsetree import ParseError
from zope.intid import IIntIds
#from waeup.sirp.catalog import QueryResultItem
from waeup.sirp.index import UniqueField
from waeup.sirp.interfaces import IUniversity, IQueryResultItem
from waeup.sirp.university.interfaces import (
    ICourse, ICertificateCourse, IDepartment,
    ICertificate,
    )

class CourseIndexes(grok.Indexes):
    """This catalog is needed for building sources.
    """
    grok.site(IUniversity)
    grok.name('courses_catalog')
    grok.context(ICourse)

    code = UniqueField(attribute='code')
    title = grok.index.Text(attribute='title')

class CertificatesIndexes(grok.Indexes):
    """This catalog is needed for building sources.
    """
    grok.site(IUniversity)
    grok.name('certificates_catalog')
    grok.context(ICertificate)

    code = UniqueField(attribute='code')
    application_category = grok.index.Field(attribute='application_category')

class CertificateCoursesIndexes(grok.Indexes):
    """This catalog is needed for automatic removal of certificate courses
    and later for selection course tickets in the students section.
    """
    grok.site(IUniversity)
    grok.name('certcourses_catalog')
    grok.context(ICertificateCourse)

    course_code = grok.index.Field(attribute='getCourseCode')

@grok.subscribe(ICourse, grok.IObjectAddedEvent)
def handleCourseAdd(obj, event):
    """Index an added course with the local catalog.

    Courses are not indexed automatically, as they are not a
    dictionary subitem of the accompanied site object
    (`IUniversity`). I.e. one cannot get them by asking for
    ``app['FACCODE']['DEPTCODE']['COURSECODE']`` but one has to ask for
    ``app.faculties['FACCODE']['DEPTCODE'].courses['COURSECODE']``.

    Once, a course is indexed we can leave the further handling to
    the default component architechture. At least removals will
    be handled correctly then (and the course unindexed).
    """
    try:
        cat = getUtility(ICatalog, name='courses_catalog')
    except ComponentLookupError:
        # catalog not available. This might happen during tests.
        return
    intids = getUtility(IIntIds)
    index = cat['code']
    index.index_doc(intids.getId(obj), obj)

@grok.subscribe(ICourse, grok.IObjectAddedEvent)
def handleCertificateAdd(obj, event):
    """Index an added certificates with the local catalog.

    See handleCourseAdd.
    """
    try:
      cat = getUtility(ICatalog, name='certificates_catalog')
    except ComponentLookupError:
      # catalog not available. This might happen during tests.
      return
    intids = getUtility(IIntIds)
    index = cat['code']
    index.index_doc(intids.getId(obj), obj)

@grok.subscribe(IDepartment, grok.IObjectRemovedEvent)
def handleDepartmentRemoval(obj, event):
    """Clear courses and certificates when a department is killed.
    """
    obj.courses.clear()
    obj.certificates.clear()
    return

class CoursesQueryResultItem(object):
    grok.implements(IQueryResultItem)

    def __init__(self, context, view):
        self.context = context
        self.url = view.url(context)
        self.title = context.title
        self.code = context.code
        self.type = 'Course'

class CertificateCoursesQueryResultItem(object):
    grok.implements(IQueryResultItem)

    def __init__(self, context, view):
        self.context = context
        self.url = view.url(context)
        self.title = context.course.title
        self.code = context.getCourseCode
        self.type = 'Course Referrer'

def search(query=None, view=None):
    if not query:
        view.flash('Empty search string.')
        return

    hitlist = []
    try:
        results = Query().searchResults(
            Eq(('courses_catalog', 'code'), query))
        for result in results:
            hitlist.append(CoursesQueryResultItem(result, view=view))
        results = Query().searchResults(
            Text(('courses_catalog', 'title'), query))
        for result in results:
            hitlist.append(CoursesQueryResultItem(result, view=view))

        results = Query().searchResults(
            Eq(('certcourses_catalog', 'course_code'), query))
        for result in results:
            hitlist.append(CertificateCoursesQueryResultItem(result, view=view))
    except ParseError:
        view.flash('Search string not allowed.')
        return
    return hitlist
