"""WAeUP portal certificates
"""
import grok
from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
try:
    from zope.catalog.interfaces import ICatalog
except ImportError:
    # BBB
    from zope.app.catalog.interfaces import ICatalog
from zope.component import getUtility
from zope.component.interfaces import IFactory, ComponentLookupError
from zope.interface import implementedBy
from waeup.sirp.university.interfaces import (
    ICertificate, ICertificateCourse, ICourse)

class Certificate(grok.Container):
    """A certificate.
    """
    grok.implements(ICertificate)

    def __init__(self, code=u'NA', title=u'Unnamed Certificate',
                 study_mode=None, start_level=None,
                 end_level=None, application_category=None, max_pass = u''):
        super(Certificate, self).__init__()
        self.code = code
        self.title = title
        self.study_mode = study_mode
        self.start_level = start_level
        self.end_level = end_level
        self.application_category = application_category
        self.max_pass = max_pass
        # Initialize workflow state...
        self.setReviewState('unchecked')

    def check(self):
        """Set Review State to ``checked``.
        """
        self.setReviewState(state='checked')

    def getReviewState(self):
        return IWorkflowState(self).getState()

    def setReviewState(self, state=None):
        """Try to set new state.

        Instead of simply setting a value, we fire a transition of a
        workflow. This might fail if, for instance, the required state
        is not part of the workflow or unreachable from current state.
        """
        if state == self.getReviewState():
            # Accept staying in the same state, even if workflow does
            # not allow this.
            return
        info = IWorkflowInfo(self)
        info.fireTransitionToward(state)
        return

    review_state = property(getReviewState, setReviewState)
    
    def addCourseRef(self, course, level=100, core_or_elective=True):
        """Add a course reference.
        """
        code = "%s_%s" % (course.code, level)
        self[code] = CertificateCourse(course, level, core_or_elective)
        self[code].__parent__ = self
        self[code].__name__ = code
        self._p_changed = True

    def delCourseRef(self, code, level=None):
        """Delete a course denoted by its code.
        """
        for key in self.keys():
            if self[key].getCourseCode() != code:
                continue
            if level is not None and str(self[key].level) != str(level):
                # found a course with correct key but wrong level...
                continue
            del self[key]
            self._p_changed = True
        return




class CertificateFactory(grok.GlobalUtility):
    """A factory for certificates.
    """
    grok.implements(IFactory)
    grok.name(u'waeup.Certificate')
    title = u"Create a new certificate.",
    description = u"This factory instantiates new certificate instances."

    def __call__(self, *args, **kw):
        return Certificate(*args, **kw)

    def getInterfaces(self):
        return implementedBy(Certificate)

class CertificateCourse(grok.Model):
    grok.implements(ICertificateCourse)

    def __init__(self, course=None, level=100, core_or_elective=True):
        self.course = course
        self.level = level
        self.core_or_elective = core_or_elective

    def getCourseCode(self):
        """Get code of a course.
        """
        return self.course.code
    
class CertificateCourseFactory(grok.GlobalUtility):
    """A factory for certificate courses.
    """
    grok.implements(IFactory)
    grok.name(u'waeup.CertificateCourse')
    title = u"Create a new certificate course.",
    description = u"This factory instantiates new certificate courses."

    def __call__(self, *args, **kw):
        return CertificateCourse(*args, **kw)

    def getInterfaces(self):
        return implementedBy(CertificateCourse)

@grok.subscribe(ICourse, grok.IObjectRemovedEvent)
def removedCourseHandler(course, event):
    """If a course is deleted, we make sure that also references in a
       certificatecontainer are removed.
    """
    code = course.code

    # Find all certcourses that reference the given course...
    try:
        cat = getUtility(ICatalog, name='certcourses_catalog')
    except ComponentLookupError:
        # catalog not available. This might happen during tests.
        return
        
    results = cat.searchResults(course_code=(code, code))
    for certcourse in results:
        # Remove that reference...
        cert = certcourse.__parent__
        cert.delCourseRef(code)
        cert._p_changed = True
    return
