#-------------------------------------------------------------------------------
#  
#  Defines the TemplateDataName class used for binding a data source to a data
#  context.
#  
#  Written by: David C. Morrill
#  
#  Date: 07/27/2007
#  
#  (c) Copyright 2007 by Enthought, Inc.
#  
#-------------------------------------------------------------------------------

""" Defines the TemplateDataName class used for binding a data source to a data
    context.
"""

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

from enthought.traits.api \
    import HasPrivateTraits, Instance, Bool, Property, Undefined, \
           on_trait_change, cached_property
    
from itemplate_data_name_item \
    import ITemplateDataNameItem
    
from itemplate_data_context \
    import ITemplateDataContext
    
from template_impl \
    import Template
    
from template_traits \
    import TList, TStr, TBool
    
#-------------------------------------------------------------------------------
#  'TemplateDataName' interface:
#-------------------------------------------------------------------------------

class TemplateDataName ( Template ):
    """ Defines the TemplateDataName class used for binding a data source to a
        data context.
    """
    
    #-- Public Template Traits -------------------------------------------------
    
    # The list of ITemplateDataNameItem's used to match the data context:
    items = TList( ITemplateDataNameItem )
    
    # A description of the template data name (for use in a user interface):
    description = TStr
    
    # Is this binding optional?
    optional = TBool( False )

    #-- Public Non-Template Traits ---------------------------------------------
    
    # The data context the template name is matching against currently:
    context = Instance( ITemplateDataContext )
    
    # Is the binding resolved?
    resolved = Property( Bool, depends_on = 'items.output_data_context' )
    
    # The actual name of the context data that the data source is bound to:
    context_data_name = Property
    
    # The context data the data source is bound to:
    context_data = Property
    
    #-- Property Implementations -----------------------------------------------
    
    @cached_property
    def _get_resolved ( self ):
        if len( self.items ) == 0:
            return False
            
        context = self.items[-1].output_data_context
        return ((context is not None) and
                (len( context.data_context_values ) == 1) and
                (len( context.data_contexts ) == 0))
        
    def _get_context_data_name ( self ):
        if self.resolved:
            context = self.items[-1].output_data_context
            path    = context.data_context_path
            if path != '':
                path += '.'
            name = context.data_context_name
            if name != '':
                name += '.'
                
            return '%s%s%s' % ( path, name, context.data_context_values[0] )
        
        return ''
        
    def _get_context_data ( self ):
        if self.resolved:
            context = self.items[-1].output_data_context
            return context.get_data_context_value( 
                       context.data_context_values[0] )
            
        return Undefined
        
    #-- Trait Event Handlers ---------------------------------------------------
    
    def _context_changed ( self, context ):
        """ Resets the name whenever the context is changed.
        """
        self._reset()
            
    @on_trait_change( ' items' )
    def _on_items_changed ( self ):
        """ Resets the name whenever any of the name items are changed.
        """
        self._reset()
        
    @on_trait_change( 'items:output_data_context' )
    def _on_output_data_context_changed ( self, item, name, old, new ):
        i = self.items.index( item )
        if i < (len( self.items ) - 1):
            self.items[ i + 1 ].input_data_context = new
            
    #-- Private Methods --------------------------------------------------------
    
    def _reset ( self ):
        """ Resets the name whenever any significant change occurs.
        """
        items = self.items
        n     = len( items )
        if n > 0:
            items[0].input_data_context = self.context
            for i in range( 0, n - 1 ):
                items[ i + 1 ].input_data_context = \
                    items[ i ].output_data_context    
        
