/*
* @(#)autocomplete.js $Revision: 1.6.2.1 $ $Date: 2008/06/19 12:37:15 $
*
* Copyright Navis Corporation 2003
* All Rights Reserved
*
* Confidential Information of Navis Corporation
* Unauthorized use is strictly prohibited
*
* This work contains valuable confidential proprietary trade secret
* information of Navis Corporation and is protected by specific
* agreements and federal copyright. This work or any part thereof
* may not be disclosed, transmitted, copied, or reproduced in any
* form or medium without prior written authorization from Navis
* Corporation.
*/

/*
* autocomplete implements the LOV class of object used in N4 in the
*	place of the standard select box.
*
* @version $Revision: 1.6.2.1 $ $Date: 2008/06/19 12:37:15 $
* @author: Darren Luvaas
*/

/************************************************************************/
/**** Used by form inputs to autocomplete data entry by loading      ****/
/**** strings from an associated <select> input.                     ****/
/****                                                                ****/
/************************************************************************/
/****                                                                ****/
/**** This file depends upon the following JavaScript files:         ****/
/****   -common.js                                                   ****/
/****   -browserSniff.js                                             ****/
/****   -ieEmulation.js                                           	 ****/
/****   -imageSwap.js                                            		 ****/
/****                                                                ****/
/************************************************************************/

/************************************************************************/
/**** GLOBAL VARIABLES                                               ****/
/************************************************************************/

//objects
var Lovs           = new Object();
var LovTxtInputs   = new Object();
var LovsArray      = new Array();
var LovTxtInputsArray = new Array();

//images
var defaultLovButtonSrc = commonImgRoot + 'buttons/inputWidgets/lovDrop.gif';
var defaultLovButtonActiveSrc = commonImgRoot + 'buttons/inputWidgets/lovDrop_down.gif';
var defaultLovButtonDisabledSrc = commonImgRoot + 'buttons/inputWidgets/lovDrop_disabled.gif';

//parameters
var defaultLovMaxSize       = 10;
var defaultLovValidate      = false;
var restrictLovWidth        = false;   //restrict the width of the LOV to the width of the srcInput, no matter how wide its content
var defaultLovValidate      = false;   //false allows users to enter values not in the list.  true forces users to enter only items from the list.
var defaultLovFilterList    = true;    //true will filter out items in the LOV when they don't match typed value.
var defaultLovShadowNudgeX  = 5;
var defaultLovShadowNudgeY  = 5;
var defaultLovShowHiddenVal = false    //true will display the submit value in the text input in lieu of the text value
var useLovShadow = ((is.win && is.ie6up) || is.moz5up) ? true : false;  //these browsers can use alpha


/************************************************************************/
/**** CONSTRUCTORS                                                   ****/
/************************************************************************/
function Lov(id) //constructor
{
  //TODO: add support for filterlist;
  //TODO: when showHiddenVal==true, replace the typed value with the hidden value
  //properties
  this.id = id;
  this.selectObj  			= 'undefined';
  this.inputObj   			= 'undefined';
  this.buttonObj  			= 'undefined';
  this.buttonObjImg         = 'undefined';
  this.buttonObjImgSrc      = 'undefined';
  this.buttonObjImgSrcA     = 'undefined';
  this.hiddenObj  			= 'undefined';
  this.shadow     			= new LovShadow(this.id);
  this.txt        			= new LovText(this.id);
  this.isVisible  			= false;
  this.hasDependent	  	    = false;
  this.maxSize    			= null;
  this.ValArray   			= new Array();
  this.TxtArray   			= new Array();
  this.validateMe 			= false;
  this.showHiddenVal        = false;

  //methods
  this.open                   = lovOpen;
  this.close                  = lovClose;
  this.unselectOptions        = lovUnselectOptions;
  this.validate               = lovValidate;
  this.updateInput            = lovUpdateInput;
  this.toggle                 = lovToggle;
  this.cancelAutoComplete     = lovCancelAutoComplete;
  this.upArrow                = lovUpArrow;
  this.downArrow              = lovDownArrow;
  this.autoComplete           = lovAutoComplete;
  this.findMatchingIndex      = lovFindMatchingIndex;
  this.updateHidden           = lovUpdateHidden;
}

function LovShadow(id) //constructor
{
  this.obj    = makeShadow(id + "Shadow");
  this.nudgeX = 0;
  this.nudgeY = 0;

  //methods
  this.setPosition = lovSetShadowPosition;
  this.show        = lovShowShadow;
  this.hide        = lovHideShadow;
  this.useShadow   = useLovShadow;
}

function LovText(id) //constructor
{
  this.defaultClassName = '';
  this.prevTxt = '';
  this.typedTxt = '';
}

/************************************************************************/
/**** DOM EVENTS                                                     ****/
/************************************************************************/
function lovSelectOnChange(e)
{
  var obj = getSrcEl(e);
  var oLov = getLov(obj.id);
  if(oLov.hasDependent && window.reSetOptions)
  {
    reSetOptions(obj)
  }
  oLov.updateInput();
}

function lovSelectOnClick(e)
{
  var obj = getSrcEl(e);
  var obj = getParentEl(obj,'SELECT','TD');
  var oLov = getLov(obj.id);

  oLov.close();
  oLov.validate();
}

function lovInputOnClick(e)
{
  var obj = getSrcEl(e);
  var oLov = getLov(obj.getAttribute('lov'));

  oLov.toggle();
}

function lovButtonOnClick(e)
{
  var imgObj = getSrcEl(e);
  var obj = getParentEl(imgObj,'A','BODY');
  var oLov = getLov(obj.getAttribute('lov'));
  oLov.toggle();
}

function lovInputOnBlur(e)
{
  var obj = getSrcEl(e);
  var oLovAtt = obj.getAttribute('lov');
  var oLov = getLov(oLovAtt);

  oLov.validate();
  oLov.updateHidden();
  if(!is.ie && !is.safari)
  {
    //clear specific selection, if any
    selectText(oLov.inputObj,oLov.inputObj.value.length,oLov.inputObj.value.length)
    //this.inputObj.select();
  }
  if(oLov.isVisible){
    var LovTimer = setTimeout('getLov(\'' + oLovAtt + '\').close();',200); //brief pause that lets user click on LOV before closing in Moz
  }
}

function lovInputOnKeyPress(obj,maxLen,e)
{
  var returnValue = true;
  //this function is used to intercept enter key, esc, and arrow keys
  //backspace-8;tab-9;delete-46;escape-27;down arrow-40;right arrow-39;up arrow-38;left arrow-37
  if((e.keyCode == 8)||(e.keyCode == 9)||(e.keyCode == 46)||(e.keyCode == 27)||(e.keyCode == 39)||(e.keyCode == 37))
  {
       returnValue = true;
  }else{
  var textLen = obj.value.length;
  //var e = getEvent(e);
  var obj = getSrcEl(e);
  var oLov = getLov(obj.getAttribute('lov'));
  var selectText = ''; 
  if (document.selection)  //For IE  
  {
   selectText = document.selection.createRange().text;
  }else if(obj.setSelectionRange)       //For FireFox
  {
  var Length = obj.textLength;
  var Start = obj.selectionStart;
  var End = obj.selectionEnd;
   if (End>0 && (End - Start > 0))
   {
   selectText = (obj.value).substring(Start, End);
   }
  }
  var selectTextLen = selectText.length;
  var diffLen = textLen - selectTextLen;

  //intercept and block the return/enter key
  if(e.keyCode == 13 && oLov.isVisible)
  {
    oLov.cancelAutoComplete()
    cancelEventPropagation(e);
    //this.inputObj.select();
  }
  else if(e.keyCode == 27 && oLov.isVisible)
  {
    //intercept and block the esc key
    oLov.inputObj.value = oLov.txt.typedTxt;
    oLov.cancelAutoComplete()
    cancelEventPropagation(e);
  }
  //Arrow keys are handled in onKeyDown, so cancel them here.
  if (e.keyCode == 38 || e.keyCode ==40) //arrow up/down
  {
    cancelEventPropagation(e);
    return;
  }
  if(maxLen != 0 && diffLen >= maxLen && textLen >= maxLen)
  {
     returnValue=false;
  }
  }
  return returnValue;
}

function lovInputOnKeyDown(e)
{
  var e = getEvent(e);
  var obj = getSrcEl(e);
  var oLov = getLov(obj.getAttribute('lov'));

  if (e.keyCode == 38) //arrow up
  {
    oLov.upArrow();
    cancelEventPropagation(e);
    return;
  }
  else if (e.keyCode == 40) //arrow down
  {
    oLov.downArrow();
    cancelEventPropagation(e);
    return;
  }
}

function lovInputOnKeyUp(e)
{
  var e = getEvent(e);
  var obj = getSrcEl(e);
  var oLov = getLov(obj.getAttribute('lov'));

  oLov.autoComplete(e);
}

/************************************************************************/
/**** FUNCTIONS                                                      ****/
/************************************************************************/
function initLov(id)
{
  if (!document.getElementById(id))
  {
    alert('Cannot initialize Autocomplete Widget.');
    return;
  }
  var oSelect = document.getElementById(id);
  var oInputId  = oSelect.getAttribute('lovInput');
  var oButtonId = oSelect.getAttribute('lovDropButton');
  var oHiddenId = oSelect.getAttribute('lovHidden');
  var oLov;

  if(!document.images['defaultLovButtonActive'])
  {
    var oImg_a = new Image();
    oImg_a.id = "defaultLovButtonActive";
    oImg_a.src = defaultLovButtonActiveSrc;
  }

  if(!document.images['defaultLovButtonDisabled'])
  {
    var oImg_d = new Image();
    oImg_d.id = "defaultLovButtonDisabled";
    oImg_d.src = defaultLovButtonDisabledSrc;
  }

  if(!document.images['defaultLovButton'])
  {
    var oImg_i = new Image();
    oImg_i.id = "defaultLovButton";
    oImg_i.src = defaultLovButtonSrc;
  }

  Lovs[id] = new Lov(id);
  LovsArray[LovsArray.length] = Lovs[id];
  oLov = Lovs[id];

  for(i=0; i<oSelect.options.length; i++)
  {
    oLov.ValArray[i] = oSelect.options[i].value;
    oLov.TxtArray[i] = oSelect.options[i].text;
  }
  oLov.selectObj        = oSelect;
  oLov.inputObj         = document.getElementById(oInputId);
  oLov.buttonObj        = document.getElementById(oButtonId);
  oLov.buttonObjImg     = oLov.buttonObj.firstChild; //should be the <a> link's child image.
  oLov.buttonObjImgSrc  = oLov.buttonObjImg.src;
  oLov.buttonObjImgSrcA = defaultLovButtonActiveSrc;
  oLov.hiddenObj        = document.getElementById(oHiddenId);

  if (!oLov.selectObj || !oLov.inputObj || !oLov.buttonObj || ! oLov.hiddenObj)
  {
    alert('Cannot initialize Autocomplete Widget.');
    return;
  }

  if(oLov.inputObj.disabled)
  	{
  	oLov.buttonObjImgSrc = oImg_d.src;
  	}
  else
		{
		oLov.buttonObjImgSrc = oImg_i.src;
		}

	// 	initialize the classname as well so that it will lose the error class.
	curClassName = oLov.inputObj.className;
  oLov.inputObj.className = curClassName.replace(/ inputError/,'');

  //TODO: when the LOV is initialize at onload, then set the input height to match the button height.
  //oLov.inputObj.style.height = oLov.buttonObjImg.offsetHeight + "px";
  oLov.validateMe = (oSelect.getAttribute('lovValidate')) ? oSelect.getAttribute('lovValidate') : defaultLovValidate;
  oLov.maxSize = (oSelect.getAttribute('lovMaxSize')) ? oSelect.getAttribute('lovMaxSize') : defaultLovMaxSize;
  oLov.shadow.nudgeX = (oSelect.getAttribute('lovShadowNudgeX')) ? oSelect.getAttribute('lovShadowNudgeX') : defaultLovShadowNudgeX;
  oLov.shadow.nudgeY = (oSelect.getAttribute('lovShadowNudgeY')) ? oSelect.getAttribute('lovShadowNudgeY') : defaultLovShadowNudgeY;
  oLov.txt.defaultClassName = oLov.inputObj.className;
  oSelect.size = (oSelect.options.length > oLov.maxSize) ? oLov.maxSize : oSelect.options.length;
  oLov.showHiddenVal = (oSelect.getAttribute('lovShowHiddenVal')) ? oSelect.getAttribute('lovShowHiddenVal') : defaultLovShowHiddenVal;

  if((oSelect.getAttribute('lovUseShadow')) != null)
    oLov.shadow.useShadow = eval(oSelect.getAttribute('lovUseShadow'));

}

function getLov(id)
{
  if (!Lovs[id])
  {
    initLov(id);
  }
  return Lovs[id];
}

function lovUpdateInput()
{
  this.inputObj.value = this.selectObj.options[this.selectObj.selectedIndex].text;
  this.inputObj.focus();
}

function lovUnselectOptions()
{
  //make sure no Lov options are selected.
  this.selectObj.selectedIndex = -1;
}

function lovUpdateHidden()
{
  var matchingIndex = this.findMatchingIndex();

  if (matchingIndex > -1)
  {
    this.hiddenObj.value = this.selectObj.options[matchingIndex].value;
  }
  else
  {
    this.hiddenObj.value = this.inputObj.value;
  }
}

function lovFindMatchingIndex()
{
  for (var i=0; i<this.TxtArray.length; i++)
  {
    //find a starting string that matches the typed string.  If validate is on, ignore case, otherwise comparison is case-sensitive.
    var lovCompString1 = (this.validateMe) ? this.TxtArray[i].toUpperCase() : this.TxtArray[i];
    var lovCompString2 = (this.validateMe) ? this.inputObj.value.toUpperCase() : this.inputObj.value;
    if (lovCompString1.indexOf(lovCompString2,0) == 0)
    {
      return i;
    }
  }
  return -1;
}

function lovAutoComplete(e)
{
  var match = false;
  var changesFound;

  this.txt.typedTxt = this.inputObj.value;

  //store current value of the input for comparison
  changesFound = (this.txt.prevTxt == this.txt.typedTxt) ? false : true;

  //TODO: if changes are made as a result of pasting or other mechanism, start autocomplete and don't return.  Not sure how to do this.
  this.txt.prevTxt = (!changesFound) ? '' : this.txt.typedTxt;
  if (!changesFound)  //if no change to the input (i.e., some key other than a character key was hit)
  {
   return;
  }

  var KeyCodeArray = new Array(13,16,9,27,37,38,39,40,17,18);
  //if modifyer keys are being used
  //Enter, Shift, Tab, Esc, Ctrl, Alt, arrow keys are being handled elsewhere, so return
  for (k=0; k<KeyCodeArray.length; k++)
  {
    if (e.altKey || e.ctrlKey || e.keyCode == KeyCodeArray[k]) return;
  }

  //abort if delete/backspace
  if ((is.safari && e.keyCode == 127) || (!is.safari && (e.keyCode == 46 || e.keyCode == 8)))
  {
    this.close();
    return;
  }

  for (var i=0; i<this.TxtArray.length; i++)
  {
    //find a starting string that matches the typed string.  If validate is on, ignore case, otherwise comparison is case-sensitive.
    var lovCompString1 = (this.validateMe) ? this.TxtArray[i].toUpperCase() : this.TxtArray[i];
    var lovCompString2 = (this.validateMe) ? this.txt.typedTxt.toUpperCase() : this.txt.typedTxt;
    if (lovCompString1.indexOf(lovCompString2,0) == 0)
    {
      match = true;
      break;
    }
  }

  if (match)
  {
    if((is.ie5up && is.win) || is.mozilla|| is.safari)
    {
      //send autocomplete text to the field
      this.inputObj.value = this.TxtArray[i];
      selectText(this.inputObj,this.txt.typedTxt.length,this.inputObj.value.length);
    }
    this.open();
    this.selectObj.options[i].selected = true;
  }
  else if (this.validateMe)
  {
    //if input requires validation, always open the LOV immediately, regardless of whether or not there is a match.
    this.open();
  }
  else
  {
    this.close();
  }
}

function selectText(obj,startRange,endRange)
{
  if (typeof obj.selectionStart != 'undefined') //Mozilla
  {
    obj.setSelectionRange(startRange, endRange);
  }
  else if(obj.createTextRange) //IE on PC
  {
    var oRange = obj.createTextRange();
    oRange.moveStart('character', startRange);
    oRange.moveEnd('character', endRange);
    oRange.select();
  }
}

function lovOpen()
{
	if (this.isVisible || this.inputObj.disabled) return;
	var x,y,w;

  //reset LOV's width
  this.selectObj.style.width = "";

  if(restrictLovWidth || this.selectObj.offsetWidth < this.inputObj.offsetWidth + this.buttonObjImg.offsetWidth)
  {
    //If LOV width is restricted or the LOV is shorter than the associated text input, make the LOV same size as text input
    w = this.inputObj.offsetWidth;
  }
  else
  {
    w = this.selectObj.offsetWidth;
  }
  //account for the width of the associated buttonObjImg
  w += this.buttonObjImg.offsetWidth;

  // Need to retrieve relative position because setting style top/left places the object
  // relative to the edge of the next positioned object.
  this.selectObj.style.width = w + "px";
  this.selectObj.style.top = getRelY(this.inputObj) + this.inputObj.offsetHeight + "px";
  this.selectObj.style.left = getRelX(this.inputObj) + "px";
  this.selectObj.style.display = "inline";
  this.isVisible = true;

  this.inputObj.className += " lovInput_active";

  x = getElX(this.selectObj);
  y = getElY(this.selectObj);

  this.shadow.setPosition(x,y,w,this.selectObj.offsetHeight);
  this.shadow.show();
  this.unselectOptions();
  this.buttonObjImg.src = this.buttonObjImgSrcA;
}

function lovClose()
{
  if (!this.isVisible) return;

  var curClassName = this.inputObj.className;

  this.isVisible = false;
  this.unselectOptions();
  this.inputObj.className = curClassName.replace(/ lovInput_active/,'');
  this.selectObj.style.display = "none";
  this.shadow.hide();
  this.buttonObjImg.src = this.buttonObjImgSrc;
}

function lovValidate()
{
  //determine if the typed value matches a value from the select list
  if (!this.validateMe) return;

  var isValid = false;

  for (var i=0; i<this.TxtArray.length; i++)
  {
    //find a valid string that matches the typed string exactly

    if (this.TxtArray[i] == this.inputObj.value)
    {
      isValid = true;
      break;
    }
  }
  if (isValid == false)
  {
    this.inputObj.className = this.txt.defaultClassName + " inputError";
  }
  else this.inputObj.className = this.txt.defaultClassName;
}

function lovSetShadowPosition(x,y,w,h)
{
  if (!this.useShadow)
  {
    return;
  }
  var myLovShadow = this.obj;
  myLovShadow.style.left   = parseInt(x) + parseInt(this.nudgeX) + "px";
  myLovShadow.style.top    = y + "px";
  myLovShadow.style.width  = w + "px";
  myLovShadow.style.height = parseInt(h) + parseInt(this.nudgeY) + "px";
}

function lovShowShadow()
{
  if (this.useShadow)
  {
    this.obj.style.visibility = "visible";
  }
}

function lovHideShadow()
{
  if (this.useShadow)
  {
    this.obj.style.visibility = "hidden";
  }
}

function getTxtInput(srcInput,oLov)
{
  if (!LovTxtInputs[this.inputObj.id])
  {
    LovTxtInputs[this.inputObj.id] = new TxtInput(srcInput,oLov);
    LovTxtInputsArray[LovTxtInputsArray.length] = LovTxtInputs[this.inputObj.id];
  }
  return LovTxtInputs[this.inputObj.id];
}

function lovToggle()
{
  if (!this.isVisible)
  {
    this.open();
  }
  else
  {
    this.close();
  }
}

function lovCancelAutoComplete()
{
  if (this.isVisible)
  {
    this.close();
    this.validate();
    //clear selection, if any
    selectText(this.inputObj,this.inputObj.value.length,this.inputObj.value.length);
  }
}

function lovUpArrow()
{
  if(!this.isVisible)
  {
    return;
  }
  var selIndex = this.selectObj.selectedIndex;
  var nextIndex = selIndex-1;

  if (selIndex != 0)
  {
    this.selectObj.options[nextIndex].selected = true;
    this.selectObj.options[selIndex].selected = false;
    this.inputObj.value = this.TxtArray[nextIndex];
  }
  this.inputObj.select();
}

function lovDownArrow()
{
  //if the LOV is closed, open it
  var selIndex = this.selectObj.selectedIndex;
  var nextIndex = selIndex+1;

  if(!this.isVisible)
  {
    this.open();
  }
  if (this.selectObj.selectedIndex < this.selectObj.options.length -1)
  {
    this.selectObj.options[nextIndex].selected = true;
    this.selectObj.options[selIndex].selected = false;
    this.inputObj.value = this.TxtArray[nextIndex];
  }
  this.inputObj.select();
}

function LovPageClick(e)
{
  //Hide all LOVs on a page click unless the lovToggle button was the object that generated the event.
  var srcObj,isLov;

  srcObj = getSrcEl(e);
  srcObj = (srcObj.tagName == "IMG") ? getParentEl(srcObj, "A", "BODY") : srcObj;
  isLov = (srcObj.getAttribute('lov')) ? true : false;

  for (var i=0; i<LovsArray.length; i++)
  {
    if ((isLov && srcObj.getAttribute('lov') != LovsArray[i].id) || !isLov)
    {
      LovsArray[i].close();
      LovsArray[i].validate();
    }
  }
}

function validateLov(form){
	
	for (i=0; i<form.elements.length; i++){

		element = form.elements[i]
		
		if (element.type=="select-one" && element.name.indexOf("_Lov") > 0){	
				
			var input = document.getElementsByName(element.name + "_input").item(0);
			trimmedInput = trim(input.value)
			
			if (trimmedInput.length <= 0)
			{
				continue;
			}

			bLovFound = false;

			for(j=0; j<element.length; j++)
			  {
                  lovId = element.options[j].value;
				  if (lovId.toUpperCase() == trimmedInput.toUpperCase()) {
				  	bLovFound = true;
				  	continue;
				  }
				  
                  lovText = element.options[j].text;
				  if (lovText.toUpperCase() == trimmedInput.toUpperCase()) {
					bLovFound = true;
					continue;
				  }
              }

			if (!bLovFound) {
				lovLabel = input.getAttribute('lovLabel');
				alert ("Please select a valid " + lovLabel);
				input.focus();
				return false;
			}
		}

	}

	form.submit();
}


function trim(str)
{
	return str.replace(/^\s*|\s*$/g,"");
}
