//----------------------------------------------------------------------------
// Public interface

/**
 * Display popup auto complete suggestion container
 *
 * @param autoCompleteDataList            Comma separated list of auto complete data string
 * @param formId                          Form id
 * @param textCtrlName                    text control name
 * @param onChangeMethod                  onChange method
 * @param divSize                         pop up container max size
 * @param targetFrameName                 Target frame for popup
  */
function autoCompleteTextBinding(autoCompleteDataList, formId, textCtrlName, onChangeMethod, divSize, targetFrameName)
{
   var elmTextSrc = null;
   if (textCtrlName != null && formId != null && textCtrlName.length > 0)
   {
      elmTextSrc = document.forms[formId].elements[textCtrlName];
      var eTarget = wdk.events.getEventTarget(elmTextSrc);

      eTarget.addEventListener("keyup", onAutoCompleteKeyUp, false);
      eTarget.addEventListener("keydown", onAutoCompleteKeyDown, false);
      eTarget.addEventListener("blur", onAutoCompleteBlur, false);
      eTarget.addEventListener("focus", onAutoCompleteFocus, false);

      var autoComplete = new AutoComplete(autoCompleteDataList, elmTextSrc, divSize, onChangeMethod, targetFrameName);
   }
}

/**
 * Display popup auto complete suggestion container when clicking the button
 *
 * @param fixedDataList                   Comma separated list of auto complete data string
 * @param formId                          Form id
 * @param textCtrlName                    text control name
 * @param buttonCtrlName                  button control name
 */
function autoCompleteButtonBinding(fixedDataList, formId, textCtrlName, buttonCtrlId)
{
   if (textCtrlName != null && formId != null && textCtrlName.length > 0 && buttonCtrlId != null && formId != null && buttonCtrlId.length > 0)
   {
      var elmButtonSrc = document.getElementById(buttonCtrlId);
      var elmTextSrc = document.forms[formId].elements[textCtrlName];
      if (elmButtonSrc != null && elmTextSrc != null && elmTextSrc.autoComplete != null)
      {
         var eButtonTarget = wdk.events.getEventTarget(elmButtonSrc);
         eButtonTarget.addEventListener("mousedown", onAutoCompleteButtonMouseDown, false);
         eButtonTarget.addEventListener("click", onAutoCompleteButtonClick, false);

         elmButtonSrc.autoComplete = elmTextSrc.autoComplete;

         elmTextSrc.autoComplete.fixedDataList = fixedDataList;
         elmTextSrc.autoComplete.buttonCtrl = elmButtonSrc;

         elmButtonSrc.style.height = elmTextSrc.offsetHeight + "px";
       }
   }
}

/**
 * set the name of the target frame
 * @param textCtrl  the control object/element.
 * @param strTargetFrameName the name of the frame.
 */
function setAutoCompleteTargetFrame(textCtrl, strTargetFrameName)
{
   if (textCtrl != null && typeof(textCtrl.autoComplete) != "undefined" && textCtrl.autoComplete != null)
   {
      textCtrl.autoComplete.targetFrameName = strTargetFrameName;
   }
}

//----------------------------------------------------------------------------
// Private functions/implementation

/**
 * Called when the user clicks on the button
 */
function onAutoCompleteButtonClick(evt)
{
    var src = evt.target;
    var autoComplete = src.autoComplete;

    if (autoComplete != null)
    {
       autoComplete.bSetfocus = true;
       autoComplete.srcCtrl.focus();

       autoComplete.matchingSuggestions = autoComplete.fixedDataList;
       //Bug 155623 - Set overflow and add scroll bar if the combo items is large.
       // recCnt is the no of items retrieved for the combo.
       var overflw = true;
       var recCnt = autoComplete.fixedDataList.length;
       autoComplete.showMatchingSuggestions(src.offsetWidth,overflw,recCnt);

    }
}

/**
 *  Mouse down event on the button control
 */
function onAutoCompleteButtonMouseDown(evt)
{
   var src = evt.target;
   var autoComplete = src.autoComplete;

   if (autoComplete != null)
   {
      autoComplete.blur = false;
   }
}

/**
 *  Key up event on the text control
 */
function onAutoCompleteKeyUp(evt)
{
    var src = evt.target;
    var autoComplete = src.autoComplete;
    autoComplete.keyUp(evt);
}

/**
 * Key down event on the text control
 */
function onAutoCompleteKeyDown(evt)
{
    var src = evt.target;
    var autoComplete = src.autoComplete;
    autoComplete.keyDown(evt);
}

/**
 * Key press event on the text control
 */
function onAutoCompleteKeyPress(evt)
{
    if (evt.keyCode != wdk.events.keycodes.ENTER)
    {
        return false;
    }

    var src = null;
    if (evt.target)
    {
        src = evt.target;
    }
    else
    {
        src = evt.srcElement;
    }

    var autoComplete = src.autoComplete;
    return autoComplete.returnKeyPress(evt);
}

/**
 * Blur event on the text control
 */
function onAutoCompleteBlur(evt)
{
    var src = evt.target;
    var autoComplete = src.autoComplete;

    if (autoComplete.div != null)
    {
        if(autoComplete.div.m_bBlur == true)
        {
            autoComplete.hideDiv();
        }
        else
        {
           autoComplete.div.m_bBlur = true;
        }
    }

    if (autoComplete.blur == true && autoComplete.oldValue != null && autoComplete.oldValue != src.value)
    {
       autoComplete.onChange(evt);
       autoComplete.oldValue = null;
    }
    else
    {
       autoComplete.blur = true;
    }
}

/**
 * Called when the text control gained the focus
 */
function onAutoCompleteFocus (evt)
{
   src = evt.target;
   var autoComplete = src.autoComplete;
   if (autoComplete && autoComplete.bSetfocus == false)
   {
      autoComplete.oldValue = src.value;
    }
}

/**
 * Mouse over event on the popup container
 */
function onAutoCompleteMouseover(evt)
{
    var target = evt.target;
    if (target != null)
    {
        var posId = target.posId;
        var div = wdk.dom.findAncestorWithClassName(target, "POPUPCONTAINER");
        if (div != null)
        {
            var autoComplete = div.autoCompleteCtrl;
            autoComplete.highlighted = posId;
            autoComplete.changeHighlight();
         }
    }
}

/**
 *  Called when the user clicks the popup container
 */
function onAutoCompleteClick(evt)
{
    var target = evt.target;
    if (target != null)
    {
        var div = wdk.dom.findAncestorWithClassName(target, "POPUPCONTAINER");
        if (div != null)
        {
            var autoComplete = div.autoCompleteCtrl;
            autoComplete.makeSelectionAndHide(evt);
        }
    }
}

/**
 * Mouse down event on the popup container
 */
function onAutoCompleteMouseDown(evt)
{
    var target = evt.target;
    if (target != null)
    {
        var div = wdk.dom.findAncestorWithClassName(target, "POPUPCONTAINER");
        if (div != null)
        {
           div.m_bBlur = false;
           div.autoCompleteCtrl.blur = false;
        }
    }
}

/**
 * Construct Auto complete object
 *
 * @param autoCompleteDataList            Comma separated list of auto complete data string
 * @param fixedDataList                   Comma separated list of fixed data string
 * @param textCtrl                        text control
 * @param buttonCtrl                      button control
 * @param onChangeMethod                  onChange method
 * @param divSize                         pop up container max size
 * @param targetFrameName                 Name of target frame to display popuup
 */
function AutoComplete(autoCompleteDataList, textCtrl, divSize, onChangeMethod, targetFrameName)
{
   //The browsers' own autocomplete feature can be problematic, since it will
   //be making suggestions from the users' past input.
   //Setting this attribute should turn it off.
   textCtrl.setAttribute("autocomplete","off");

   this.suggestions = autoCompleteDataList;

   //Arrow to store a subset of matching suggestions that match the user's input
   this.matchingSuggestions = new Array();

   //The text input by the user.
    this.inputText = null;

    //A pointer to the index of the highlighted eligible item. -1 means nothing highlighted.
    this.highlighted = -1;

    textCtrl.autoComplete = this;

    this.srcCtrl = textCtrl;

    this.blur = true;

    // array of select controls that are possibly behind the popup container
    this.hiddenSelects = null;

    this.div = null;
    this.divSize = divSize;

    this.targetFrameName = targetFrameName;

    // the original value
    this.oldValue = null;
    this.bSetfocus = false;
    this.onChangeMethod = onChangeMethod;
}

AutoComplete.prototype.returnKeyPress  = function(evt)
{
    if (evt.keyCode != wdk.events.keycodes.ENTER)
    {
        return false;
    }

    var handleReturnKey = false;

    if ( this.highlighted > -1 && this.highlighted < this.matchingSuggestions.length)
    {
      handleReturnKey = true;
    }
    this.makeSelectionAndHide(evt);
    return handleReturnKey;
}


AutoComplete.prototype.keyDown  = function(evt)
{
    var eventKeyCode =  evt.keyCode;

    switch(eventKeyCode)
    {
        case wdk.events.keycodes.TAB:
            if (this.highlighted > -1)
            {
                evt.stopPropagation();
                evt.preventDefault();
             }
            this.makeSelectionAndHide(evt);

        break;

        case wdk.events.keycodes.ESC:
            if (this.div != null)
            {
                evt.stopPropagation();
                evt.preventDefault();
             }
            this.hideDiv();

        break;

        case wdk.events.keycodes.UP_ARROW:
            if (this.matchingSuggestions.length > 0)
            {
                if (this.highlighted <= 0)
                {
                    this.highlighted = this.matchingSuggestions.length;
                }
                this.highlighted--;
                this.changeHighlight();
                evt.stopPropagation();
                evt.preventDefault();
            }

        break;

        case wdk.events.keycodes.DOWN_ARROW:
            if (this.matchingSuggestions.length > 0)
            {
                if (this.highlighted  == (this.matchingSuggestions.length - 1))
                {
                    this.highlighted = -1;
                }

                this.highlighted ++;
                this.changeHighlight();
                evt.stopPropagation();
                evt.preventDefault();
            }
        break;
    }
}

AutoComplete.prototype.makeSelectionAndHide  = function( evt)
{
   this.useMatchingSuggestion();
   this.hideDiv();
   this.bSetfocus = true;
   this.srcCtrl.focus();

   // fire onchange event when the control has drop down button
   if (this.buttonCtrl != null)
   {
      this.onChange(evt);
   }
}

AutoComplete.prototype.keyUp  = function(evt)
{
    var eventKeyCode = evt.keyCode;
    switch(eventKeyCode)
    {
    //The control keys were already handled by onkeydown, so do nothing.
    case wdk.events.keycodes.TAB:
    case wdk.events.keycodes.ESC:
    case wdk.events.keycodes.UP_ARROW:
    case wdk.events.keycodes.DOWN_ARROW:
    case wdk.events.keycodes.ENTER:
        return;
    default:

        var target =  evt.target;

        if (this.inputText != target.value)
        {
            this.inputText = target.value;

            this.getSuggestions();

            // we have something to show
            if (this.matchingSuggestions.length > 0)
            {
                this.showMatchingSuggestions(0);
                return;
            }
            this.hideDiv();

         }
    }
}

AutoComplete.prototype.showMatchingSuggestions = function(width,overflw,recCnt)
{
    this.attachDiv(createAutoCompleteDiv(this.targetFrameName,overflw,recCnt), width);    
    this.highlighted = -1;
    this.setContent();
    this.reCalculateWidth(width);
    this.showDiv();
    this.hideIntersectingSelects();
}

AutoComplete.prototype.useMatchingSuggestion = function()
{
   if (this.highlighted > -1 && this.highlighted < this.matchingSuggestions.length)
   {
        var target =  this.srcCtrl;

        var matchingString = this.matchingSuggestions[this.highlighted];

        target.value = matchingString;

        this.inputText = target.value;
    }
}

AutoComplete.prototype.changeHighlight  = function()
{
    if (this.div == null)
    {
        return;
    }

    var lis = this.div.getElementsByTagName('DIV');
    for (var i = 0; i < lis.length; i++)
    {
        var li = lis[i];

        if (this.highlighted == i)
        {
            li.className = "autoCompleteHighlightSelected";
        }
        else
        {
            li.className = "menuBarHighlightAutoComplete";
        }
    }
}

AutoComplete.prototype.onChange  = function(evt)
{
    if (this.onChangeMethod != null)
    {
       this.onChangeMethod.call(this.srcCtrl, evt);
    }
}

function createAutoCompleteDiv(targetFrameName,overflw,recCnt)
{
    if (createAutoCompleteDiv.sAutoCompleteDIV == null)
    {
        var wnd = getAutoCompleteTargetWindow(targetFrameName);
        createAutoCompleteDiv.sAutoCompleteDIV = wnd.document.createElement("DIV");
        createAutoCompleteDiv.sAutoCompleteDIV.id = "AutoCompleteContainer";
        wnd.document.body.appendChild(createAutoCompleteDiv.sAutoCompleteDIV);
        
        var dispItemcnt = 10;
        var rowheightinpx = 22;        

        with (createAutoCompleteDiv.sAutoCompleteDIV.style)
        {
            position="absolute";
            overflow="hidden";
            borderStyle = "solid";
            borderWidth = 1 + "px";
            cursor = "pointer";
            //Add scroll bar if the no if items in the combo exceeds 10.
            if (overflw == true && overflw != null && recCnt > dispItemcnt)
            {
               overflowY = "auto";
               overflowX = "hidden";
               height = (dispItemcnt * rowheightinpx) + "px";
            }
        }
        createAutoCompleteDiv.sAutoCompleteDIV.m_bBlur = true;
        createAutoCompleteDiv.sAutoCompleteDIV.className = "POPUPCONTAINER";

        var eTarget = wnd.wdk.events.getEventTarget(createAutoCompleteDiv.sAutoCompleteDIV);
        eTarget.addEventListener("mousedown", onAutoCompleteMouseDown, false);
    }
    return createAutoCompleteDiv.sAutoCompleteDIV;
}

createAutoCompleteDiv.sAutoCompleteDIV = null;

/**
 * Get target window for autocomplete popup
 *
 * @param targetFrameName   name of the target frame
 * @return        the target window
 */
function getAutoCompleteTargetWindow(targetFrameName)
{
    if (targetFrameName == null)
    {
        return window;
    }
    else
    {
        return eval(getAbsoluteFramePath(targetFrameName));
    }
}

AutoComplete.prototype.attachDiv  = function(div, extraWidth)
{
    if ( this.div == null)
    {
        this.div = div;
        var elmSrc = this.srcCtrl;
        var elemSrcRect = new wdk.pos.getElementRect(elmSrc);
        with (this.div.style)
        {
           if (extraWidth > 0)
           {
              width = elmSrc.offsetWidth + extraWidth +"px";
              div.style.width = width;
           }
           else
           {
              overflow = "auto";
              visibility = "hidden";
           }
           if (this.targetFrameName == null)
           {
              top = elemSrcRect.bottom;
           }
           else
           {
              top = "-1px";
           }
            left = elemSrcRect.left;
            zIndex = 99999;
         }
        div.autoCompleteCtrl = this;
    }
}

AutoComplete.prototype.hideDiv  = function()
{
    if (this.div != null)
    {
	this.div.style.visibility = "hidden";
        this.highlighted = -1;
        this.showHiddenIntersectingSelects();
        this.div = null;
        createAutoCompleteDiv.sAutoCompleteDIV = null;
    }
}

/**
 * Add a specified entry to the suggestion list
 *
 * @param entry	   an entry to add
 */
AutoComplete.prototype.addEntry  = function(entry)
{
    for (var i = 0; i < this.suggestions.length; i++)
    {
        // check if the entry is already in the sugestion list
        if (this.suggestions[i] == entry)
        {
            return;
        }
    }
    // add the new entry & sort
    this.suggestions[this.suggestions.length]=entry;
    this.suggestions.sort();
}

AutoComplete.prototype.getSuggestions  = function()
{
    this.matchingSuggestions = new Array();
    var count = 0;

    if (this.inputText.length > 0)
    {
        for (var i = 0; i < this.suggestions.length; i++)
	    {
            var listvalue = this.suggestions[i];
            if (listvalue.toLowerCase().indexOf(this.inputText.toLowerCase()) == 0)
            {
                if (count >= this.divSize)
                {
                    break;
                }
                this.matchingSuggestions[this.matchingSuggestions.length]=listvalue;
                count = count + 1;
            }
        }
     }
}

AutoComplete.prototype.setContent  = function()
{
    if (this.div != null)
    {
       // remove any existing child DIVs
       while (this.div.childNodes.length > 0)
       {
           this.div.removeChild(this.div.childNodes[0]);
       }

       var wnd = getAutoCompleteTargetWindow(this.targetFrameName);

       //Create an array of LI's for the words.
       for (var i = 0; i < this.matchingSuggestions.length; i++)
      {
            var word = this.matchingSuggestions[i];
            var innerDiv = wnd.document.createElement('DIV');
            var tNode = wnd.document.createTextNode(word);
            innerDiv.appendChild(tNode);
            innerDiv.className = "menuBarHighlightAutoComplete";
            innerDiv.posId = i;
            var eTarget = wnd.wdk.events.getEventTarget(innerDiv);
            eTarget.addEventListener("mouseover", onAutoCompleteMouseover, false);
            eTarget.addEventListener("click", onAutoCompleteClick, false);
            this.div.appendChild(innerDiv);
       }

    }
}

AutoComplete.prototype.reCalculateWidth  = function(extraWidth)
{
    if (this.div != null)
    {
       // remove any existing child DIVs
       var elmSrc = this.srcCtrl;

       if (extraWidth == 0)
       {
            var widthSize;
            if (this.div.offsetWidth < elmSrc.offsetWidth)
            {
               widthSize = elmSrc.offsetWidth;
            }
            else if (this.div.offsetWidth > 2 * elmSrc.offsetWidth)
            {
               widthSize = 2 * elmSrc.offsetWidth;
            }
            else
            {
               widthSize = this.div.offsetWidth;
            }

            widthSize += "px";
            this.div.style.overflow = "hidden";
            this.div.style.width = widthSize;
       }
    }
}

AutoComplete.prototype.showDiv  = function()
{
    if (this.div != null)
    {
       this.div.style.visibility="visible";
    }
}

/**
 * Hide any select elements that intersest the passed rectangle
 *
 * @param left, top, right, bottom   Rectangle coords
 */
AutoComplete.prototype.hideIntersectingSelects = function()
{
    function HiddenSelectCtrl(element, elemRect)
    {
        this.m_element = element;
        this.m_visibility = element.style.visibility;
        this.m_elemRect = elemRect;
    }

    var divElmRect = new wdk.pos.getElementRect(this.div);

    // initialize for the first time
    if ( this.hiddenSelects == null)
    {
        var wnd = getAutoCompleteTargetWindow(this.targetFrameName);
        this.hiddenSelects = [];
        for (var j = 0; j < wnd.document.forms.length; j++)
        {
            var form = wnd.document.forms[j];
            for (var i = 0; i < form.elements.length; i++)
            {
                var element = form.elements[i];
                if (element.type && element.type.indexOf("select") == 0)
                {
                    var elemRect = new wdk.pos.getElementRect(element);

                    // is element intersesting?
                    if ( divElmRect.left < elemRect.right && divElmRect.top < elemRect.bottom && divElmRect.right > elemRect.left)
                    {
                        this.hiddenSelects[this.hiddenSelects.length] = new HiddenSelectCtrl(element, elemRect);
                        if (wdk.pos.intersect(divElmRect, elemRect, false))
                        {
                            element.style.visibility = "hidden";
                        }
                    }
                }
            }
        }
    }
    else
    {
        for (i = 0; i < this.hiddenSelects.length; i++)
        {
            var element = this.hiddenSelects[i];
            // is element intersesting?
             if (wdk.pos.intersect(divElmRect, element.m_elemRect, false))
            {
                element.m_element.style.visibility = "hidden";
            }
            else  // back to original state
            {
                element.m_element.style.visibility = element.m_visibility;
            }
        }
    }
}

/**
 * Show any select elements that were previously hidden
 */
AutoComplete.prototype.showHiddenIntersectingSelects = function()
{
    if (this.hiddenSelects != null )
    {
        for (i = 0; i < this.hiddenSelects.length; i++)
        {
            var element = this.hiddenSelects[i];
            element.m_element.style.visibility = element.m_visibility;
        }
        this.hiddenSelects = null;
    }
}

