# -*- 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 extends AnArenaContentProvider to produce a list of channels that
#  is appropriate for the current user.  Since channels in arena are defined
#  in two places -- in the 'channels' data source category and by posts 
#  themselves -- this data must be amalgamated and pruned so that only those
#  channels for which the current user has permissions are displayed.

from Plugins.Content.PerUser.Arena.ContentProviders import \
    AnArenaContentProvider, AnArenaContentProviderError
from Library.String.Utilities import String
from Plugins.User.Subscriptions import Right, Rights
from Library.UI.Channels import chMetaItemsSeparator, \
    chMetaKeysValuesSeparator
    
from Local.Configuration import Site
    
## The query key that specifies which rights to match for the channel list
aclRightsQueryKey = "rights"
## The default rights to match if none are provided by the client
aclDefaultRights = Right.toRead
    
## A channel list producer
class AnArenaChannelsListing(AnArenaContentProvider):
    ## Fetch content
    def content(Self):
        # Determine which rights to match
        clientRights = Rights.unzip(aclDefaultRights)
        
        if aclRightsQueryKey in Self._Request:
            clientRights = Rights.unzip(Self._Request[aclRightsQueryKey].value)
        
        masterList = {}
        # After this call, 'postChannels' will contain a list of all channels
        # defined by posts, thanks to the 'onFetchContent' code snippet stored
        # in the data source for this channel.  Self._User will have loaded a
        # list of all channels to which the user has a subscription, thanks to
        # ASubscribedUser.fetch().  All we need to do is:
        #   1. Load the list of channels specified in the 'channels' data 
        #      source category and
        #   2. Add the channel names to the master list; then
        #   3. We can compare this list to the ones for which the user is
        #      subscribed, removing the ones for which they are not; and finally
        #   4. Return the filtered list
        postChannels = AnArenaContentProvider.content(Self)
        
        # Each 'postChannels' item is actually a comma-delimited string of
        # channels to which the post belongs; we need to break out that list
        for channelItem in postChannels:
            if channelItem is None:
                continue
                
            channels = String.explode(channelItem["channels"], list)
            
            for channel in channels:
                masterList[channel] = {
                    "path": channel,
                    "public": "y",
                    "icon": Site.icon["large"]
                }
        
        # 1. Fetch the list of channels specified in the 'channels' category
        definedChannels = Self._DataSource.fetch(Site.Channels.category,
            fields = ("channelName", "public", "meta")
        )
        
        # 2. Add the channel names to the master list
        for channel in definedChannels:
            channelIcon = Site.icon
            
            channelMeta = String.explode(channel["meta"], dict,
                chMetaItemsSeparator, chMetaKeysValuesSeparator)
        
            if "icon" in channelMeta:
                channelIcon = channelMeta["icon"]
                
            masterList[channel["channelName"]] = {
                "path": channel["channelName"],
                "public": channel["public"],
                "icon": channelIcon
            }
                        
        # Break out the channel hierarchy
        channels = masterList.keys()
        for channel in channels:
            # Ignore channels that start with a special character
            if channel[0].isalpha() == False:
                del masterList[channel]
                continue
                
            # 3. Compare the master list to the ones for which the user is 
            #    subscribed.                
            if Self._User.hasAnyOf(clientRights, channel) == "":
                public = masterList[channel]["public"]
                
                # If the user has no explicit rights granted for the specific
                # channel, then we allow for blanket subscriptions to all public
                # or private channels
                if len(Self._User.Subscriptions().rightsFor(channel)) == 0:
                    if public == "y":
                        if Self._User.hasAnyOf(clientRights, "$site/channels/public") == "":
                            del masterList[channel]
                    
                    else:
                        if Self._User.hasAnyOf(clientRights, "$site/channels/private") == "":
                            del masterList[channel]   
                
                # Otherwise, if explicit rights are granted for the channel, but
                # they are not the rights requested, then the channel will not
                # be listed
                else:
                    del masterList[channel]
        
        # 4. Return the filtered list
        return sorted(masterList.values())
