/// <reference path="../June_2_0.js" />


/*==================================================================================
    Copyright (c) 2008 Costin Trifan                        http://www.june-js.com/ 
                                                                                    
    Permission is hereby granted, free of charge, to any person obtaining a copy    
    of this software and associated documentation files (the "Software"), to deal   
    in the Software without restriction, including without limitation the rights    
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell       
    copies of the Software, and to permit persons to whom the Software is           
    furnished to do so, subject to the following conditions:                        
                                                                                    
    The above copyright notice and this permission notice shall be included in      
    all copies or substantial portions of the Software.                             
                                                                                    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR      
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,        
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE     
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER          
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,   
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN       
    THE SOFTWARE.                                                                   
                                                                                    
==================================================================================*/

/*==============================================================
        Widget: DROPDOWNLIST                                    
        Package: JUNE FRAMEWORK                                 
        Package version: 2.0                                    
        Last Edited: Sept 17, 2008                              
==============================================================*/

if ( !JUNE.Browser.isFirefox() )
{
	JUNE.getScriptPath = function (scriptRef)
	{
		var  head = JUNE.Dom.getByTags('head')[0]
			,scripts = JUNE.Dom.getByTags('script', head)
			,path = '';
	
		for (var s=0; s < scripts.length; s++)
		{
			var script = scripts[s];
			path = script.getAttribute('src');
			if (path)
			{
				if (path.indexOf(scriptRef) >= 0)
				{
					path = path.substr(0, path.length - scriptRef.length);
					break;
				}
			}
		}
		return path;
	};
	// if the prototypes.js file hasn't been already loaded by another widget:
	JUNE.Util.loadDependantFile(JUNE.getScriptPath('JuneWidget_DropDownList.js')+'res/protoypes.min.js');
}


JUNE.JuneWidget_DropDownList = function(){};
JUNE.Util.addMethodsTo(JUNE.JuneWidget_DropDownList.prototype,
{
    create : function(widgetID, updateElement, options)
    {
///<summary>Creates a new instance of a DropDownList widget.</summary>

        // VERIFY THE REQUIRED ARGUMENTS.
        if (!widgetID) { throw new Error(JUNE.Exception.missingArgument("JUNE.Widget.DropDownList", "widgetID")); }
        if (!updateElement) { throw new Error(JUNE.Exception.missingArgument("JUNE.Widget.DropDownList", "updateElement")); }


        // GLOBAL REFERENCES
        var _this = this;
        this.widgetID = widgetID;           // SET A REFERENCE TO THE WIDGET element
        this.updateElement = updateElement; // SET A REFERENCE TO THE element THAT WILL STORE THE SELECTED VALUE
        this.options = arguments[2];        // SET A REFERENCE TO THE options OBJECT
        this.captionElement = null;         // THE CAPTION ELEMENT
        this.listItemsWrapper = null;       // THE LIST ITEMS CONTAINER
        this.ListItems = null;              // THE LIST ITEMS ARRAY
		this.stateCookie = null;            // THE NAME OF THE COOKIE USED TO STORE THE VIEWSTATE OF THE WIDGET
        this.selectedIndex = -1;

		if (this.options.cookie) {
        	this.stateCookie = this.options.cookie;
		}

        // UPDATE REFERENCES:
        this.listItemsWrapper = JUNE.Dom.getByClass('ListItemsWrapper', this.widgetID)[0];
        this.captionElement = JUNE.Dom.getByTags('span', this.widgetID)[0];
        this.ListItems = JUNE.Dom.getByClass('ListItem', this.widgetID);
        
        // DISABLE DROPDOWNLIST
        if (this.__disabled())
        {
            this.__showDisabled();
        }

        // SHOW THE FIRST LIST ITEM :: HELPER FUNCTION:
        var __showFirstItem = function()
        {
            var firstListItem = _this.ListItems[0];
            _this.captionElement.setAttribute('id', _this.__getListItemID(firstListItem));
            _this.captionElement.innerHTML = firstListItem.innerHTML;

            _this.__selectedIndexChanged(0);   //  UPDATE THE SELECTED INDEX AND THE RELATED HIDDEN ELEMENT
            _this.__cleanListItems(_this.ListItems);                      //  REMOVE THE SELECTED CLASS FROM LIST ITEMS
            _this.__swapElements(firstListItem, _this.captionElement);   //  SHOW CAPTION

            if (_this.options.saveState && _this.options.cookie) { //  SAVE STATE [if set]
				_this.__saveState(0);
			}

            if (_this.options.onChange) {   //  EXECUTE THE CALLBACK [if set]
				_this.options.onChange(firstListItem, 0);
				
			}
        };


        if (this.__widgetHasItems())
        {
            // IF A SELECTED ITEM IS SET :: OVERRIDE THE USE COOKIE AND UPDATE ITS VALUE:
            if (this.options.selectedIndex != null)
            {
                // value must be in range:
                if ( (this.options.selectedIndex >= 0 ) && (this.options.selectedIndex <= this.ListItems.length) )
                {
                    this.__selectedIndexChanged(this.options.selectedIndex);   //  UPDATE THE SELECTED INDEX AND THE RELATED HIDDEN ELEMENT

                    this.__cleanListItems(this.ListItems);                      //  REMOVE THE SELECTED CLASS FROM LIST ITEMS

                    this.__swapElements(this.ListItems[this.options.selectedIndex], this.captionElement);   //  SHOW CAPTION

                    if (this.options.saveState && this.options.cookie) { //  SAVE STATE [if set]
						this.__saveState(this.options.selectedIndex);
					}

                    if (this.options.onChange) {   //  EXECUTE THE CALLBACK [if set]
						this.options.onChange(this.ListItems[this.options.selectedIndex], this.options.selectedIndex);
					}
                    
                }
                // VALUE IS OUT OF RANGE :: SELECT FIRST ITEM:
                else { __showFirstItem(); }
            }
            // IF THE USE-STATE OPTION IS SET:
            else if (this.options.saveState) { this.__loadState(); }

            // THE USE-STATE OPTION IS NOT SET ; MARK THE FIRST LIST ITEM AS SELECTED:
            else { __showFirstItem(); }

            // Item OnClick:
            this.ListItems.forEach(function(item, index)
            {
                if ( !_this.__disabled() && !JUNE.Dom.hasClass(item, 'Optgroup'))
                {
                    JUNE.Event.addHandler(item, 'click', function(event)
                    {
                        JUNE.Event.stopPropagation(event);

                        _this.__selectedIndexChanged(index);                //  UPDATE THE SELECTED INDEX AND THE RELATED HIDDEN ELEMENT

                        _this.__cleanListItems(_this.ListItems);            //  REMOVE THE SELECTED CLASS FROM LIST ITEMS

                        _this.__hideContent();                              //  HIDE THE LIST ITEMS WRAPPER

                        _this.__swapElements(this, _this.captionElement);   //  SHOW CAPTION

                        if (_this.options.saveState && _this.options.cookie) { //  SAVE STATE [if set]
							_this.__saveState(index);
						}

                        if (_this.options.onChange) {
							_this.options.onChange(item, index);            //  EXECUTE THE CALLBACK [if set]
						}
                    });
                }
            });
        } /* End __widgetHasItems() function */


        var caption = JUNE.Dom.getByClass('DropDownList_Header', this.widgetID)[0];
		
        JUNE.Event.addHandler(caption, 'click', function(event)
        {
		
            if ( !_this.__disabled() )
            {
                JUNE.Event.stopPropagation(event);

                _this.widgetID.className = 'DropDownList_Active';

                // Adjust size, if set:
                if (_this.__widgetHasItems() && _this.options.size != null && _this.options.size != -1) {
                    _this.__changeSize(_this.options.size);
                }
				
                // SHOW / HIDE THE LIST ITEMS CONTAINER
                if (_this.listItemsWrapper.style.display != 'block') {
                    _this.__showContent();
                }
                else { _this.__hideContent(); }
            }
        });

        JUNE.Event.addHandler(document, 'click', function (event) { if (_this.listItemsWrapper.style.display == 'block') { return _this.__hideContent(); }});
        JUNE.Event.addHandler(this.listItemsWrapper, 'click', function(event) { return JUNE.Event.stopPropagation(event); });

	}, /* End function create() */


/*=========================
//  INTERNAL METHODS
=========================*/
    __selectedIndexChanged : function (index)
    {
    ///<summary>Observer that gets notified every time a ListItem was selected.</summary>

        // Update object
        this.__updateElement(this.ListItems[index]);

        // Update the global index
        this.selectedIndex = index;
    },

    __hideContent : function ()
    {
    ///<summary>Hides all ListItems from the control.</summary>
        if (JUNE.Dom.hasClass(this.widgetID, 'DropDownList_Active')) {
            JUNE.Dom.removeClass(this.widgetID, 'DropDownList_Active');
        }
        return this.listItemsWrapper.style.display = 'none';
    },

    __showContent : function ()
    {
    ///<summary>Displays all ListItems from the control.</summary>
        return this.listItemsWrapper.style.display = 'block';
    },

    __disabled : function ()
    {
    ///<summary>Detects if the widget is disabled.</summary>
        return (this.options.disabled) ? true : false;
    },

    __showDisabled : function ()
    {
    ///<summary>Displays the DropDownList as disabled.</summary>
        var _color = this.options.disabledColor || '#cccccc';
        var Elements = JUNE.Dom.getByTags(['p','span'], this.widgetID);

        Elements.forEach(function(item) { item.style.color = _color; });
    },

    __updateElement : function (listItem)
    {
    ///<summary>Updates the Object with the value of the Selected ListItem.</summary>
        return this.updateElement.value = this.__getListItemValue(listItem);
    },

    __getListItemID : function (listItem)
    {
    ///<summary>Gets the Selected List Item's ID.</summary>
        return listItem.getAttribute('id');
    },

    __getListItemValue : function (listItem)
    {
    ///<summary>Gets the Selected List Item's VALUE.</summary>
        return listItem.getAttribute('title');
    },

    __getListItemText : function (listItem)
    {
    ///<summary>Gets the Selected List Item's TEXT.</summary>
        return listItem.innerHTML;
    },

    __saveState : function (ck_index)
    {
    ///<summary>Saves the DropDownList's state in a cookie.</summary>

		// IF THE COOKIE NAME WAS NOT SET:
		if (this.stateCookie) {
			JUNE.Cookie.setCookie(this.stateCookie, ck_index, 365);
		}
		else {
			JUNE.Exception.missingArgument("JUNE.Widget.DropDownList", "options.cookie");
			return;
		}
    },

    __loadState : function ()
    {
    ///<summary>Loads the DropDownList's state from the cookie.</summary>
		if (this.stateCookie)
		{
			var ck_index = JUNE.Cookie.getCookie(this.stateCookie);
			if (ck_index)
			{
				// UPDATE THE SELECTED INDEX
				this.selectedIndex = ck_index;
	
				// UPDATE OBJECT WITH THE SELECTED ITEM'S VALUE
				this.updateElement.value = this.__getListItemValue(this.ListItems[this.selectedIndex]);
	
				// Restore the last selected ListItem
				this.__swapElements(this.ListItems[this.selectedIndex], this.captionElement);
			}
			// NO COOKIE FOUND. SET THE COOKIE AND MARK THE FIRST LIST ITEM AS SELECTED
			else {
				var firstListItem = this.ListItems[0];
				this.captionElement.setAttribute('id', this.__getListItemID(firstListItem));
				this.captionElement.innerHTML = this.__getListItemValue(firstListItem);
				this.updateElement.value = this.captionElement.innerHTML;
				this.__saveState(0);
			}
		}
		else { JUNE.Exception.missingArgument("JUNE.Widget.DropDownList", "options.cookie"); return; }
    },

    __cleanListItems : function (listItemsArray)
    {
    ///<summary>Removes the selected class from any ListItem that might have it.</summary>
	
        listItemsArray.forEach(function(item) { 
		
			item.className = 'ListItem'; 
			}
		);
    },

    __swapElements : function (listItem, caption)
    {
    ///<summary>Replaces the default shown ListItem in the caption with the selected ListItem.</summary>

        // Get the needed attributes from the selected List Item
        var  li_id = this.__getListItemID(listItem)
            ,li_text = this.__getListItemText(listItem);

        // swap elements
        caption.setAttribute('id', li_id);
        caption.innerHTML = li_text;
		
        listItem.className = "ListItem_Selected";
    },

    __widgetHasItems : function ()
    {
    ///<summary>Detects if the widget has any listitems to display.</summary>
        return (this.ListItems.length > 0) ? true : false;
    },

    __changeSize : function (numOfItems)
    {
    ///<summary>Sets the number of ListItems that will be visible when the DropDownList is selected.</summary>
        var _this = this;
        function adjustSize (numberOfItems)
        {
            var new_height = numberOfItems * 20;
            _this.listItemsWrapper.style.height = new_height + 'px';
            _this.listItemsWrapper.style.overflowY = 'scroll';
        }

        if ( this.options.selectedIndex != null )
        {
            if (this.options.selectedIndex >= 0 && this.options.selectedIndex <= this.ListItems.length)
            {
                adjustSize(numOfItems);
            }
        }
    }
});

/*=========================
//      PUBLIC METHODS
=========================*/
JUNE.Util.addMethodsTo(JUNE.JuneWidget_DropDownList.prototype,
{
    disable : function ()
    {
    ///<summary>Disables the selected DropDownList.</summary>
        if (!this.__disabled())
        {
            this.options.disabled = true;
            this.__showDisabled();
        }
    },
    enable : function ()
    {
    ///<summary>Enables the selected DropDownList.</summary>
        if (this.__disabled())
        {
            this.options.disabled = false;
            JUNE.Dom.getByTags(['p','span'], this.widgetID).forEach(function(item) { item.style.color = ''; });
        }
    }
});


JUNE.Util.addMethodsTo(JUNE.Widget,
{
    DropDownList : function(widgetID, updateElement, options)
    {
///<summary>Creates a DropDownList widget.</summary>
///<param name="widgetID" type="Object" optional="false">(Required). The reference to the Widget element.</param>
///<param name="updateElement" type="Object" optional="false">(Required). The reference to the Element that will be used to store the value of the selected ListItem.</param>
///<param name="options" type="Object" optional="true">
///     (Optional). The Object Literal containing the additional options.
///                     size [Number] - The number of items to display in the DropDownList widget; by default, all items are displayed.
///                     saveState [Boolean] - Whether cookies should be used to store the index of the last visited ListItem.
///                     cookie [String] - The name of the cookie. Required if saveState is set to true.
///                     disabled [Boolean] - Whether the DropDownList widget should be displayed as disabled.
///                     disabledColor [String] - The caption's and the ListItems' foreground color when the DropDownList widget is displayed as disabled.
///                     selectedIndex [Number] - The index of the element to be shown as selected by default; if this value is set, it will make the saveState option useless.
///                     onChange [Function] - The callback method to execute when the selected item is clicked. Use this method when you want to override the default click event for a specific ListItem.
///                         Arguments:
///                             item [Object] - A direct reference to the selected item;
///                             index [Number] - The position in the ListItems array where the selected item can be found.
///</param>
        var module = null;
        try {
            module = new JUNE.JuneWidget_DropDownList();
            module.create(widgetID, updateElement, options);
            return module;
        }
        catch(ex) { throw new Error(JUNE.Exception.generalError('JUNE.Widget.DropDownList', "The DropDownList Widget could not be created...\n\nMessage: "+ex.message));}
    }
});