/** Method that allows a calling function to explicitly
 * define a context that it wishes to execute in.
 * @param {Object} obj
 */
Function.prototype.bindObj = function(obj){
	//Handle to the calling function
	var method=this;

	//anonymous function that will execute the calling function
	//within the scope of the explicitly defined object
	scopeClosure = function(){
		//apply is a javascript method that immediately executes
		//a method in the scope of an explicitly defined object
		//this can not be directly invoked outside of the closure though
		//because we only want the method to be invoked when externally called
		//and not as the code is parsed by the browser.
		return method.apply(obj,arguments);
	};

	//reference to the call that executes in the second objects context
	return scopeClosure;
}

/** Class that deals with all client side locale switching issues for the TSS
 * Expext this class to be part of a call back from an ajax call as part of
 * switching languages on the page
 * @param {String} languageString
 */
function LocaleElement(languageString){
	//Class Variables
	var language = languageString;
	var frenchElement = document.getElementById("language:fr");
	var englishElement = document.getElementById("language:en");

	//Getter such that page language is globally available
	this.getLanguage = function(){
		return language;
	}

	/**
	 * Method that will verify the existence of the language selection
	 * page elements and then toggle them accordingly.  This is
	 * currently being updated via a basic remoting call.
	 */
	this.setLocaleStyle = function(){


		if (frenchElement === null ||
			englishElement === null) {
			return;
		}

		if (language == "fr"){

			frenchElement.className="current";
			frenchElement.disabled=true;
			frenchElement.href="#";
			frenchElement.onclick='return false;';
			frenchElement.style.cursor='text';
			frenchElement.style.textDecoration='none';

			englishElement.className="";
			englishElement.style.textDecoration='none';

		} else {
			frenchElement.className="";
			frenchElement.style.textDecoration='none';

			englishElement.className="current";
			englishElement.disabled=true;
			englishElement.href="#";
			englishElement.onclick='return false;';
			englishElement.style.cursor='text';
			englishElement.style.textDecoration='none';
		}
	}

	/**
	* Method to be used after an ajax call to verify the locale has not changed
	* in another location
	*/
	this.switchLocale = function(externalLink){
		/*alert(document.getElementById('TireDetails:localeSwitch').value);
		if (document.getElementById('TireDetails:localeSwitch').value == "true"){
			alert(document.getElementById('language:fr'));
			//document.getElementById('language').submit();
			Seam.Component.getInstance("tssDetailsBean").switchDetailsLocale(this.refreshPage.bindObj(localeElement));
		}*/
	}

	this.refreshPage = function(){
		//document.getElementById('language').submit();
	}
}

function updateLocaleCallback(language){
	//alert("updateLocaleCallback: conversation id set to:" + Seam.Remoting.getContext().getConversationId());
	localeElement = new LocaleElement(language);
	localeElement.setLocaleStyle();
}


function doTab(tab_number, catLink ) {

	if( isIE() ){
		if( catLink ){
			var t = document.getElementById( tab_number );
			if( t ){
				var l = t.children[0];
				if( l ){
					l.onclick();
					return false ;
				}
			}
		}
	}

	if (document.getElementById('tab_0F') != null){
		document.getElementById('tab_0F').className='off';
	}

	if (document.getElementById('tab_0R') != null){
		document.getElementById('tab_0R').className='off';
	}

	if (document.getElementById('tab_0B') != null){
		document.getElementById('tab_0B').className='off';
	}

	if (document.getElementById('tab_1F') != null){
		document.getElementById('tab_1F').className='off';
	}

	if (document.getElementById('tab_1R') != null){
		document.getElementById('tab_1R').className='off';
	}

	if (document.getElementById('tab_1B') != null){
		document.getElementById('tab_1B').className='off';
	}

	// these are for the details page
	if (document.getElementById('tab_1') != null){
		document.getElementById('tab_1').className='off';
	}

	if (document.getElementById('tab_2') != null){
		document.getElementById('tab_2').className='off';
	}

	if (document.getElementById('tab_3') != null){
		document.getElementById('tab_3').className='off';
	}

	var ele = document.getElementById(tab_number);
	if( ele ){
		ele.className='on';
	}

	return true;
}

function highlightInitialTab(){

	var uList = document.getElementById( 'resultsTabs' );
	if( uList ){

		var found = 0;
		var list = uList.getElementsByTagName('li');
		for( var i = 0; i < list.length; i++ ){

			var child = list[i];

				if( found == 0 ){
					child.className = 'on' ;
					found = 1 ;
				}
				else {
					child.className = 'off' ;
				}
		}
	}
}

/** Class that will deal with all client side aspects of the
 * selected comparison activities for tire results.
 */
function TrackComparisonItems(){

	/** Maximum number of tires that may be compared using TSS */
	var MAX_ITEMS_FOR_COMPARE = 3;
	/** Minimum number of tires that may be compared using TSS */
	var MIN_ITEMS_FOR_COMPARE = 2;
	/** Error message displayed when too many items are being selected for comapre */
	var MAX_ERR_MSG = document.getElementById('contentForm:compareErrorMessageMax').value;
	/** Error message displayed when too few items have been selected and compare is attempted */
	var MIN_ERR_MSG = document.getElementById('contentForm:compareErrorMessageMin').value;


	function getTrackingField(){
		/**
		 * Used to keep a handle on the field that maintains the count of the selected items
		 * through ajax calls.
		 *
		 * This form variable is backed by the TSSBean class variable - numberOfSelectedFitments
		 */
		var selectTrackingElement = document.getElementById('tlForm:numSelected');

		//If the page is being entered for the first time or there is no initialized
		//value for the tracking element then set to 0 - Note that this acts as
		//constructor code and executes each time a TrackComparisonItems class is created
		if (selectTrackingElement != null &&
			(selectTrackingElement.value == "" ||
			selectTrackingElement.value == null)){
			selectTrackingElement.value = 0;
		}

		return selectTrackingElement;
	}

	/**
	 * The trackItems method is responsible for keeping a count of the selected items
	 * for a given tire type.  If more than the maximum - 3 in this case are selected
	 * an alert box will display the error and the check box selected will automatically
	 * be unchecked.
	 */
	this.trackItems = function(element){
		//The value will be stored as a string so convert to a local integer variable
		//so simple arithmetic may be performed.
		var selectTrackingElement = getTrackingField();
		var numberOfItemsSelected = parseInt(selectTrackingElement.value);

		//If the user has attempted to add another item to compare
		if (element.checked) {
			//First ensure that the maximum number of comparison items has not
			//been already reached
			if (numberOfItemsSelected == MAX_ITEMS_FOR_COMPARE){
				alert(MAX_ERR_MSG);
				element.checked=false;
				return false;
			}
			//If there are fewer than the maximum number of comparable items selected
			//then increment the number of items being compared and store to the form
			else {
				numberOfItemsSelected++;
				selectTrackingElement.value = numberOfItemsSelected;
				element.checked=true;
				return true;
			}
		}
		//The user is unchecking an already selected check box so reduce the
		//requested item for comparison count by 1
		else {
			numberOfItemsSelected--;
			selectTrackingElement.value = numberOfItemsSelected;
		}
	}

	/**
	 * Method to verify that the minimum number of items have been selected such
	 * that the TireComparison page may be displayed.
	 */
	this.verifyMinimumSelected = function(){
		var selectTrackingElement = getTrackingField();

		var numberOfItemsSelected = parseInt(selectTrackingElement.value);
		if (numberOfItemsSelected < MIN_ITEMS_FOR_COMPARE){
			alert(MIN_ERR_MSG);
			return false;
		}
		return true;
	}
}

function AddToCartHandler(){
	//MMYO Parameters for the add to cart link
	var MAKE_PARAM="&Make=";
	var MODEL_PARAM="&Model=";
	var YEAR_PARAM="&Year=";
	var OPTION_PARAM="&Option=";

	//Tire Parameters for the add to cart link
	var CPN_PARAM="&ItemNo=";
	var QTY_PARAM="&Quantity=";
	var LANG_PARAM="&lang=";

	var quantitySelectedId;

	this.setQuantitySelectedId = function(quantityId,replace){

		if( replace == null ){
			quantitySelectedId = quantityId;
			return ;
		}

		var l = quantityId.lastIndexOf(':');
		var t = quantityId.substring(0,(l + 1));
		quantitySelectedId = t + replace ;

	}

	var preAssembledLink;

	this.assembleRetailerLink = function(baseURL, cpnValue){

		var finalURL = baseURL + CPN_PARAM + encodeURIComponent( cpnValue ) +
					   QTY_PARAM + encodeURIComponent( document.getElementById(quantitySelectedId).value ) +
					   MAKE_PARAM + encodeURIComponent( document.getElementById('addToCartMake').value ) +
					   MODEL_PARAM + encodeURIComponent( document.getElementById('addToCartModel').value )+
					   YEAR_PARAM + encodeURIComponent( document.getElementById('addToCartYear').value ) +
					   OPTION_PARAM + encodeURIComponent( document.getElementById('addToCartOptions').value );

		preAssembledLink = finalURL;

	}

	this.executeRetailerLink = function(linkToExecute){

		if (linkToExecute != null){
			preAssembledLink = linkToExecute;
		}

		var url = encodeURI( preAssembledLink );

		window.location.href = url ;
	}
}



/**
 * Javascript initialization for the TSS page. Called from onload event for every TSS page. Provides
 * initialization of SEAM remoting, sets locale defaults, and creates instances of page-specific JavaScript objects.
 */
function initializePage() {



	//Initialize Seam remoting messages
	Seam.Remoting.displayLoadingMessage = function() {};
  	Seam.Remoting.hideLoadingMessage = function() {};
  	//Seam.Remoting.setDebug(true);

	//Set up a batch for all initialization remoting calls; makes callbacks happen in
	//deterministic order, and reduces number of network round trips from N to 1.
	Seam.Remoting.startBatch();

	//Set up the current Locale
	//TODO: should this be singleton or new instance? Leave as singleton for now since
	//      Locale is in Session scope - another issue that should be evaluated.
	Seam.Component.getInstance("localeBean").getLanguage(updateLocaleCallback);

	//get the conversationId for the current page for use in initializing various components
	var pageConversationId = getConversationIdForCurrentPage();

	//create javascript component for handling tire search selections
	ymmoComponent = new YMMOComponent();
	ymmoComponent.init(pageConversationId);
	ymmoComponent.synchronize();

	addToCartHandler = new AddToCartHandler();
	localeComponent = new LocaleElement();
	highlightInitialTab();

	var inp = document.getElementById('currentTireType');
	if( inp ){
		var currentTireType = inp.value ;
		if( currentTireType ){
			Seam.Component.newInstance("tssBean").setDisplayFitmentList( currentTireType );
		}
	}

	//Submit the batch of initialization remoting calls, as noted above, using a batch
	//makes the set of calls/callbacks execute in a deterministic order, and ensures a
	//single network round trip is made for the entire sequence of initialization calls. A batch
	//shares a single conversation id within the Remoting context singleton, so set the
	//conversation id here.
	Seam.Remoting.getContext().setConversationId(pageConversationId);
	//alert("initializePage: prior to Seam.Remoting.executeBatch - conversation id set to:" + Seam.Remoting.getContext().getConversationId());
	Seam.Remoting.executeBatch();

	//once the batch is complete, need to rewrite the button handler to set search parameters for values currently
	//selected in the YMMO drop downs.  Resolution of MNABJ-117 and MNABJ-118.
	var ele = document.getElementById("MMYO:findTires");
	if( ele ) {
		//only rewrite if the button is found on the page
		ymmoComponent.rewriteButtonHandler(ele);
	}

	// if we are on the results page
	// reset the comparion toggle states
 	// TODO - add reset call here
 	var found = $$('div.compare_box')
 	if( found != null ){
 		if( found.length > 0 ){
 			Seam.Component.getInstance("tssCompareBean").resetToggleStates( resetToggleStatesCallback )
 		}
 	}

}

function resetToggleStatesCallback(){
	//
}

/**
 * Retrieve the conversation id used to generate the current page, generated by an EL call and
 * stored in the hidden input field named "conversationId" on the page.
 */
function getConversationIdForCurrentPage() {
	//
	var pageConversationId;
	var ele = document.getElementById('conversationId');
	if( ele ){
		pageConversationId = ele.value ;
		if( pageConversationId){
			//alert ("getConversationForPage - page conversation id is: " + pageConversationId);
		}
	}
	else {
		//default to null to that remoting will use a new conversation
		//alert ("getConversationForPage - page conversation id not found");
		pageConversationId = null;
	}
	return pageConversationId;
}


/** Allow for window.onload event to be chained.  Prevents like scripts from overwriting the onload event
*/
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
	} func();
	}
  }
}

/** Allow for window.onunload event to be chained.  Prevents like scripts from overwriting the onload event
*/
function addUnloadEvent(func) {
  var oldonunload = window.onunload;
  if (typeof window.onunload != 'function') {
    window.onunload = func;
  } else {
    window.onunload = function() {
      if (oldonunload) {
        oldonunload();
	} func();
	}
  }
}

/**
	A function to limit the entry to numerics only
*/
function checkNumber( e ) {

    var code;

    // a little browser work around
    if (!e) var e = window.event;
    if( e.charCode ){
    	code = e.charCode ;
    }
    else if (e.keyCode) {
    	code = e.keyCode;
   	}
    else if (e.which) {
    	code = e.which;
    }
    else {
    	code = 0;
    }

    if( code > 31
        && ( code < 48 || code > 57 ) ){
        return false ;
	}

    return true ;
}


function validateNumber( ele, min, max, msg ){

	if( isNaN( ele.value ) ){
		if( msg != null ){
			alert( msg );
		}
		ele.select();
		ele.focus();
		return false ;
	}

	var val = parseFloat( ele.value );
	if( val < min ){
		if( msg != null ){
			alert( msg );
		}
		ele.select();
		ele.focus();
		return false ;
	}

	if( val > max ){
		if( msg != null ){
			alert( msg );
		}
		ele.select();
		ele.focus();
		return false ;
	}

	return true ;
}


function validateQuantity( eleId, min, max, msg ){

	var l = eleId.lastIndexOf(':');
	var t = eleId.substring(0,(l + 1));
	var quantityId = t + 'quantity' ;
	var ele = document.getElementById( quantityId );

	var val = parseFloat( ele.value );
	if( isNaN( val ) ){
		if( msg != null ){
			alert( msg );
		}
		ele.select();
		ele.focus();
		return false ;
	}

	if( val < min ){
		if( msg != null ){
			alert( msg );
		}
		ele.select();
		ele.focus();
		return false ;
	}

	if( val > max ){
		if( msg != null ){
			alert( msg );
		}
		ele.select();
		ele.focus();
		return false ;
	}

	ele.value = val ;
	return true ;
}

function toggleDisplay(content_number) {

	//

	//Get the content for the header element label;
	//loaded from resource bundle into hidden div on page for retrieval here
	var ele = document.getElementById( 'label.hide' );
	var hideTxt = ele.innerHTML ;
	ele = document.getElementById( 'label.show' );
	var showTxt = ele.innerHTML ;

	//build element names for the header and content elements
	var this_toggle_id = 'showhide'+content_number+'_toggle';
	var this_content_id = 'showhide'+content_number+'_data';

	//flip the state of the header and show the correct content for the state
	if ($(this_toggle_id).className == 'show') {
		$(this_toggle_id).className = 'hide';
		$(this_toggle_id).innerHTML = hideTxt;
	} else {
		$(this_toggle_id).className = 'show';
		$(this_toggle_id).innerHTML = showTxt;
	}
	//flip the state of the content element
	$(this_content_id).toggle();

	// update the server side component
	var state = $(this_toggle_id).className
	Seam.Component.getInstance("tssCompareBean").setToggleState( content_number, state, setToggleStateCallback );

}


function setToggleStateCallback(){

	// nothing to do really

}



// detect IE
function isIE(){
  	var isThisIE  = ( navigator.appName == "Microsoft Internet Explorer" );
  	return isThisIE ;
}

// detect Opera
function isOpera(){
  var isThisOpera  = ( window.opera ) ? true : false ;
  return isThisOpera ;
}

// detect Safari on Windows
function isSafariOnWindows(){
  var isThisSafari  =  ( navigator.vendor == "Apple Computer, Inc." && navigator.platform == "Win32" );
  return isThisSafari ;
}

function unloadPage(){
        writeCIDCookie();
        return true ;
}

// helper function to write the current CID cookie
function writeCIDCookie(){
        var cid = getConversationIdForCurrentPage();
        if( cid ) {
                // write a cookie
                document.cookie = "currentCID=" + encodeURIComponent(cid);
         }
}

// helper function to read the current cid cookie
function readCIDCookie(){

        var allcookies = document.cookie;
        // Look for the start of the cookie named "currentCID"
        var pos = allcookies.indexOf("currentCID=");

        // found it get the value
        if (pos != -1) {
            var start = pos + 11 ;
            var end = allcookies.indexOf(";", start);
            if (end == -1) end = allcookies.length;
            var value = allcookies.substring(start, end);
            value = decodeURIComponent(value);
			return value ;
        }
}

// helper function to reset the cookie
function clearCIDCookie(){
        document.cookie = "currentCID=" + "" ;
}

/**
 * Function to prevent enter key press from submitting form.  Invoke from
 * onkeypress event handler on input field
 *
 * @param {Object} e
 */
function disableEnterKey(e) {
     var key;
     if(window.event)
          key = window.event.keyCode; //IE
     else
          key = e.which; //firefox
     return (key != 13);
}

/**
 * Function to wrap the onClick handler for a specified element with before and optionally
 * after function calls.  This function is used to avoid interfering with the behaviour of
 * AJ4-generated onClick handlers.  It should be invoked from the onpageload event chain for
 * the page that contains the element of interest.
 *
 * @param {Object} elementIdToWrap
 * @param {Object} beforeFunction
 * @param {Object} afterFunction
 */
function wrapOnClickEvent(elementIdToWrap, beforeFunction, afterFunction){
	var eid = document.getElementById(elementIdToWrap);
	if (eid) {
		var existingOnclick = eid.onclick;
		eid.onclick = function(){
			//New Functionality
			var invalid = beforeFunction();
			if (invalid) return false;
			//Existing Functionality
			var result = existingOnclick();
			if (afterFunction) {
				afterFunction();
			}
			//have to force the false here; A4J returns undefined for existingOnClick
			return false;
		}
	}
}

/*
 * Add non-function code here so we don't have to pick through the entire file
 */
//Initialize base functionality for the page
addLoadEvent(initializePage);
if( isIE() || isSafariOnWindows() ){
		//use cookie to store current conversation id so we can redirect
		//to the correct conversation if the user uses the IE browser back button.  IE
		//looses the conversation context on back because it issues a new request for the
		//page - HTTP GET /
        addUnloadEvent(unloadPage);
} else {
	addUnloadEvent(function() {});
}
