"""Workflow for applicants.
"""
import grok
from datetime import datetime
from hurry.workflow.workflow import (
    Transition, Workflow, WorkflowVersions, WorkflowInfo, WorkflowState,
    NullCondition)
from hurry.workflow.interfaces import (
    IWorkflow, IWorkflowState, IWorkflowInfo, IWorkflowVersions,
    InvalidTransitionError, IWorkflowTransitionEvent)
from waeup.sirp.applicants.interfaces import IApplicantBaseData


INITIALIZED = 'initialized'
STARTED = 'started'
SUBMITTED = 'submitted'
ADMITTED = 'admitted'
NOT_ADMITTED = 'not admitted'
CREATED = 'created'

def create_workflow():
    init_transition = Transition(
        transition_id = 'init',
        title = 'Initialize application',
        source = None,
        condition = NullCondition,
        msg = 'application process initialized',
        destination = INITIALIZED)

    start_transition = Transition(
        transition_id = 'start',
        title = 'Start application',
        msg = 'application process started',
        source = INITIALIZED,
        destination = STARTED)

    submit_transition = Transition(
        transition_id = 'submit',
        title = 'Submit application',
        msg = 'application record submitted',
        source = STARTED,
        destination = SUBMITTED)

    admit_transition = Transition(
        transition_id = 'admit',
        title = 'Admit applicant',
        msg = 'applicant admitted',
        source = SUBMITTED,
        destination = ADMITTED)

    refuse1_transition = Transition(
        transition_id = 'refuse1',
        title = 'Refuse application',
        msg = 'application refused',
        source = SUBMITTED,
        destination = NOT_ADMITTED)

    refuse2_transition = Transition(
        transition_id = 'refuse2',
        title = 'Refuse application',
        msg = 'application refused',
        source = ADMITTED,
        destination = NOT_ADMITTED)

    create_transition = Transition(
        transition_id = 'create',
        title = 'Create student record',
        msg = 'student record created',
        source = ADMITTED,
        destination = CREATED)

    reset1_transition = Transition(
        transition_id = 'reset1',
        title = 'Reset application',
        msg = 'application record reset',
        source = SUBMITTED,
        destination = STARTED)

    reset2_transition = Transition(
        transition_id = 'reset2',
        title = 'Reset application',
        msg = 'application record reset',
        source = ADMITTED,
        destination = STARTED)

    reset3_transition = Transition(
        transition_id = 'reset3',
        title = 'Reset application',
        msg = 'application record reset',
        source = NOT_ADMITTED,
        destination = STARTED)

    reset4_transition = Transition(
        transition_id = 'reset4',
        title = 'Reset application',
        msg = 'application record reset',
        source = CREATED,
        destination = STARTED)

    return [init_transition, start_transition, submit_transition,
            admit_transition, create_transition, refuse1_transition,
            refuse2_transition, reset1_transition, reset2_transition,
            reset3_transition, reset4_transition]


class ApplicationWorkflow(Workflow):
    """A hurry.workflow Workflow with more appropriate error messages.
    """
    grok.provides(IWorkflow)
    def __init__(self):
        super(Workflow, self).__init__()
        self.refresh(create_workflow())

    def getTransition(self, source, transition_id):
        transition = self._id_transitions[transition_id]
        if transition.source != source:
            raise InvalidTransitionError(
                "Transition '%s' requires '%s' as source state (is: '%s')" % (
                    transition_id, transition.source, source))
        return transition


class ApplicationWorkflowNullVersions(WorkflowVersions):
    """A workflow versions manager that does not handle versions.

    Sounds odd, but the default implementation of
    :class:`hurry.workflow.workflow.WorkflowVersions` is a base
    implementation that raises :exc:`NotImplemented` exceptions for
    most of the methods defined below.

    If we want to register a versionless workflow, an utility
    implementing IWorkflowVersions is looked up nevertheless by
    WorkflowInfo and WorkflowState components so we **have** to
    provide workflow versions, even if we do not support versioned
    workflows.

    This implementation returns empty result sets for any requests,
    but does not raise :exc:`NotImplemented`.
    """
    def getVersions(self, state, id):
        return []

    def getVersionsWithAutomaticTransitions(self):
        return []

    def hasVersion(self, id, state):
        return False

    def hasVersionId(self, id):
        return False

# Register global utilities for workflows and workflow versions...
grok.global_utility(ApplicationWorkflow, IWorkflow)
grok.global_utility(ApplicationWorkflowNullVersions, IWorkflowVersions)

class ApplicationState(grok.Adapter, WorkflowState):
    """An adapter to adapt Applicant objects to workflow states.
    """
    grok.context(IApplicantBaseData)
    grok.provides(IWorkflowState)

class ApplicationInfo(grok.Adapter, WorkflowInfo):
    """Adapter to adapt Applicant objects to workflow info objects.
    """
    grok.context(IApplicantBaseData)
    grok.provides(IWorkflowInfo)


@grok.subscribe(IApplicantBaseData, IWorkflowTransitionEvent)
def handle_applicant_transition_event(obj, event):
    """Append message to applicant when transition happened.
    """
    timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
    # XXX: We should not store HTML code but simple messages.
    msg = '%s - %s (new state: %s)' % (
        timestamp, event.transition.user_data['msg'], event.destination)
    msgs = getattr(obj, 'msgs', None)
    if msgs:
        msgs += '<br />'
        msgs += msg
    else:
        msgs = msg
    obj.msgs = msgs
    return
