# This file is part of Indico.
# Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

import tempfile
from copy import copy
from datetime import datetime

import BTrees.OIBTree as OIBTree
from BTrees.IOBTree import IOBTree
from BTrees.OOBTree import OOBTree, intersection, union
from persistent import Persistent
from persistent.list import PersistentList
from pytz import timezone

from indico.core.config import Config
from indico.modules.events.abstracts.legacy import (contribution_from_abstract,
                                                    AbstractFieldM
anagerAdapter,
                                                    AbstractJudgmentLegacyMixin,
                                                    AbstractLegacyMixin,
              
                                      AbstractManagerLegacyMixin,
                                                    AbstractStatusAcceptedLegacyMixin)
from indico.modules.events.contributions.models.types import ContributionType
from indico.util.string import safe_slice, safe_upper

from MaKaC.common.Counter import Counter
from MaKaC.common.timezoneUtils import nowutc
from MaKaC.errors import MaKaCError, NoReportError
from MaKaC.i18n import _
from MaKaC.trashCan import TrashCanManager


class _AbstractParticipationIndex(Persistent):
    """This class allows to index abstract participations (submitters)
        for a single CFA process; this means that clients will be able to
        efficiently perform queries of the type "give me all the abstracts
        in which a certain registered user is implied".
       For being able to perform this indexing, it is supposed that the Avatar
        identifier is unique among other avatars and that it cannot change.
       This index must be maintained by clients (i.e. the CFAMgr) as it doesn't
        keep track of the changes on Participantons.
       The key of the index is the Avatar and the values the different
        Participations that user has within the current CFA process. For
        performance reasons, the Avatar id will be used as index key (using the
        whole Avatar object would make the index bigger and as the Avatar id
        cannot change it's enough); the clients would have to keep the
        integrity of the index.
    """

    def __init__(self):
        self._idx = OOBTree()

    def index(self, participation):
        """Add a new participation to the index
        """
        #if the Participation is not linked to an Avatar there's no point to
        #   index it
        a = participation.getAvatar()
        if not a:
            return
        #ToDo: if the Participation corresponds to an abstract which doesn't
        #   correspond to the current CFAMgr, then an error must be raised

        if not self._idx.has_key(a.getId()):
            self._idx[a.getId()] = PersistentList()
        #if the participation is already in the index, no need for adding it
        if participation in self._idx[a.getId()]:
            return
        self._idx[a.getId()].append(participation)

    def unindex(self, participation):
        """Remove an existing participation from the index
        """
        #if the Participation is not linked to an Avatar there's no point to
        #   unindex it
        a = participation.getAvatar()

        if not a:
            return
        #if the Avatar associated to the participation isn't in the index do
        #   nothing
        if not self._idx.has_key(a.getId()):
            return
        #if the given participation is indexed remove it, otherwise do nothing
        if participation in self._idx[a.getId()]:
            self._idx[a.getId()].remove(participation)

    def getParticipationList(self, av):
        try:
            return self._idx[av.getId()]
        except KeyError, e:
            return []


class AbstractParticipation(Persistent):

    def __init__(self, abstract, **data):
        self._abstract = abstract
        self._firstName = ""
        self._surName = ""
        self._email = ""
        self._affilliation = ""
        self._address = ""
        self._telephone = ""
        self._fax = ""
        self._title = ""
        self.setData(**data)

    def setFromAvatar(self, av):
        data = {"title": av.getTitle(),
                "firstName": av.getName(),
                "surName": av.getSurName(),
                "email": av.getEmail(),
                "affiliation": av.getOrganisation(),
                "address": av.getAddress(),
                "telephone": av.getTelephone(),
                "fax": av.getFax()}
        self.setData(**data)

    def setFromAbstractParticipation(self, part):
        data = {"title": part.getTitle(),
                "firstName": part.getFirstName(),
                "surName": part.getSurName(),
                "email": part.getEmail(),
                "affiliation": part.getAffiliation(),
                "address": part.getAddress(),
                "telephone": part.getTelephone(),
                "fax": part.getFax()}
        self.setData(**data)

    def setData(self, **data):
        if "firstName" in data:
            self.setFirstName(data["firstName"])
        if "surName" in data:
            self.setSurName(data["surName"])
        if "email" in data:
            self.setEmail(data["email"])
        if "affiliation" in data:
            self.setAffiliation(data["affiliation"])
        if "address" in data:
            self.setAddress(data["address"])
        if "telephone" in data:
            self.setTelephone(data["telephone"])
        if "fax" in data:
            self.setFax(data["fax"])
        if "title" in data:
            self.setTitle(data["title"])
    setValues = setData

    def getData(self):
        data = {}
        data["firstName"] = self.getFirstName()
        data["surName"] = self.getSurName()
        data["email"] = self.getEmail()
        data["affiliation"] = self.getAffiliation()
        data["address"] = self.getAddress()
        data["telephone"] = self.getTelephone()
        data["fax"] = self.getFax()
        data["title"] = self.getTitle()

        return data
    getValues = getData

    def clone(self, abstract):
        ap = AbstractParticipation(abstract, self.getData())
        return ap

    def _notifyModification(self):
        self._abstract._notifyModification()

    def _unindex(self):
        abs = self.getAbstract()
        if abs is not None:
            mgr = abs.getOwner()
            if mgr is not None:
                mgr.unindexAuthor(self)

    def _index(self):
        abs = self.getAbstract()
        if abs is not None:
            mgr = abs.getOwner()
            if mgr is not None:
                mgr.indexAuthor(self)

    def setFirstName(self, name):
        tmp = name.strip()
        if tmp == self.getFirstName():
            return
        self._unindex()
        self._firstName = tmp
        self._index()
        self._notifyModification()

    def getFirstName(self):
        return self._firstName

    def getName(self):
        return self._firstName

    def setSurName(self, name):
        tmp = name.strip()
        if tmp == self.getSurName():
            return
        self._unindex()
        self._surName = tmp
        self._index()
        self._notifyModification()

    def getSurName(self):
        return self._surName

    def getFamilyName(self):
        return self._surName

    def setEmail(self, email):
        email = email.strip().lower()
        if email != self.getEmail():
            self._unindex()
            