# -*- coding: UTF-8 -*-
#    This file is part of arena.
#
#    arena 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.
#
#    arena is distributed in the hope that it will be useful, but
#    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABLITY
#    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 arena.  If not, see <http://www.gnu.org/licenses/>.

## @file
#  This file defines a class to manage a user that is part of one or more
#  groups which are subscribed to a particular channel.

from Plugins.User.GroupedUsers import AGroupedUser
from Plugins.User.Subscriptions import Right, Rights, ASubscriptionError, \
    ASubscriptionList
import sys

## The events generated by ASubscribedUser
suEvents = {
    ## Before user subscriptions are retrieved
    "getSubscriptions": None
}

## The error message used when failing to resolve group membership for a user
suErrorResolvingGroups = "failed to resolve group membership for user \"{}\""
## The error message used when failing to resolve subscription information
suErrorResolvingSubscriptions = "failed to resolve subscription information " \
    "for user \"{}\""
## The error message used when failing to retrieve subscription information for
#  the user
suErrorRetrievingSubscriptions = ("failed to retrieve subscriptions for user "
                                 "\"{}\" because: {}")

## This class represents a user that belongs to one or more groups, which are
#  in turn subscribed to one or more channels.
class ASubscribedUser(AGroupedUser):
    ## Constructor.
    #
    #  In addition to the paremters expected by AGroupedUser.__init__(), this
    #  routine expects that \p params will contain the following items:
    #  - \p subscriptionsCategory -- The name of the category (or table) in
    #                                the data source that stores group
    #                                channel subscriptions.
    def __init__(Self, fieldsValues=None, **params):
        AGroupedUser.__init__(Self, fieldsValues, **params)
        
        if "subscriptionsCategory" in Self._params:
            Self._subscriptionsCategory = Self._params["subscriptionsCategory"]
            del Self._params["subscriptionsCategory"]
            
    ## Initializer
    def init(Self):
        result = AGroupedUser.init(Self)

        if result == True:
            # Establish private attributes
            # The channels to which the user should be subscribed
            Self._channels = []
            # The name of the category that will be searched for subscription
            # information
            Self._subscriptionsCategory = ""
            # The subscription that allows the user to access the channel
            Self._Subscriptions = None
            
            # Update the events generated by the class
            Self._events.update(suEvents)

        return result
        
    ## Destructor
    def __del__(Self):
        if Self._Subscriptions is not None:
            del Self._Subscriptions
            
        AGroupedUser.__del__(Self)

    ## Retrieve the user's subscriptions for the specified channels.
    def getSubscriptionsFor(Self, userName=None):
        Subscriptions = None
        
        Event = Self.generate("getSubscriptions", userName=userName)
        if Event.handled():
            Subscriptions = Event.result()
            del Event
            return Subscriptions
            
        del Event
        
        if userName is None:
            userName = Self["userName"]
        
        try:
            # Get the list of groups to which the user belongs
            groupList = Self._Source.fetch(Self._groupCategory,
                criteria = [
                    ("{field:userName} = {}", userName)
                ]
            )
                
            groups = []
            for group in groupList:
                groups.append(group["groupName"])
                    
            else:
                if len(groups) == 0:
                    Self.error(ASubscriptionError(suErrorResolvingGroups,
                        userName))
                
            Subscriptions = ASubscriptionList(
                DataSource = Self._Source,
                category = Self._subscriptionsCategory
            )

            Subscriptions.fetch(groups)
                    
        except Exception, Err:
            Self.error(ASubscriptionError(suErrorRetrievingSubscriptions,
                userName, str(Err)))
                         
        return Subscriptions

    ## Fetch the user from the data source.
    def fetch(Self, userName):
        # Fetch the user information
        AGroupedUser.fetch(Self, userName)
        
        # Fetch the subscription that allows the user to access the specified
        # channels
        Self._Subscriptions = Self.getSubscriptionsFor(userName)
        
    ## Determine whether or not the user has the specified access right for the
    #  specified channel.
    def has(Self, thisRight, thisChannel):
        return Self._Subscriptions.has(thisRight, thisChannel)
        
    ## Determine whether or not the user has any of the specified access rights
    #  for the specified channel.
    def hasAnyOf(Self, theseRights, thisChannel):
        return Self._Subscriptions.hasAnyOf(theseRights, thisChannel)

    # Properties ---------------------------------------------------------------
    ## Retrieve the name of the category used to search for subscription
    #  information.
    def subscriptionsCategory(Self):
        return Self._subscriptionsCategory
        
    ## Retrieve all subscriptions for the user. 
    def Subscriptions(Self):
        return Self._Subscriptions

    ## Return the subscription that allows the user to access the specified 
    #  channel.
    def subscriptionFor(Self, thisChannel):
        return Self._Subscriptions[thisChannel]

