////////////////////////////////////////////////////////////////////////////////
//
//  ADOBE SYSTEMS INCORPORATED
//  Copyright 2005-2008 Adobe Systems Incorporated
//  All Rights Reserved.
//
//  NOTICE: Adobe permits you to use, modify, and distribute this file
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////

package mx.states
{
    
import mx.binding.BindingManager;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.events.PropertyChangeEvent;
import mx.utils.OnDemandEventDispatcher;

/**
 *  The OverrideBase class is the base class for the 
 *  override classes used by view states. 
 *  
 *  @langversion 3.0
 *  @playerversion Flash 9
 *  @playerversion AIR 1.1
 *  @productversion Flex 3
 */
public class OverrideBase extends OnDemandEventDispatcher implements IOverride
{
    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------
    /**
     *  Constructor.
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public function OverrideBase() {}

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------
    
    /**
     *  @private
     *  Flag which tracks if we're actively overriding a property.
     */
    protected var applied:Boolean = false;
    
    /**
     *  @private
     *  Our most recent parent context.
     */
    protected var parentContext:UIComponent;
    
    /**
     *  @private
     */  
    private var targetProperty:String;
    
    /**
     *  @private
     *  Specifies whether or not a property-centric 
     *  state override's base value is data bound.
     *  
     *  This value is intended for use by the MXML 
     *  compiler only.
     */
    public var isBaseValueDataBound:Boolean;
    
    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------
    
    /**
     *  IOverride interface method; this class implements it as an empty method.
     * 
     *  @copy IOverride#initialize()
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public function initialize():void {}
    
    /**
     *  @inheritDoc
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public function apply(parent:UIComponent):void {}
    
    /**
     *  @inheritDoc
     *  
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public function remove(parent:UIComponent):void {}
    
    /**
     * @private 
     * Initialize this object from a descriptor.
     */
    public function initializeFromObject(properties:Object):Object
    {
        for (var p:String in properties)
        {
            this[p] = properties[p];
        }
        
        return Object(this);
    }
    
    /**
     * @private
     * @param parent The document level context for this override.
     * @param target The component level context for this override.
     */
    protected function getOverrideContext(target:Object, parent:UIComponent):Object
    {
        if (target == null)
            return parent;
    
        if (target is String)
            return parent[target];
    
        return target;
    }
 
    /**
     * @private
     * If the target of our override is a String (representing a property), 
     * we register a PROPERTY_CHANGE listener to determine when/if our target 
     * context becomes available or changes.  
     */ 
    protected function addContextListener(target:Object):void
    {
        if (target is String && parentContext != null)
        {
            targetProperty = target as String;
            parentContext.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
                context_propertyChangeHandler);
        }
    }
    
    /**
     * @private
     * Unregister our PROPERTY_CHANGE listener.
     */ 
    protected function removeContextListener():void
    {
        if (parentContext != null)
        {
            parentContext.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
                context_propertyChangeHandler);
        }
    }
    
    /**
     * @private
     * Called when our target context is set.  We re-apply our override
     * if appropriate.
     */
    protected function context_propertyChangeHandler(event:PropertyChangeEvent):void
    {
        if (event.property == targetProperty && event.newValue != null)
        {
            apply(parentContext);
            removeContextListener();
        }
    }
    
    /**
     * @private 
     * Disables or enables binding associated with a property override.
     */
    protected function enableBindings(target:Object, parent:UIComponent, property:String, enable:Boolean=true):void
    {
        if (isBaseValueDataBound && target && parent && property)
        {
            var document:Object = target.hasOwnProperty("document") ? target.document : null;
            document = !document && parent.hasOwnProperty("document") ? parent.document : document;
            
            var name:String = target.hasOwnProperty("id") ? target.id : null;
            name = !name && target.hasOwnProperty("name") ? target.name : name;
            
            if (document && name)
            {
                var root:String = (document == target) ? "this" : name;
                BindingManager.enableBindings(document, root + "." + property, enable);
            }
        }
    }
}

}