# -*- coding: utf8 -*-
# Copyright (c) 2014 by Ecreall under licence AGPL terms 
# available on http://www.gnu.org/licenses/agpl.html

# licence: AGPL
# author: Amen Souissi
"""
This module represent the Proposal management process definition 
powered by the dace engine.
"""

import datetime
from persistent.list import PersistentList
from pyramid.threadlocal import get_current_request

from dace.processdefinition.processdef import ProcessDefinition
from dace.util import getSite, find_service
from dace.processinstance.activity import (
    SubProcess as OriginSubProcess)
from dace.processdefinition.activitydef import (
    ActivityDefinition,
    SubProcessDefinition as OriginSubProcessDefinition)
from dace.processdefinition.eventdef import (
    StartEventDefinition,
    EndEventDefinition,
    IntermediateCatchEventDefinition,
    TimerEventDefinition)
from dace.processdefinition.gatewaydef import (
    ExclusiveGatewayDefinition,
    ParallelGatewayDefinition)
from dace.processdefinition.transitiondef import TransitionDefinition
from dace.objectofcollaboration.services.processdef_container import (
    process_definition)
from pontus.core import VisualisableElement

from .behaviors import (
    CreateProposal,
    SeeProposal,
    DuplicateProposal,
    EditProposal,
    PublishProposal,
    SubmitProposalModeration,
    PublishProposalModeration,
    ArchiveProposalModeration,
    CommentProposal,
    CommentProposalAnonymous,
    PresentProposal,
    PresentProposalAnonymous,
    Associate,
    Work,
    VotingPublication,
    Withdraw,
    Resign,
    Participate,
    SubmitProposal,
    SeeAmendments,
    SeeMembers,
    PublishAsProposal,
    SupportProposal,
    OpposeProposal,
    WithdrawToken,
    SeeRelatedIdeas,
    CompareProposal,
    MakeOpinion,
    DeleteProposal,
    close_votes,
    AMENDMENTS_CYCLE_DEFAULT_DURATION,
    VOTE_PUBLISHING_MESSAGE,
    VOTE_DURATION_MESSAGE,
    VOTE_REOPENING_MESSAGE,
    VOTE_MODEWORK_MESSAGE,
    publish_condition,
    AlertEnd,
    SeeWorkspace,
    AddFiles,
    RemoveFile,
    AttachFiles,
    calculate_improvement_cycle_duration
    )
from . import VP_DEFAULT_DURATION
from novaideo import _, log
from novaideo.content.ballot import Ballot


VOTE_PUBLISHING_GROUP = {
    'group_id': 'vote_submission',
    'group_title': _('Vote for continuing to improve the proposal or not'),
    'group_activate': True,
    'group_activator_title': _('Vote for submission'),
    'group_activator_class_css': 'vote-action',
    'group_activator_style_picto': 'glyphicon glyphicon-stats',
    'group_activator_order': 80
}


def firs_ale
rt(process, date):
    alert_date = datetime.timedelta(seconds=(date.total_seconds()/3) * 2) + \
        getattr(process, 'new_cycle_date', datetim
e.datetime.now())
    return alert_date


def second_alert(process, date):
    alert_date = datetime.timedelta(seconds=(date.total_seconds()/7) * 6) + \
        getattr(process, 'new_cycle_date', datetime.datetime.now())
    return alert_date


ALERTS = {0: firs_alert, 1: second_alert}


def alert_end_cycle_duration(process):
    alert = getattr(process, 'previous_alert', -1) + 1
    alert_op = ALERTS.get(alert, None)
    proposal = process.execution_context.created_entity('proposal')
    if alert_op and proposal:
        working_group = proposal.working_group
        date = getattr(
            working_group, 'work_duration', None)
        if not date:
            date = calculate_improvement_cycle_duration(process)

        alert_date = alert_op(process, date)
        log.warning(alert_date)
        return alert_date

    return datetime.datetime.now()


def has_alert_condition(process):
    alert = getattr(process, 'previous_alert', -1) + 1
    alert_op = ALERTS.get(alert, None)
    return True if alert_op else False


def amendable_condition(process):
    return not publish_condition(process)


class SubProcessFirstVote(OriginSubProcess):

    def __init__(self, definition):
        super(SubProcessFirstVote, self).__init__(definition)

    def _start_subprocess(self, action):
        proposal = self.process.execution_context.created_entity('proposal')
        working_group = proposal.working_group
        if not hasattr(working_group, 'first_vote'):
            working_group.first_vote = True
            return None
        else:
            working_group.first_vote = False
            return super(SubProcessFirstVote, self)._start_subprocess(action)

    def stop(self):
        request = get_current_request()
        for process in self.sub_processes:
            exec_ctx = process.execution_context
            vote_processes = exec_ctx.get_involved_collection('vote_processes')
            vote_processes = [process for process in vote_processes
                              if not process._finished]
            if vote_processes:
                close_votes(None, request, vote_processes)

            ballots = getattr(process, 'ballots', [])
            for ballot in ballots:
                ballot.finish_ballot()

        super(SubProcessFirstVote, self).stop()


class SubProcessDefinition(OriginSubProcessDefinition):
    """Run the voting process for proposal publishing
       and working group configuration"""

    factory = SubProcessFirstVote

    def _init_subprocess(self, process, subprocess):
        root = getSite()
        proposal = process.execution_context.created_entity('proposal')
        working_group = proposal.working_group
        work_mode = getattr(working_group, 'work_mode', None)
        participants_mini = work_mode.participants_mini if work_mode else root.participants_mini
        participants_maxi = work_mode.participants_maxi if work_mode else root.participants_maxi
        electors = working_group.members[:participants_mini]
        if not getattr(working_group, 'first_improvement_cycle', True):
            electors = working_group.members

        contexts = [proposal]
        ballot = Ballot('Referendum', electors, contexts, VP_DEFAULT_DURATION,
                        true_val=_("Submit the proposal as is"),
                        false_val=_("Continue to improve the proposal"),
                        group=VOTE_PUBLISHING_GROUP,
                        subjects=[proposal])
        working_group.addtoproperty('ballots', ballot)
        ballot.report.description = VOTE_PUBLISHING_MESSAGE
        ballot.title = _("Continue to improve the proposal or not")
        processes = ballot.run_ballot()
        subprocess.ballots = PersistentList()
        subprocess.ballots.append(ballot)
        working_group.vp_ballot = ballot #vp for voting for publishing
        root_modes = root.get_work_modes()
        modes = [(m, root_modes[m].title) for m in root_modes
                 if root_modes[m].participants_mini <= len(working_group.members)]
        if len(modes) > 1:
            modes = sorted(modes,
                           key=lambda e: root_modes[e[0]].order)
            group = [m[0] for m in modes]
            default_mode = working_group.work_mode.work_id
            if default_mode not in root_modes:
                default_mode = modes[0][0]

            ballot = Ballot('FPTP', electors, group, VP_DEFAULT_DURATION,
                            group_title=_('Work mode'),
                            group_values=modes,
                            group_default=default_mode,
                            group=VOTE_PUBLISHING_GROUP,
                            subjects=[proposal])
            working_group.addtoproperty('ballots', ballot)
            ballot.title = _('Work modes')
            ballot.report.description = VOTE_MODEWORK_MESSAGE
            processes.extend(ballot.run_ballot(context=proposal))
            subprocess.ballots.append(ballot)
            working_group.work_mode_configuration_ballot = ballot

        if not getattr(working_group, 'first_improvement_cycle', True) and \
           'closed' in working_group.state:
            contexts = [working_group]
            ballot = Ballot('Referendum', electors,
                            contexts, VP_DEFAULT_DURATION,
                            group=VOTE_PUBLISHING_GROUP,
                            subjects=[prop