# -*- 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 AContentProvider to allow content to be retrieved from
#  a data source.

from Library.UI.ContentProviders import AContentProvider, \
    AContentProviderError
    
## The error message used when no data source is provided 
dcpNoDataSource = "failed to fetch content using {} because no data source " \
    "was provided"
## The error message used when no category name is provided
dcpNoCategory = "failed to fetch content from {} because no category name " \
    "was provided"
## The error message used when the data source raises an exception
dcpDataSourceError = "failed to fetch content from \"{}\" in {} because: {}"
    
## A content provider that retrieves content from a data source.
class ADataSourceContentProvider(AContentProvider):
    ## Constructor.
    #
    #  The constructor expects the following parameters will be provided
    #  in \p params:
    #  - \p DataSource -- The data source from which content will be 
    #                     retrieved.  This should be an instance of ADataSource
    #                     or its descendants.
    #  - \p category -- The name of the data source category (or table) from
    #                   which to draw content.
    #
    #  In addition to the above, \p params may also include any parameters that
    #  are accepted by ADataSource.fetch(); these will be passed to 
    #  ADataSource.fetch() when content is requested from the content provider.
    def __init__(Self, **params):
        AContentProvider.__init__(Self, **params)
        
        if "DataSource" in Self._params:
            Self._DataSource = Self._params["DataSource"]
            del Self._params["DataSource"]
            
        if "category" in Self._params:
            Self._category = Self._params["category"]
            del Self._params["category"]
            
    ## Initializer.
    def init(Self):
        result = AContentProvider.init(Self)
        
        if result:
            # Establish private attributes
            # The data source from which content will be retrieved
            Self._DataSource = None
            # The name of the category (or table) within the data source from
            # which content will be retrieved
            Self._category = None
            
        return result
        
    # Properties ---------------------------------------------------------------
    ## Retrieve the content from the content provider.
    #
    #  This method should be implemented by descendant classes.  It should
    #  return an iterable object that contains content which will be passed to
    #  a view for display.  If there is no content to display, an empty
    #  iterable object should be returned.
    #
    #  This method generates the \p fetchContent event.
    def content(Self):
        result = tuple()
        
        Event = Self.generate("fetchContent")
        if Event.handled():
            result = Event.result()
            del Event
            return result
            
        del Event
        
        if Self._DataSource is None:
            Self.error(AContentProviderError(dcpNoDataSource,
                Self.displayName()))
                
        if Self._category is None:
            Self.error(AContentProviderError(dcpNoCategoryName,
                Self._DataSource.displayName()))
                
        # Fetch the content
        try:
            result = Self._DataSource.fetch(Self._category, **Self._params)
            
        except Exception, Err:
            Self.error(AContentProviderError(dcpDataSourceError,
                Self._category, Self._DataSource.displayName(),
                str(Err)))
        
        return result
