////////////////////////////////////////////////////////////////////////////////
//
//  ADOBE SYSTEMS INCORPORATED
//  Copyright 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 spark.components
{

import mx.core.IVisualElement;
import mx.core.UIComponentGlobals;
import mx.core.mx_internal;

import spark.components.supportClasses.DropDownListBase;
import spark.core.IDisplayText;
import spark.components.supportClasses.TextBase;
import spark.utils.LabelUtil;
    
use namespace mx_internal;

//--------------------------------------
//  Other metadata
//--------------------------------------

[IconFile("DropDownList.png")]

/**
 * Because this component does not define a skin for the mobile theme, Adobe
 * recommends that you not use it in a mobile application. Alternatively, you
 * can define your own mobile skin for the component. For more information,
 * see <a href="http://help.adobe.com/en_US/flex/mobileapps/WS19f279b149e7481c698e85712b3011fe73-8000.html">Basics of mobile skinning</a>.
 */
[DiscouragedForProfile("mobileDevice")]

/**
 *  The DropDownList control contains a drop-down list
 *  from which the user can select a single value.
 *  Its functionality is very similar to that of the
 *  SELECT form element in HTML.
 *
 *  <p>The DropDownList control consists of the anchor button, 
 *  prompt area, and drop-down-list, 
 *  Use the anchor button to open and close the drop-down-list. 
 *  The prompt area displays a prompt String, or the selected item 
 *  in the drop-down-list.</p>
 *
 *  <p>When the drop-down list is open:</p>
 *  <ul>
 *    <li>Clicking the anchor button closes the drop-down list 
 *      and commits the currently selected data item.</li>
 *    <li>Clicking outside of the drop-down list closes the drop-down list 
 *      and commits the currently selected data item.</li>
 *    <li>Clicking on a data item selects that item and closes the drop-down list.</li>
 *    <li>If the <code>requireSelection</code> property is <code>false</code>, 
 *      clicking on a data item while pressing the Control key deselects 
 *      the item and closes the drop-down list.</li>
 *  </ul>
 *
 *  <p><b>Note: </b>The Spark list-based controls (the Spark ListBase class and its subclasses
 *  such as ButtonBar, ComboBox, DropDownList, List, and TabBar) do not support the BasicLayout class
 *  as the value of the <code>layout</code> property. 
 *  Do not use BasicLayout with the Spark list-based controls.</p>
 *
 *  <p>To use this component in a list-based component, such as a List or DataGrid, 
 *  create an item renderer.
 *  For information about creating an item renderer, see 
 *  <a href="http://help.adobe.com/en_US/flex/using/WS4bebcd66a74275c3-fc6548e124e49b51c4-8000.html">
 *  Custom Spark item renderers</a>. </p>
 *  
 *  <p>The DropDownList control has the following default characteristics:</p>
 *  <table class="innertable">
 *     <tr><th>Characteristic</th><th>Description</th></tr>
 *     <tr><td>Default size</td><td>112 pixels wide and 21 pixels high</td></tr>
 *     <tr><td>Minimum size</td><td>112 pixels wide and 21 pixels high</td></tr>
 *     <tr><td>Maximum size</td><td>10000 pixels wide and 10000 pixels high</td></tr>
 *     <tr><td>Default skin class</td><td>spark.skins.spark.DropDownListSkin</td></tr>
 *  </table>
 *
 *  @mxml <p>The <code>&lt;s:DropDownList&gt;</code> tag inherits all of the tag 
 *  attributes of its superclass and adds the following tag attributes:</p>
 *
 *  <pre>
 *  &lt;s:DropDownList 
 *    <strong>Properties</strong>
 *    prompt=""
 *    typicalItem="null"
 * 
 *    <strong>Events</strong>
 *    closed="<i>No default</i>"
 *    open="<i>No default</i>"
 *  /&gt;
 *  </pre>
 *
 *  @see spark.skins.spark.DropDownListSkin
 *  @see spark.components.supportClasses.DropDownController
 *
 *  @includeExample examples/DropDownListExample.mxml
 *  
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 1.5
 *  @productversion Flex 4
 */
public class DropDownList extends DropDownListBase
{
    include "../core/Version.as";
    
    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor. 
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
    public function DropDownList()
    {
        super();
    }
    
    //--------------------------------------------------------------------------
    //
    //  Skin parts
    //
    //--------------------------------------------------------------------------    
    
    //----------------------------------
    //  labelDisplay
    //----------------------------------

    [SkinPart(required="false")]

    /**
     *  An optional skin part that holds the prompt or the text of the selected item. 
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
    public var labelDisplay:IDisplayText;
       
    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    private var labelChanged:Boolean = false;
    private var labelDisplayExplicitWidth:Number; 
    private var labelDisplayExplicitHeight:Number; 
    private var sizeSetByTypicalItem:Boolean;
    
    //--------------------------------------------------------------------------
    //
    //  Overridden properties
    //
    //--------------------------------------------------------------------------

    //----------------------------------
    //  baselinePosition
    //----------------------------------
    
    /**
     *  @private
     */
    override public function get baselinePosition():Number
    {
        return getBaselinePositionForPart(labelDisplay as IVisualElement);
    }

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------
    
    //----------------------------------
    //  prompt
    //----------------------------------

    /**
     *  @private
     */
    private var _prompt:String = "";

    [Inspectable(category="General", defaultValue="")]
    
    /**
     *  The prompt for the DropDownList control. 
     *  The prompt is a String that is displayed in the
     *  DropDownList when <code>selectedIndex</code> = -1.  
     *  It is usually a String such as "Select one...". 
     *  Selecting an item in the drop-down list replaces the 
     *  prompt with the text from the selected item.
     *  
     *  @default ""
     *       
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
    public function get prompt():String
    {
        return _prompt;
    }

    /**
     *  @private
     */
    public function set prompt(value:String):void
    {
        if (_prompt == value)
            return;
            
        _prompt = value;
        labelChanged = true;
        invalidateProperties();
    }
    
    //--------------------------------------------------------------------------
    //
    //  Overridden Properties
    //
    //--------------------------------------------------------------------------
    
    [Inspectable(category="Data")]
    
    /**
     *  Layouts use the preferred size of the <code>typicalItem</code>
     *  when fixed row or column sizes are required, but a specific 
     *  <code>rowHeight</code> or <code>columnWidth</code> value is not set.
     *  Similarly virtual layouts use this item to define the size 
     *  of layout elements that have not been scrolled into view.
     *
     *  <p>The container  uses the typical data item, and the associated item renderer, 
     *  to determine the default size of the container children. 
     *  By defining the typical item, the container does not have to size each child 
     *  as it is drawn on the screen.</p>
     *
     *  <p>Setting this property sets the <code>typicalLayoutElement</code> property
     *  of the layout.</p>
     * 
     *  <p>Restriction: if the <code>typicalItem</code> is an IVisualItem, it must not 
     *  also be a member of the data provider.</p>
     * 
     *  <p>Note: Setting <code>typicalItem</code> overrides any explicit width or height
     *  set on the <code>labelDisplay</code> skin part. </p>
     * 
     *  @default null
     *  
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
    override public function set typicalItem(value:Object):void
    {
        super.typicalItem = value;
        invalidateSize();
    }
    
    //--------------------------------------------------------------------------
    //
    //  Overridden methods
    //
    //--------------------------------------------------------------------------
    
    /**
     *  @private
     */ 
    override protected function commitProperties():void
    {
        super.commitProperties();
        
        if (labelChanged)
        {
            labelChanged = false;
            updateLabelDisplay();
        }
    }
    
    /**
     *  @private
     */ 
    override protected function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);
        
        if (instance == labelDisplay)
        {
            labelChanged = true;
            invalidateProperties();
        }
    }
    
    /**
     *  @private
     */
    override protected function measure():void
    {
        var labelComp:TextBase = labelDisplay as TextBase;
        
        // If typicalItem is set, then use it for measurement
        if (labelComp && typicalItem != null)
        {   
            // Save the labelDisplay's dimensions in case we clear out typicalItem
            if (!sizeSetByTypicalItem)
            {
                labelDisplayExplicitWidth = labelComp.explicitWidth;
                labelDisplayExplicitHeight = labelComp.explicitHeight;
                sizeSetByTypicalItem = true;
            }
            
            labelComp.explicitWidth = NaN;
            labelComp.explicitHeight = NaN;
            
            // Swap in the typicalItem into the labelDisplay
            updateLabelDisplay(typicalItem);
            UIComponentGlobals.layoutManager.validateClient(skin, true);
            
            // Force the labelDisplay to be sized to the measured size
            labelComp.width = labelComp.measuredWidth;
            labelComp.height = labelComp.measuredHeight;
            
            // Set the labelDisplay back to selectedItem
            updateLabelDisplay();
        }
        else if (labelComp && sizeSetByTypicalItem && typicalItem == null)
        {
            // Restore the labelDisplay to its original size
            labelComp.width = labelDisplayExplicitWidth;
            labelComp.height = labelDisplayExplicitHeight;
            sizeSetByTypicalItem = false;
        }
        
        super.measure();
    }
    
    /**
     *  @private
     *  Called whenever we need to update the text passed to the labelDisplay skin part
     */
    // TODO (jszeto): Make this protected and make the name more generic (passing data to skin) 
    override mx_internal function updateLabelDisplay(displayItem:* = undefined):void
    {
        if (labelDisplay)
        {
            if (displayItem == undefined)
                displayItem = selectedItem;
            if (displayItem != null && displayItem != undefined)
                labelDisplay.text = LabelUtil.itemToLabel(displayItem, labelField, labelFunction);
            else
                labelDisplay.text = prompt;
        }   
    }
 
}

}
