# -*- coding: utf-8 -*-
##
##
## This file is part of Indico.
## Copyright (C) 2002 - 2014 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/>.

"""
Schedule-related services
"""

from MaKaC.services.interface.rpc.common import ServiceError, ServiceAccessError,NoReportError
from MaKaC.services.implementation.base import \
     ParameterManager, ProtectedModificationService, ProtectedDisplayService

import MaKaC.webinterface.locators as locators
from MaKaC.errors import ModificationError

import MaKaC.conference as conference
from MaKaC.user import AvatarHolder, GroupHolder
from MaKaC.common.fossilize import fossilize
from MaKaC.fossils.conference import IMaterialFossil,\
        ILinkFossil, ILocalFileFossil, ILocalFileExtendedFossil
from MaKaC.common.PickleJar import DictPickler
from MaKaC.webinterface.rh.contribMod import RCContributionPaperReviewingStaff


class UserListChange(object):

    def changeUserList(self, object, newList):
        # clone the list, to avoid problems
        allowedUsers = object.getAllowedToAccessList()[:]

        # user can be a user or group
        for user in allowedUsers:
            if not user.getId() in newList:
                object.revokeAccess(user)
            else:
                del newList[user.getId()]

        for elem in newList:
            # TODO: Change this, when DictPickler goes away
            if ('isGroup' in elem and elem['isGroup']) or \
                   ('_fossil' in elem and elem['_fossil'] == 'group'):
                avatar = GroupHolder().getById(elem['id'])
            else:
                avatar = AvatarHolder().getById(elem['id'])
            object.grantAccess(avatar)


class MaterialBase:

    def _checkParams( self ):
        try:
            l = locators.WebLocator()

            self._material = None
            self._conf = None

            l.setMaterial( self._params, 0 )
            self._target = l.getObject()


            #if isinstance(self._target, conference.Material):
            self._material = self._target
            self._conf = self._target.getConference()
            if self._conf == None:
                self._categ = self._target
            else:
                self._categ = self._conf.getOwner()

            ## TODO: remove this, since material/resource creation
            ## doesn't come through this method

            ## if isinstance(self._target, conference.Category):
            ##     self._categ = self._target
            ## else:
            ##     self._conf = self._target.getConference()

            ## if self._conf == None:
            ##     self._categ=self._target.getCategory()


        except Exception, e:
            if self._target is None:
                raise NoReportError(_("The material with does not exist anymore. Please refresh the page."))
            else:
                raise ServiceError("ERR-M0", str(e))

class MaterialDisplayBase(ProtectedDisplayService, MaterialBase):

    def _checkParams(self):
        MaterialBase._checkParams(self)
        ProtectedDisplayService._checkParams(self)

class MaterialModifBase(MaterialBase, ProtectedModificationService):

    def _checkParams(self):
        MaterialBase._checkParams(self)
        ProtectedModificationService._checkParams(self)

    def _checkProtection(self):
        owner = self._material.getOwner()

        # Conference submitters have access
        if isinstance(owner, conference.Conference) and owner.getAccessController().canUserSubmit(self._aw.getUser()):
            return

        # There are two exceptions to the normal permission scheme:
        # (sub-)contribution submitters and session coordinators

        # in case the owner is a (sub-)contribution, we should
        # allow submitters
        if isinstance(owner, conference.Contribution) or \
           isinstance(owner, conference.SubContribution):

            reviewingState = self._material.getReviewingState()

            if (reviewingState < 3 and # it means the papers has not been submitted yet (or not reviewing material)
                owner.canUserSubmit(self._aw.getUser())):
                # Submitters have access
                return
            # status = 3 means the paper is under review (submitted but not reviewed)
            # status = 2 means that the author has not yet submitted the material
            elif isinstance(owner, conference.Contribution) and RCContributionPaperReviewingSta
ff.hasRights(self, contribution = owner, includingContentReviewer=False) and reviewingState in [2,
 3]:
                return
            elif owner.getSession() and \
                     owner.getSession().canCoordinate(self._aw, "modifContribs"):
                # Coordinators of the parent session have access
                return

        # if it's associated with a session, coordinators
        # should be allowed
        elif self._material.getSession() != None and \
            self._material.getSession().canCoordinate(self._aw):
            # Session coordinators have access
            return

        try:
            ProtectedModificationService._checkProtection(self)
        except ModificationError:
            raise ServiceAccessError(_("you are not authorised to manage material "
                                       "for this contribution"))
class ResourceBase:
    """
    Base class for material resource access
    """

    def _checkParams(self):
        """
        Checks the materialId, and retrieves the material using it
        """

        self._material = None
        self._conf = None

        l = locators.WebLocator()

        try:

            l.setResource( self._params, 0 )
            self._target = l.getObject()

            if isinstance(self._target, conference.Resource):
                self._resource = self._target
                self._material = self._target.getOwner()

            if isinstance(self._target, conference.Material):
                self._material = self._target

            if isinstance(self._target, conference.Category):
                self._categ = self._target
            else:
                self._conf = self._target.getConference()

            if self._conf == None:
                self._categ=self._target.getCategory()

        except Exception, e:
            if self._target is None:
                raise NoReportError(_("The resource with does not exist anymore. Please refresh the page."))

            else:
                raise ServiceError("ERR-M0", str(e))


class ResourceDisplayBase(ProtectedDisplayService, ResourceBase):

    def _checkProtection(self):
        ProtectedDisplayService._checkParams(self)

    def _checkParams(self):
        ResourceBase._checkParams(self)
        ProtectedDisplayService._checkParams(self)

class ResourceModifBase(ResourceBase, MaterialModifBase):

    def _checkParams(self):
        ResourceBase._checkParams(self)


class GetMaterialClassesBase(MaterialDisplayBase):
    """
    Base class for obtaining a listing of material classes
    """

    def _checkParams( self ):
        l = locators.WebLocator()

        l.setMaterial( self._params, 0 )
        self._target = l.getObject()


    def _getAnswer(self):
        """
        Provides the list of material classes, based on the target
        resource (conference, session, contribution, etc...)
        """
        matList = {}

        for mat in self._target.getAllMaterialList():
            matList[mat.getId()] = mat.fossilize(IMaterialFossil)

        return matList

class GetReviewingMaterial(GetMateri