// ---------
// common javascript to all form validators, basically holding cross-browser vars and error
// reporting functions.
// must be called before the validating js, i.e at the bottom of a component JSP page:
//
// if emailValidator.js is the validating js file for that page.
//
// @developer : tsiciliani@digitas.com

//--------------------------------------------------------------------------------------------
				// D E B U G G I N G
// -------------------------------------------------------------------------------------------


//DEBUGGING

// debug switch
var DEBUG = 0;
var _console;

// debug function
function debug(msg)
{
   		if(DEBUG == 0)
	   		return;

   		// open a window only once at a time
   		if(_console == null || _console.closed)
   		{
      		_console = window.open("","console","width=500,height=300,resizable,scrollbars");
	  		// open a doc to display text
	 		 _console.document.open("text/plain");
   		}
   		_console.document.writeln(msg);
}

//--------------------------------------------------------------------------------------------
					// I N I T
// -------------------------------------------------------------------------------------------

// make it cross-browser
var ns4, ns6, ie;
// ptr var
var topBlock;

// cross-browser indicators
ns4 = (document.layers) ? true : false ;
ie = (document.all) ? true : false ;
ns6 = (document.getElementById && ! document.all) ? true : false ;

// ptr var to the top DIV block
//if (ns4) topBlock = document.topMsgDiv;
//if (ie)  topBlock = topMsgDiv.style;
topBlock = document.getElementById("topMsgDiv");

//--------------------------------------------------------------------------------------------
				// E V E N T    H A N D L I N G
// -------------------------------------------------------------------------------------------

// capture enter key event in NS6
// why ? using tab key from last form field onto submit button will submit
// the form without err checking..
  if(ns6)
  {
    	function disableEnter(e)
		{
	  		return (e.keyCode == 13) ? false : true ;
		}

		document.addEventListener('keypress',disableEnter,true);
  }

  // capture onload event in ns4 so that eventual errors will not 'disappear' on page refresh
  if(ns4)
  {
	   window.captureEvents(Event.ONLOAD | Event.RESIZE);
	   // onload
	   window.onload = function(event) {  fixDIV();  };
       // onresize
	   window.onresize = function (evt) { fixDIV(); };

	   function fixDIV()
	   {
	   		// make the DIV visible only after the page is fully loaded, so we'll avoid
			// 'dancing' text across the screen..
	        topBlock.visibility = 'show';

			// write any existing error on top of the page after load
	   		if(currentErr != null && currentErr != '')
	       		writeOnTop( currentErr );
	   }

   }


//--------------------------------------------------------------------------------------------
				// E R R O R    H A N D L I N G
// -------------------------------------------------------------------------------------------

// ERRORS
var errors = new Array();
// previous error fields
var prevErrFields = new Array();
// current error fields
var errFields = new Array();
// current first error
var currentErr = '';


//-------------------------------------------------------
// Error handling function
// is called with a key, and any number of fields arguments
//   . error[errkey] is the message on top of the screen
//   . any field arg is the field to highlight in red
// No field arg means error is only displayed et the top of the page, with no field in red
// further down the page. Example : the 'tooManyFeatures' error.

function error(errkey)
{
        // loop through the args to get all error fields. Leave the first arg (errkey) out
  		for(var i = 1; i <arguments.length ; i++)
  		{
		    if(arguments[i] != null)
			{
			  // if the NAME attrib contains the '|' char, it's unusable. use ID attrib instead
			  // check for id first.
			  errFields[ i - 1] = (
			                           ( arguments[i].id == null || arguments[i].id == '' ) ?
	  		                            	arguments[i].name
							            		: arguments[i].id
								   );

			}
  		}

        currentErr = errors[errkey];
  		writeOnTop( currentErr );
        markFields( errFields );

}

//--------------------------------------------
// write an error msg (in red) on top of the screen
function writeOnTop(msg){
    layerWrite("topMsgDiv",'<SPAN CLASS=\'error\'>'+ msg +'</SPAN>');

		 // get back to where top msg is displayed so that user can see it
		/* ns6 ?
              window.scrollTo( parseInt(topBlock.style.left), parseInt(topBlock.style.top) )
  		 	   : window.scrollTo(topBlock.left, topBlock.top) ;	*/

    ns6 ? window.scrollTo( parseInt(0), parseInt(0) ) : window.scrollTo(0, 0);
}

//---------------------------------------------
// change error fields in red
function markFields(fields){
    var fieldsLabels = new Array();
    // first clear any prev error that was corrected by user by reverting font color
    for(var n =0; n <prevErrFields.length ; n++){
        // debug("prev err fields : " + prevErrFields[n]);
        for(var k = 0; k <fields.length; k++){
            if( prevErrFields[n] != fields[k] )
                changeColor( prevErrFields[n],"#000000" );
        }
    }

     // mark err field labels in red
    for(var i = 0; i < fields.length; i++){
        // debug("curr err fields : " + fields[i]);
        changeColor( fields[i],"#990000" );
        // store in prev
        prevErrFields[i] = fields[i];
    }

    /*###################################### reworked code */
    // mark err field labels in red
    for(var i = 0; i <fields.length; i++){
        if (fields[i].substr(0,7) == "arrival")	{
                fieldsLabels[i] = "checkIn";
        }
        else if (fields[i].substr(0,9) == "departure")	{
                fieldsLabels[i] = "checkOut";
        }
        else {
                fieldsLabels[i] = fields[i];
        }
    }

    for(var x = 0; x <fieldsLabels.length; x++){
        if (x == 0)	{
            changeColor( fieldsLabels[x],"#990000" );
            prevErrFields[x] = fieldsLabels[x];
        }
        else if (x>0 && (fieldsLabels[x] != fieldsLabels[x-1]))	{
            changeColor( fieldsLabels[x],"#990000" );
            prevErrFields[x] = fieldsLabels[x];
        }
        else	{
            prevErrFields[x] = fieldsLabels[x];
        }
    }
/*###################################### reworked code */
}

function markFieldStyle(fields){
    var fieldsLabels = new Array();
    // first clear any prev error that was corrected by user by reverting font color
    for(var n =0; n <prevErrFields.length ; n++){
        // debug("prev err fields : " + prevErrFields[n]);
        for(var k = 0; k <fields.length; k++){
            if( prevErrFields[n] != fields[k] )
                changeStyle( prevErrFields[n],"#000000" );
        }
    }

     // mark err field labels in red
    for(var i = 0; i < fields.length; i++){
        // debug("curr err fields : " + fields[i]);
        changeStyle( fields[i],"errorDisplay" );
        // store in prev
        prevErrFields[i] = fields[i];
    }

    /*###################################### reworked code */
    // mark err field labels in red
    for(var i = 0; i <fields.length; i++){
        if (fields[i].substr(0,7) == "arrival")	{
                fieldsLabels[i] = "checkIn";
        }
        else if (fields[i].substr(0,9) == "departure")	{
                fieldsLabels[i] = "checkOut";
        }
        else {
                fieldsLabels[i] = fields[i];
        }
    }

    for(var x = 0; x <fieldsLabels.length; x++){
        if (x == 0)	{
            changeStyle( fieldsLabels[x],"errorDisplay" );
            prevErrFields[x] = fieldsLabels[x];
        }
        else if (x>0 && (fieldsLabels[x] != fieldsLabels[x-1]))	{
            changeStyle( fieldsLabels[x],"errorDisplay" );
            prevErrFields[x] = fieldsLabels[x];
        }
        else	{
            prevErrFields[x] = fieldsLabels[x];
        }
    }
}





//---------------------------------------------
// DHTML layer writing
// tell it what layer to change, and what text to change it too:
// e.g :
// layerWrite("alayer", "a text here")

/*########################################## changed function*/
function layerWrite(id, text)
{


	if (ns4)
		rewriteLayer (id, text); // hack

	else if (ie && document.all[id])
	   document.all[id].innerHTML = text;

    else if (ns6 && document.getElementById(id))
       document.getElementById(id).innerHTML = text;

}

//-----------------------------------------------
// change to color desired

function changeColor(field, acolor ){

    var pid = field + "Label"; // e.g for 'zip' --> pid = 'zipLabel'
     //debug('Changing color for field ' + pid);
    if(ie){
        if(document.all[pid] != null && document.all[pid].style != null){
            document.all[pid].style.color = acolor;
        }
    }
    else if(ns6){
       if(document.getElementById(pid) != null && document.getElementById(pid).style != null)
                document.getElementById(pid).style.color = acolor;
    }
    else if(ns4){
        // NS 4.xx does not allow access to the inline style of elts like IE does
        // so we could use :
        // layerWrite(pid, '<SPAN CLASS=\'red\'>'+ 'Zip/Postal code' +'</SPAN>');
        // but this will require us to put a DIV tag around every field label and
        // hard-code all those labels like 'Zip/Postal code' to be able to write to the DIVs.

    }
}

function changeStyle(field, aStyle ){

    var pid = field + "Label"; // e.g for 'zip' --> pid = 'zipLabel'
     //debug('Changing color for field ' + pid);
    if(ie){
        if(document.all[pid] != null && document.all[pid].style != null){
//            alert("setting for: " + pid +" with " + aStyle);
            document.all[pid].className = aStyle;
        }
    }
    else if(ns6){
       if(document.getElementById(pid) != null && document.getElementById(pid).style != null){
//            alert("setting for: " + pid +" with " + aStyle);
           document.getElementById(pid).className = aStyle;
       }
    }
    else if(ns4){
        // NS 4.xx does not allow access to the inline style of elts like IE does
        // so we could use :
        // layerWrite(pid, '<SPAN CLASS=\'red\'>'+ 'Zip/Postal code' +'</SPAN>');
        // but this will require us to put a DIV tag around every field label and
        // hard-code all those labels like 'Zip/Postal code' to be able to write to the DIVs.

    }
}

//---------------------------------------------------


/*
   NN4's dhtml implementation has some bugs, in particular regarding
relatively positioned content. When you try to rewrite the content of
such an element with the standard
  var l = document['layerId'];
  l.document.open();
  l.document.write('some new content');
  l.document.close();
that new content might not show up or show up in the wrong place.
The workaround is to use a new Layer element placed on top of the
relatively positioned element and document.write to that new Layer
instead. We 'll just need to pass the layer id (or
the complete path to the layer for nested layers) and the new content
as the arguments.
*/

function rewriteLayer (idOrPath, html)
{
  	if (ns4)
  	{
    		var l = idOrPath.indexOf('.') != -1 ? eval(idOrPath)
             				: document[idOrPath];
			//width:400; height:100; clip:rect(0,400,100,0)
			/*l.width = 400; l.height = 100;
			debug('l.height =' + l.height );
			l.clip.top = 0;
			l.clip.right = 400;
			l.clip.bottom = 100;
			l.clip.left = 0; */

      	    if (!l.ol)
			{
      			var ol = l.ol = new Layer (l.clip.width, l);
      			ol.clip.width = l.clip.width;
      			ol.clip.height = l.clip.height;
				// debug('ol.clip.width=' + ol.clip.width + ' ol.clip.height=' + ol.clip.height); //
      			ol.bgColor = l.bgColor;
      			l.visibility = 'hide';
      			ol.visibility = 'show';
   			}
   			var ol = l.ol;
    	    ol.document.open();
    		ol.document.write(html);
    		ol.document.close();
  	}

}


//--------------------------------------------------------------------------------------------
				// M I S C
// -------------------------------------------------------------------------------------------

// check for illegal chars in all the formand their fields
var illegalCharStr = '<>{}[]~`$%^=?/\\\":;';

// if form has state pull down, set the country dynamically
var us_states = [ "AL","AP","AE","AA","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL",
	      		  "IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV",
	      		  "NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX",
	      		  "UT","VT","VA","WA","WI","WV", "WI","WY" ];

// candian : 16 st/prov
var ca_prov = ["AB","BC","LB","MB","NB","NF","NWT","NS","NU","ON","PI","PQ","PE","SK","YT"];
// australia : 8 st/prov
var aus_sp = ["ACT","NSW","NT","QLD","SA","TAS","VIC","WAU"];
// argentina : 24 st/prov
var arg_sp = ["BA","CA","CF","CH","CO","CR","CU","ER","FO","JU","LP","LR","ME","MI","NE","RN","SC","SE","SF","SJ","SL","TF","TU"];
//var arg_sp = ["BA","CA","CF","CH","CO","CR","CU","ER","FO","JU","LP","LR","ME","MI","NE","RN","SA","SC","SE","SF","SJ","SL","TF","TU"];
// brazil : 24 st/prov
var bra_sp = ["TO"];
//var bra_sp = ["AC","AL","AM","AP","BA","CE","DF","ES","GO","MG","MS","MT","PA","PB","PI","PR","RJ","RN","RO","RR","RS","SC","SP","TO"];
// mexico : 32 st/prov
var mex_sp	= ["AGS","BCN","BCS","CAMP","CHIH","CHIS","COAH","COL","DF","DGO","GRO","GTO","HGO","JAL","MEX","MICH","MOR","NAY","NL","OAX","PUE","QRO","QROO","SIN","SLP","SON","TAB","TAM","TLAX","VER","YUC","ZAC"];

// MISCELLANOUS: US TERRITORIES .IF they are in state drop-down, set the country to US..
// American Samoa (AS)
// Guam (GU)
// Federated States of Micronesia (FM)
// Marshall Islands (MH)
// Northern Marianas Islands (MP)
// Palau (PW)
// Puerto Rico (PR)
// Virgin Islands (VI)
var misc = ["AS", "GU", "FM", "MH", "MP", "PW", "PR", "VI"]; //@

var i = 0;
while(document.forms[i])
{
    var fm = document.forms[i];
	// trim & check for illegal chars entered
	var elts = document.forms[i].elements;
	if(elts != null)
	{
			for(var e = 0; e <elts.length ; e++)
			{
                // if the element is a checkin/checkout day, do not assign the blur declaration as it is set inline
                if((elts[e].className == 'dates') && (overRideOnblur)){
                    // do nothing
                }
                else{
                    checkField(elts[e]);
                }
			}
	}

	// try to cover all the different names used for country & state fields in all the forms.
	var country = (fm.countryCode != null) ? fm.countryCode : fm.country ;
	if(country == null) country = fm.shipToCountryCode;
	if(country != null )
	{
		// debug('In commErr::form ' + document.forms[i] + ' country exists');
		// these are the different field names used in the forms for state/prov
		if( fm.stateProvince != null && fm.stateProvince.options != null )
			setOnChange( fm, country, fm.stateProvince );
		if(fm.stateProvince1 != null && fm.stateProvince1.options != null )
			setOnChange( fm, country, fm.stateProvince1 );
		if(fm.shipToStateProvince != null && fm.shipToStateProvince.options != null )
			setOnChange( fm, country, fm.shipToStateProvince );
	}

	// try to cover all possible field names for zip used in the forms
	var zip = (fm.postalCode != null) ? fm.postalCode : fm.zipPostalZone ;
	if(zip == null) zip = fm.zipPostalCodeID;
	if(zip == null) zip = fm.shipToPostalZone;
	if(zip != null && country != null)
	{  /* commented out because of CQ2477
	   zip.onchange = function(){ setCountryFromZip(fm,country,zip); }
	   */
	}

	fm.onsubmit = function(){
			//debug('ONSUBMIT evt handler called in commonErr.js !');
			// trim & check for illegal chars entered once again, to make sure user doesn't
			// go ahead and submit the form anyway..
			if(elts != null)
			{
					for(var e = 0; e <elts.length ; e++)
					{
						//debug('OnSubmit:Verifying elt ' + elts[e].name);
						trim(elts[e]);
						if( ! checkIlleg(elts[e]) )
							return false;
					}
			}
			return true;
			}


	++i; // next form
}

//-------------------------------------------------------------------------
// trim leading and trailing whitespace
function trim(elt)
{
	if(elt.type != 'text' && elt.type != 'password')
		return true;

	var va = elt.value;

	// trim trailing spaces
	while('' + va.charAt(0) == ' ' )
		va = va.substring(1, va.length);

	// trim leading spaces
	while('' + va.charAt(va.length-1) == ' ')
		va = va.substring(0, va.length-1);

	// display trimmed value back to user
	elt.value = '';
	elt.value = va;
	//debug('Trimmed value is ' + va);
}

//--------------------------------------------------------------------------
// trim fields & check for illegal chars in fields at soon as elt changes
function checkField(elt){
    elt.onblur = function(){ trim(elt); checkIlleg(elt); }
}

function checkIlleg(elt)
{
	if(elt.type != 'text' && elt.type != 'password' && elt.type != 'textarea')
		return true;

	var va = elt.value;
	// for text area illegal chars are only a subset
	// '<>{}[]~`$%^*=?/\\\"\':;'  --> '<>{}'

	//dkersting(7.18.03): added streetAddress check to allow the character "/".
	var origIllegalCharStr = illegalCharStr;
	if(elt.name == 'streetAddress1' || elt.name == 'streetAddress2' || elt.name == 'guestAddress1' || elt.name == 'guestAddress2')
		illegalCharStr = illegalCharStr.replace("/", "");
	//dkersting(7.18.03): end

	if(elt.type == 'textarea')
		illegalCharStr = illegalCharStr.slice(0,4);

	//alert(elt.name);
	//alert(illegalCharStr);

	//debug('illegalCharStr is ' + illegalCharStr );

	var stripped = stripCharsInBag (va, illegalCharStr);
	if(va != '' && stripped.length <va.length)
	{
		error('illegalChars', elt);
		return false;
	}
	//dkersting(7.18.03): reset illegalCharStr to it's original subset of illegal chars.
	illegalCharStr = origIllegalCharStr;
	//dkersting(7.18.03): end
	return true;
}

//--------------------------------------------------------------------------

// set an onchange evt hdler for a given state field from the first state value
// up to the number of states/prov ex : US ->52, CAN ->13

function setOnChange(fm, ctry, stateField )
{
		if( stateField == null || ctry == null
			|| stateField.options == null || stateField.selectedIndex == null)
			return;

	  // debug('ctry field is ' + ctry + ' and ctry val is '+
	   			//( (ctry.options == null) ? ctry.value : ctry.options[ctry.selectedIndex].value ) );//

	   stateField.onchange = function() { setCountry( ctry, stateField); }
	   ctry.onchange = function() { clearStateProv( ctry, stateField ); }

}

//----------------------------------------------------------------------------
// dynamically set the country given the state/Prov

function setCountry( ctry, stateProv )
{
        if( stateProv == null || ctry == null)
			return;

	  var state = stateProv.options[stateProv.selectedIndex].value;

		if(  isIn(state, us_states) || isIn(state, misc) ) //@
			setCountryValue(ctry,'US');
		else if (  isIn(state, ca_prov) )
			setCountryValue(ctry,'CA');
		else if (  isIn(state, arg_sp) )
			setCountryValue(ctry,'AR');
		else if (  isIn(state, aus_sp) )
			setCountryValue(ctry,'AU');
		else if (  isIn(state, bra_sp) )
			setCountryValue(ctry,'BR');
		else if (  isIn(state, mex_sp) )
			setCountryValue(ctry,'MX');
		else
			setCountryValue(ctry,''); //@

}
//--------------------------------------------------

function isIn(elt, list)
{
	   if(elt == null || list == null)
	   		return false;

	   for( var ix =0; ix <list.length ; ix++)
	  		 if( list[ix] == elt )
			 {
				return true;
			 }

	   return false;
}

//---------------------------------------------------

function setCountryValue (ctry,val)
{
    if(ctry == null)
			return;

	if(ctry.options != null) // country is a drop-down
	{
		for( var n =0; n <ctry.options.length ; n++)
			if( ctry.options[n].value == val )
			{
				ctry.selectedIndex = n;
				//debug('In commErr::setCountry(), set country ' + val + ' from State selected');//
				break;
			}
	}
	else // country is a text field
		ctry.value = val;
}
//----------------------------------------------------
// if country is not US/CA , clear the stateProv field
function clearStateProv(ctry, stateField)
{
	if(ctry == null || ctry.options == null || stateField == null)
			return;

	var cntry = ctry.options[ ctry.selectedIndex ].value ;
	var state = stateField.options[stateField.selectedIndex].value;

	if(cntry != 'US' || cntry != 'CA')   //@
			stateField.selectedIndex = 0;

//if(cntry != 'US' || cntry != 'CA' || cntry != 'AU' || cntry != 'BR' || cntry != 'MX' || cntry != 'AR' )   //@
	//		stateField.selectedIndex = 0;
}
//------------------------------------------------------


// non-digit characters which are allowed in ZIP Codes
var ZIPCodeDelimiters = "- ";
// U.S. ZIP codes have 5 or 9 digits.
// They are formatted as 12345 or 12345-6789.
var digitsInZIPCode1 = 5;
var digitsInZIPCode2 = 9;


// The postal code will be validated against US patterns and if it passes, US will be sent
// as the country.  If not, it will be validated against Canadian
// patterns.  If it passes, CA will be sent as the country.  If it fails, nothing happens.//@

function setCountryFromZip(fm,country,zip)
{
    if(country == null || country.options == null || zip == null)
		return;

   if( isUSZip(zip) )
   		setCountryValue(country,'US');

   else if ( isCAZip(zip) )
   		setCountryValue(country,'CA');

  // else
   		//setCountryValue(country,''); //@
}

//------------------------------------------------

function isUSZip(field)
{
   v = stripCharsInBag(field.value, ZIPCodeDelimiters);
   // debug('In commonErr::isUSZip() zip is ' + v + ' and length is ' + v.toString().length );

   if( isNaN(v)
		   || (v.length != digitsInZIPCode1 && v.length != digitsInZIPCode2) )
	  return false;

   return true;

}

//--------------------------------------------------

/*
   from :
   http://www.canadapost.ca/CPC2/addrm/pclookup/pcinfo.html#pci

'Canadian postal codes are always listed in the same format: K1A 0B1, for example.
The sequence is always  letter/number/letter (full space) number/letter/number.
Precisely:
. first character always a letter other than W or Z
. D, F, I, O, Q, U  are never used in Canadian postal codes.

*/

function isCAZip(field)
{
    v = stripCharsInBag(field.value, ZIPCodeDelimiters);
	// debug('In commonErr::isCAZip() zip is ' + v + ' and length is ' + v.toString().length );

	var regexp = /^[A-Va-v]|[X,Y,x,y]\d[A-Za-z]\d[A-Za-z]\d$/;

	if( v.length != 6 || hasChars(v,'D', 'F', 'I', 'O', 'Q', 'U') || v.search(regexp) == -1 )
		return false;

	return true;

}
//------------------------------------------------------
                 // utility functions
//-------------------------------------------------------


// parse dates
function parser(input)
{
  		if(input == null || input == '')
     		return null;

  		// input format is yyyy-mm-dd
		s1 = input.indexOf('-');
		s2 = input.lastIndexOf('-');
		if(s1 == -1 || s2 == -1)
		{
		   // debug('Dates are in wrong format !!');
		   return null;
		}
		y = input.substr(0,4);
		m = input.substr(s1 + 1 ,2);
		d = input.substr(s2 + 1,2);

   		// debug('From parser : ' + y + ' ' + m + ' ' +  d);

		// get rid of possible leading zero, otherwise in '0d' we'll get '0' instead of 'd'
		// when m & d will be converted to ints in Netscape(4 &6).
		m = stripZero(m), d = stripZero(d);

		return [ y, m, d ];
}

//-----------------------------------------------
// strip leading zero, if any.
function stripZero(s)
{
   if(s.charAt(0) == '0')
      s = s.substr(1);

   return s;
}
//-----------------------------------------------
// padd a zero if string is one char
function paddZero(s)
{
	//if(s.length ==1)
    if(s >= 0 && s <= 9)
	  s = '0' + s;

	return s;
}

//-------------------------------------------------
// Removes all characters which appear in string bag from string s.

function stripCharsInBag (s, bag)

{   var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.

    for (i = 0; i <s.length; i++)
    {
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }

    return returnString;
}

//---------------------------------------------------------
// check for any number of case insensitive letters(variable args) in a given string

function hasChars( str )
{
    if(str == null)
		return false;

	str = str.toLowerCase();

	for(var i = 1; i <arguments.length ; i++)
	{
	      arguments[i] = arguments[i].toLowerCase();
	      if( str.indexOf( arguments[i] ) != -1 )
		  		return true;
	}

	return false;
}

//------------------------------------------------------------
function isInteger(s){
    var re = /^\d+$/
    return (s.search(re) == -1) ? false : true ;
}

