// *************************************************************************************************************************
// ComboBoxObj (Javascript Object)
//
// Wrapper around a Combobx ('div' HTML Element) containing Text (TextObj) and an Image (ImageObj).  The list of elements
// is a hidden window ('div' HTML Element) which contains rows of elements (DisplayObj).  When the combo box is clicked,
// the hidden window is moved to the bottom of the combobox and made visible.  When an element is chosen, the combobox text
// updates with the text of the selected DisplayObj.  A callback function can be provided which will be called when an
// element in the drop down window (other than the already selected element) has been chosen.  The drop down window remains 
// visible until the user clicks anywhere in the page (including anywhere in the combo box).
// To add the combo box to the form, call the draw() method.  The combo box will be added to the provided element through
// a call to the appendChild() method.
// *************************************************************************************************************************

// Dependencies:
/// <reference path="uicore.js" />
/// <reference path="divwrapper.js" />
/// <reference path="text.js" />
/// <reference path="image.js" />

ComboBoxObj = function(uniqueID, arrContents, visibleIndex, width, imagePath, 
                                            dropShadow, dropShadowColor, animateOpen, animateDuration, 
                                            classNamePrefix, maxItems, maxHeight, maxChars)
{
    /// <summary>Constructor for ComboBoxObj. [ComboBox = 'div' Element]  [ComboText = TextObj] [ComboImage = ImageObj] [ComboWindow = 'div' Element]</summary>
    /// <param name="uniqueID">[OPTIONAL] (string) unique id used in the ID's of internal elements. If null, generates random ID. (ComboBox = 'ComboBox[uniqueID]') (ComboWindow = 'ComboWindow[uniqueID]')</param>
    /// <param name="arrContents">(DisplayObj[]) Array of DisplayObj's which will be the rows in the Combo Drop Down Window</param>
    /// <param name="visibleIndex">(int) Index of DisplayObj to display initially (default: 0)</param>
    /// <param name="width">[OPTIONAL] (string/int) width of Combobox</param>
    /// <param name="imagePath">(string) Path to image to display in combobox window</param>
    /// <param name="dropShadow">(bool) True = Display a drop shadow around Drop Down Window, null/false = No drop shadow</param>
    /// <param name="dropShadowColor">[OPTIONAL] (string) Color of drop shadow (default: #726E6D) </param>
    /// <param name="animateOpen">(bool) True = Animate showing/hiding Drop Down Window, null/false = No Animation</param>
    /// <param name="animateDuration">[OPTIONAL] (string/int) Duration (seconds) of Drop Down animation (default: .15)</param>
    /// <param name="classNamePrefix">[OPTIONAL] (string) Prefix of Style Sheet class names for this combobox (default: 'combobox')</param>
    /// <returns>A new ComboBoxObj</returns>

    this.m_strUniqueID = (uniqueID != undefined) ? uniqueID : UIHelper.generateRandomString(10);
    this.m_arrContents = arrContents;
    if((arrContents != undefined) && (arrContents[visibleIndex] != undefined))
        this.m_iSelectedIndex = visibleIndex;
    else
        this.m_iSelectedIndex = 0;
    this.m_iOldSelectedIndex = this.m_iSelectedIndex; 
    this.m_varWidth = width;
    this.m_iscrollTopOffset = 0;
    this.m_strComboImagePath = (imagePath != undefined) ? imagePath : '';
    this.m_bDropShadow = (dropShadow == true) ? true : false;
    this.m_strDropShadowColor = (dropShadowColor != undefined) ? dropShadowColor : '#726E6D';
    this.m_bShowAnimation = (animateOpen == true) ? true : false;
    this.m_varAnimationDuration = (animateDuration != undefined) ? animateDuration : '.15';
    this.m_strClassNamePrefix = (classNamePrefix != undefined) ? classNamePrefix + '-' : 'combobox-';

    if ( null == maxItems || undefined == maxItems )
    {
        this.m_iMaxItem = 4;
    } else {
        this.m_iMaxItem = maxItems;
    }
    if ( null == maxHeight || undefined == maxHeight )
    {
        this.m_iMaxHeight = '72px';
    } else {
        this.m_iMaxHeight = maxHeight;
    }
    if ( null == maxChars || undefined == maxChars )
    {
        this.m_iMaxChars = 18;
    } else {
        this.m_iMaxChars = maxChars;
    }
    if ( this.m_arrContents.length >= this.m_iMaxItem ) // there will be a scrollbar 
    {
        this.m_iMaxChars -= 3;
    }
    
    
    this.m_iAnimationIndex = 0;
    this.m_iDropShadowIndex = 0;
    this.m_fnCallback = null;
    this.m_bClickHandled = false;
    
    // Elements
    this.m_elContainer = null;
    this.m_elDivComboBox = null;
    this.m_elDivWindow = null;
    this.m_elSpace = null;
    
    // Objects
    this.m_objTextDiv = null;
    this.m_objText = null;
    this.m_objImageDiv = null;
    this.m_objImage = null;
    this.m_arrComboRows = new Array();
    
    // ID's
    this.m_strComboBoxID = 'ComboBox' + this.m_strUniqueID;
    this.m_strWindowID = 'ComboWindow' + this.m_strUniqueID;
    this.m_strComboRowIDPrefix = this.m_strWindowID + 'Row';
    this.m_strTextDivID = this.m_strComboBoxID + 'TextDiv';
    this.m_strTextID = this.m_strComboBoxID + 'TextObj';
    this.m_strImageDivID = this.m_strComboBoxID + 'ImageDiv';
    this.m_strImageID = this.m_strComboBoxID + 'ImageObj';
    
    // Create ComboBox Div
    this.m_elDivComboBox = document.createElement('div');
    this.m_elDivComboBox.id = this.m_strComboBoxID;
    this.m_elDivComboBox.className = this.m_strClassNamePrefix + 'box';
    if(this.m_varWidth != undefined)
        this.m_elDivComboBox.style.width = this.m_varWidth;

    // Create Text inside combobox
    this.m_objTextDiv = new DivObj(this.m_strTextDivID);
    this.m_objTextDiv.setClassName(this.m_strClassNamePrefix + 'text');
    this.m_objText = new TextObj(this.m_strTextID, this.m_arrContents[this.m_iSelectedIndex].Text, this.m_strClassNamePrefix + 'text');
    this.m_objText.setText( this.m_arrContents[this.m_iSelectedIndex].Text, this.m_iMaxChars );
    if (this.m_arrContents[this.m_iSelectedIndex].Text.length > this.m_iMaxChars)
        this.m_objText.setTitle(this.m_arrContents[this.m_iSelectedIndex].Text);
    this.m_objText.draw(this.m_objTextDiv.getElement());
    this.m_objTextDiv.draw(this.m_elDivComboBox);
    this.m_objTextDiv.setTabIndex(0);
    
    // Create Image inside combobox (usually down arrow)
    this.m_objImageDiv = new DivObj(this.m_strImageDivID);
    this.m_objImageDiv.setClassName(this.m_strClassNamePrefix + 'image');
    this.m_objImage = new ImageObj(this.m_strImageID, this.m_strComboImagePath, '5px', '9px', 'right', null);
    this.m_objImage.draw(this.m_objImageDiv.getElement());
    this.m_objImageDiv.draw(this.m_elDivComboBox);

    // empty space to ensure the dropdown windows be pushed to the next line, see bug 761866
    this.m_elSpace = document.createElement('div');
    this.m_elSpace.style.width =  width;
    this.m_elSpace.style.height="1px";
    this.m_elSpace.style.overflow = 'hidden';
    this.m_elDivComboBox.appendChild( this.m_elSpace );

    // Create Drop Down Window which appears below combobox when the box is clicked
    this.m_elDivWindow = document.createElement('div');
    this.m_elDivWindow.id = this.m_strWindowID;
    this.m_elDivWindow.style.position = 'absolute';

    // height is determined by the size of the content array, 'auto' or '??px'

    if ( this.m_arrContents.length < this.m_iMaxItem )
    {
        this.m_elDivWindow.style.height = 'auto';
        this.m_bHasVScroll = false;
    } 
    else 
    {
        this.m_elDivWindow.style.height = this.m_iMaxHeight;
        this.m_elDivWindow.style.overflow= 'auto';        
        this.m_bHasVScroll = true;
    }
        
    this.m_elDivWindow.className = this.m_strClassNamePrefix + 'window';

    if(this.m_varWidth != undefined)
        this.m_elDivWindow.style.width = this.m_varWidth;

    // Handle adding Drop Shadow and setting up animation
    var currIndex = 0;
    if(this.m_bDropShadow)
    {
        this.m_elDivWindow.style.filter = 'progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Positive=true, Color='+this.m_strDropShadowColor+')';
        this.m_iDropShadowIndex = currIndex;
        currIndex++;              
    }
    if(this.m_bShowAnimation)
    {
        if(this.m_elDivWindow.style.filter == undefined)
            this.m_elDivWindow.style.filter = '';

        this.m_elDivWindow.style.filter += 'progid:DXImageTransform.Microsoft.GradientWipe(duration=' + this.m_varAnimationDuration + ')';
        this.m_iAnimationIndex = currIndex;
        currIndex++;
    }
    if(this.m_elDivWindow.style.filter != undefined)
        this.m_elDivWindow.style.filter += ';';

    this.m_elDivWindow.style.visibility = 'hidden';

    // Add rows to Combo Window
    if(this.m_arrContents != undefined)
    {
        for(var i=0; i < this.m_arrContents.length; i++)
        {
            var newRow = new ComboWindowRowObj(this.m_strComboRowIDPrefix+i, this.m_arrContents[i].Text, i, this);
            this.m_arrComboRows.push(newRow);
            newRow.draw(this.m_elDivWindow);
        }
    }
    this.m_elDivComboBox.appendChild(this.m_elDivWindow);
}

ComboBoxObj.prototype = 
{
    draw:function(elementDiv)
    {
        /// <summary>Calls appendChild() on the provided element, appending this combobox element</summary>
        /// <param name="elementDiv">(HTML Element) HTML element to append this combobox to</param>
        if(elementDiv != undefined)
        {
            var self = this;
            // Store container element
            this.m_elContainer = elementDiv;
            
            this.m_elDivComboBox.onclick = function() {self.clickOnComboBox()};
            this.m_elDivComboBox.onkeydown = function() {self.keyDown()};
            document.body.attachEvent("onclick", function() {self.clickOutsideComboBox()});
            
            this.m_elContainer.appendChild(this.m_elDivComboBox);                      
        }
    },

    setComboBoxBorder:function(cobrandingobj)
    {
        /// <summary>Set the border style for this combo box</summary>    
        if(this.m_elDivComboBox != undefined)
        {
            this.m_elDivComboBox.style.borderStyle = "solid";
            this.m_elDivComboBox.style.borderWidth = "1";
            this.m_elDivComboBox.style.verticalAlign = "top";
            this.m_elDivComboBox.style.borderColor = "#666666";

            if ( null == cobrandingobj || undefined == cobrandingobj )
                return;
            if ( null == cobrandingobj.m_strFieldBdColor ||undefined == cobrandingobj.m_strFieldBdColor )
                return;
            if ( cobrandingobj.m_strFieldBdColor.length <= 0 )
                return;

            this.m_elDivComboBox.style.borderColor = cobrandingobj.m_strFieldBdColor;
        }
    },
    
    setArrowAlign:function(alignment)
    {
        /// <summary>Set the border style for this combo box</summary>    
        if(this.m_elDivComboBox != undefined)
        {
            this.m_objImageDiv.setAlign(alignment);
        }
    },
    
    setCallback:function(callback)
    {
        /// <summary>Sets the callback function for this combobox. Function is called when user selects an item in the combobox other than the one that is already selected</summary>
        /// <param name="callback">(Function) Callbac function to call when a new element is selected</param>
        this.m_fnCallback = callback;
    },
    
    getSelectedIndex:function()
    {
        /// <summary>Returns the index of the currently selected DisplayObj</summary>
        return this.m_iSelectedIndex;
    },
    
    getSelectedValue:function()
    {
        /// <summary>Returns 'value' property of selected DisplayObj</summary>
        return this.m_arrContents[this.m_iSelectedIndex].Value;
    },
    
    getSelectedObj:function()
    {
        /// <summary>Returns currently selected DisplayObj</summary>
        return this.m_arrContents[this.m_iSelectedIndex];
    },
    
    setTabIndex:function(value)
    {
        /// <summary>Sets the tab index of this combobox</summary>
        /// <param name="value">(int) Tab index of this combobox</param>
        if((this.m_elDivComboBox != undefined) && (value != undefined))
            this.m_elDivComboBox.tabIndex = value;
    },
    
    // **********************************************************************************
    // * Internal methods
    // **********************************************************************************
    clickOnComboBox:function()
    {
        /// <summary>Called when combobox is clicked on</summary>
        this.m_bClickHandled = true;
        this.switchWindowState();
    },
    
    keyDown:function()
    {
        if(window.event != undefined)
        {
            var keycode = window.event.keyCode;
            if((keycode == KEY_CODE_SPACE) || (keycode == KEY_CODE_ENTER))
            {
                window.event.returnValue = false;
                this.switchWindowState();
            }
        }
    },
    
    clickOutsideComboBox:function()
    {
        /// <summary>Called when user clicks anywhere in the form, closes the window if not already handled</summary>
        if(!this.m_bClickHandled)
            this.closeWindow();
        this.m_bClickHandled = false;
    },
    
    switchWindowState:function()    
    {
        /// <summary>Closes window if it's open, opens it if it's closed</summary>
        if(this.m_elDivWindow != undefined)
        {
            if(this.m_elDivWindow.style.visibility == 'visible')
                this.closeWindow();
            else if(this.m_elDivWindow.style.visibility == 'hidden')
                this.openWindow();
        }
    },
    
    closeWindow:function()
    {
        /// <summary>Closes (hides) the drop down window, animates the action if enabled</summary>
        // Animate closing the window if animation is enabled
        if((this.m_elDivWindow != undefined) && 
            this.m_bShowAnimation &&
           (this.m_elDivWindow.filters != undefined) &&
           (this.m_elDivWindow.filters[this.m_iAnimationIndex] != undefined))
        {
            this.m_elDivWindow.filters[this.m_iAnimationIndex].Motion = 'reverse';
            this.m_elDivWindow.filters[this.m_iAnimationIndex].WipeStyle = 1;
            this.m_elDivWindow.filters[this.m_iAnimationIndex].Apply();
            this.m_elDivWindow.style.visibility = 'hidden';
            this.m_elDivWindow.filters[this.m_iAnimationIndex].Play();
        }
        else
        {
            this.m_elDivWindow.style.visibility = 'hidden';
        }
    },
    
    openWindow:function()
    {
        /// <summary>Opens (makes visible) the drop down window, animates the action if enabled</summary>
        if((this.m_elDivWindow != undefined) && (this.m_elDivComboBox != undefined))
        {            
            // Animate drawing the window if animation is enabled
            if(this.m_bShowAnimation && 
              (this.m_elDivWindow.filters != undefined) && 
              (this.m_elDivWindow.filters[this.m_iAnimationIndex] != undefined))
            {
                this.m_elDivWindow.filters[this.m_iAnimationIndex].Motion = 'forward';
                this.m_elDivWindow.filters[this.m_iAnimationIndex].WipeStyle = 1;
                this.m_elDivWindow.filters[this.m_iAnimationIndex].Apply();
                this.m_elDivWindow.style.visibility = 'visible';
                this.m_elDivWindow.filters[this.m_iAnimationIndex].Play();
            }
            else
                this.m_elDivWindow.style.visibility = 'visible';
        }
    },
    
    updateComboBoxSelected:function()
    {
        /// <summary>Updates the text in the combobox to be that of the last selected DisplayObj. Calls callback if one is enabled</summary>
        if((this.m_objText != undefined) && 
           (this.m_arrContents != undefined) && 
           (this.m_arrContents[this.m_iSelectedIndex] != undefined))
        {
            if(this.m_iSelectedIndex != this.m_iOldSelectedIndex)
            {
                if(this.m_fnCallback != undefined)
                    this.m_fnCallback();
                this.m_objText.setText(this.m_arrContents[this.m_iSelectedIndex].Text, this.m_iMaxChars);
                this.m_iOldSelectedIndex = this.m_iSelectedIndex;
                if (this.m_arrContents[this.m_iSelectedIndex].Text.length > this.m_iMaxChars)
                    this.m_objText.setTitle(this.m_arrContents[this.m_iSelectedIndex].Text);
                else
                    this.m_objText.setTitle('');
            }
        }
    },
    // adjust the position of the combobox-window to combobox-box when scroll happens
    adjustPositionOnScroll:function( scrolltopOffset )
    {
        if ( scrolltopOffset != null && scrolltopOffset != undefined )
        {
            this.m_iscrollTopOffset = scrolltopOffset;
            // simple implementation, when scroll, just hidden the drop down
            if(this.m_elDivWindow.style.visibility == 'visible')
                this.m_elDivWindow.style.visibility = 'hidden'
        }
    }
}

// *************************************************************************************************************************
// ComboWindowRowObj (Javascript Object)
//
// This is an internal class used by the ComboBoxObj to hold the elements in the drop down window.  This object is dependant
// on the Drop Down Window of a ComboBoxObj so it is not re-usable for other objects.  This is a wrapper around a 'div' element
// *************************************************************************************************************************
ComboWindowRowObj = function(uniqueID, innertext, index, comboBoxObj)
{
    /// <summary>Constructor for ComboWindowRowObj.  A ComboWindowRowObj is a 'div' element.  This is dependant on a ComboWindow from a ComboBoxObj and is not re-usable for other objects</summary>
    /// <param name="uniqueID">[OPTIONAL] (string) Unique ID for this ComboRowObj. If null, generates random ID.</param>
    /// <param name="innertext">(string) Display string for this combo row</param>
    /// <param name="index">(int) Index of this combo row in the Drop Down Window</param>
    /// <param name="comboBoxObj">(ComboBoxObj's ComboWindow 'div') Drop Down Window this ComboWindowRow is part of</param>
    /// <returns>A new ComboWindowRowObj</returns>
    
    this.m_strUniqueID = (uniqueID != null) ? uniqueID : 'ComboWindowRowObj' + UIHelper.generateRandomString(10);
    this.m_strText = innertext;
    this.m_iIndex = index;
    this.m_objComboBox = comboBoxObj;
    this.m_strID = this.m_strUniqueID;
    this.m_strClassNamePrefix = (this.m_objComboBox != undefined) ? this.m_objComboBox.m_strClassNamePrefix : 'combobox-';

    // Elements
    this.m_elParentWindow = null;
    this.m_elDivComboRow = null;
    this.m_objLink = null;
    
    // Create Combo Row div
    this.m_elDivComboRow = document.createElement("div");
    this.m_elDivComboRow.className = this.m_strClassNamePrefix + 'row';
    this.m_elDivComboRow.tabIndex = -1;
        
    if ( this.m_objComboBox.m_iMaxChars!=null && this.m_objComboBox.m_iMaxChars != undefined )
    {
        this.m_objLink = new LinkObj('Link' + this.m_strID, "#", UIHelper.truncateName(this.m_strText, this.m_objComboBox.m_iMaxChars), null, true);
        if (this.m_strText.length > this.m_objComboBox.m_iMaxChars)
        {
            this.m_objLink.setTitle(this.m_strText);
        }
    }    
    else      
        this.m_objLink = new LinkObj('Link' + this.m_strID, "#", this.m_strText, null);
    
    this.m_objLink.setClassName( 'credpicker');    
    this.m_elDivComboRow.id = this.m_strID;
    this.m_objLink.onclick = function() {return false;};    
    this.m_objLink.draw(this.m_elDivComboRow);    
    this.m_objLink.setTabIndex(0);
}

ComboWindowRowObj.prototype = 
{
	draw:function(comboWindow)
    {
        /// <summary>Calls appendChild() on the Drop Down Window for the ComboBoxObj this is part of</summary>
        /// <param name="elementDiv">(ComboBoxWindow 'div' element) Drop Down Window to append this row to</param>
	    if(comboWindow != undefined)
	    {
	        var self = this;
	        
	        this.m_elParentWindow = comboWindow;
	        
	        this.m_elDivComboRow.onclick = function() {self.comboRowClick()};
	        this.m_elDivComboRow.onkeydown = function() {self.checkEnterKey()};
	        this.m_elDivComboRow.onmouseover = function() {self.comboRowHighlight(true)};
	        this.m_elDivComboRow.onmouseout = function() {self.comboRowHighlight(false)};
	        this.m_elParentWindow.appendChild(this.m_elDivComboRow);
	    }
	},
	
	getID:function()
	{
	    /// <summary>Returns the ID of this 'div' element</summary>
	    return this.m_strID;
	},
	
	setID:function(value)
	{
	    /// <summary>Sets the ID of this 'div' element</summary>
	    /// <param name="value">(string) ID to use</param>
	    if(value != undefined)
	    {
	        this.m_strID = value;
	        this.m_elDivComboRow.id = this.m_strID;
	    }
	},

    checkEnterKey:function()
    {
        if(window.event != undefined)
        {            
            if((window.event.keyCode == KEY_CODE_ENTER))
            {
                window.event.returnValue = false;
                this.comboRowClick();
            }
        }
    },
	
	comboRowHighlight:function(highlight)
    {
        /// <summary>Highlights/De-Highlights this combo row</summary>
	    /// <param name="highlight">(bool) True = Switch combo row's Style Sheet Class to 'rowselect' class, False = Switch class to 'row' class</param>
        if(this.m_elDivComboRow != undefined)
            this.m_elDivComboRow.className = (highlight == true) ? this.m_strClassNamePrefix + 'rowselect' : this.m_strClassNamePrefix + 'row';
    },
    
    comboRowClick:function()
    {
        /// <summary>Called when this combo row is clicked, sets ComboBoxObj's selected index to it's own index, update's ComboBox, and closes Drop Down Window</summary>
	    /// <param name="rowIndex">(index) index of comborow that was clicked</param>
        if(this.m_objComboBox != undefined)
        {
            if(this.m_objComboBox.m_iSelectedIndex != this.m_iIndex)
            {
                this.m_objComboBox.m_iSelectedIndex = this.m_iIndex;
                this.m_objComboBox.updateComboBoxSelected();
            }
            else
            {
                if(this.m_objComboBox.m_fnCallback != undefined)
                    this.m_objComboBox.m_fnCallback();
            }
            this.m_objComboBox.m_bClickHandled = true;
        }
    }
}
