#-------------------------------------------------------------------------------
#  
#  An abstract base class implementation of the ITemplateDataNameItem interface
#  that looks for specified sub-contexts in its input context and if one match
#  is found, outputs that context; otherwise if more than one match is found it
#  outputs a context containing all matching sub-contexts found.
#  
#  Written by: David C. Morrill
#  
#  Date: 07/29/2007
#  
#  (c) Copyright 2007 by Enthought, Inc.
#  
#-------------------------------------------------------------------------------

""" An abstract base class implementation of the ITemplateDataNameItem interface
    that looks for specified sub-contexts in its input context and if one match
    is found, outputs that context; otherwise if more than one match is found it
    outputs a context containing all matching sub-contexts found.
"""

#-------------------------------------------------------------------------------
#  Imports:
#-------------------------------------------------------------------------------

from enthought.traits.api \
    import HasPrivateTraits, Instance, Property, implements, on_trait_change
    
from enthought.template.itemplate_data_context \
    import ITemplateDataContext
    
from enthought.template.itemplate_data_name_item \
    import ITemplateDataNameItem
    
from enthought.template.template_impl \
    import Template
    
from template_data_context \
    import TemplateDataContext
    
#-------------------------------------------------------------------------------
#  'AnyContextDataNameItem' class:
#-------------------------------------------------------------------------------

class AnyContextDataNameItem ( Template ):
    """ An abstract base class implementation of the ITemplateDataNameItem 
        interface that looks for specified sub-contexts in its input context
        and if one match is found, outputs that context; otherwise if more than
        one match is found it outputs a context containing all matching 
        sub-contexts found.
    """
    
    implements ( ITemplateDataNameItem )
    
    #-- 'ITemplateDataNameItem' Interface Implementation -----------------------
    
    # The data context which this data name item should match against:
    input_data_context = Instance( ITemplateDataContext )
    
    # The data context containing the data values and/or contexts this data
    # name item matches:
    output_data_context = Instance( ITemplateDataContext )
    
    # The ITemplateChoice instance representing the current settings of the
    # data name item. This value must be read/write, and must be overridden by
    # sublasses.
    data_name_item_choice = Property
    
    # The alternative choices the user has for the data name item settings for
    # the current input data context. The list may be empty, in which case the
    # user cannot change the settings of the data name item. This value can be
    # read only, and must be overridden by subclasses. 
    data_name_item_choices = Property
    
    #-- Private Traits ---------------------------------------------------------
        
    # The current input data context:
    current_input_data_context = Property

    #-- Partially Abstract Methods (Can be overridden in subclasses) -----------
    
    def filter ( self, name, context ):
        """ Returns **True** if the specified *context* called *name* should be
            included in the output context; and **False** otherwise.
        """
        return False
        
    #-- Property Implementations -----------------------------------------------

    def _get_data_name_item_choice ( self ):
        raise NotImplementedError
        
    def _set_data_name_item_choice ( self, value ):
        raise NotImplementedError
        
    def _get_data_name_item_choices ( self ):
        raise NotImplementedError        
        
    def _get_current_input_data_context ( self ):
        return self.input_data_context        
    
    #-- Trait Event Handlers ---------------------------------------------------
    
    def _input_data_context_changed ( self ):
        """ Handles the 'input_data_context' trait being changed. 
        """
        self.inputs_changed()
        
    #-- Private Methods --------------------------------------------------------
    
    def inputs_changed ( self ):
        """ Handles any of the input values being changed. May be called by
            subclasses.
        """
        output_context = None
        input_context  = self.input_data_context
        if input_context is not None:
            contexts = {}
                    
            # Process each name/context in the input data contexts, and only add
            # those that match the subclass's filter to the output context:
            filter = self.filter
            gdc    = input_context.get_data_context
            for name in input_context.data_contexts:
                if filter( name, gdc( name ) ):
                    contexts[ name ] = context
                    
            # If the result set is not empty, create an output context for it:
            n = len( contexts )
            if n == 1:
                output_context = values.values()[0]
            elif n > 1:
                output_context = TemplateDataContext(
                    data_context_path = input_context.data_context_path,
                    data_context_name = input_context.data_context_name,
                    contexts          = contexts )
          
        # Set the new output context:
        self.output_data_context = output_context
        
