/**
    JSP's using this Javascript will need to include some dwr dependencies:
    
      <script src='/esuite/dwr/interface/AjaxFacade.js'></script>
      <script src='/esuite/dwr/engine.js'></script>validate
  
  */
/**
        Address validation and update on Country change
        
        To use on your jsp:
          
          <script src='/esuite/dwr/interface/AjaxFacade.js'></script>
        <script src='/esuite/dwr/engine.js'></script>
        <ic:javascript path="icentris/ajax4i.js"/>
        ...
        ...
          var myAddressVerifier = new AjaxAddressValidator( "myAddress" );
          <input type="..." name="address1" id="myAddressAddress1" ... onChange="myAddressVerifier.validate(this);">
        <input type="..." name="city" id="myAddressCity" ... onChange="myAddressVerifier.validate(this);">
          
      -  OR  -
          
          var myAddressVerifier = new AjaxAddressValidator( "my_address_" );
          <input type="..." name="address1" id="my_address_Address1" ... onChange="myAddressVerifier.validate(this);">
        <input type="..." name="city" id="my_address_City" ... onChange="myAddressVerifier.validate(this);">
          
      - OR ( if you have lower case id's already, for example... )
          
          var myAddressVerifier = new AjaxAddressValidator( "address.", { "address1" : "address1",
                                        "address2": "address2",
                                        "city" : "city",
                                        "state" : "stateProvinceGeoId",
                                        "validateAddresspostalCode" : "postalCodeGeoId",
                                        "country" : "countryGeoIdCodeValue" } );
          <input type="..." name="address1" id="address.address1" ... onChange="myAddressVerifier.validate(this);">
        <input type="..." name="countryGeoIdCodeValue" id="adress.countryGeoIdCodeValue" ... onChange="myAddressVerifier.validate(this);">
          
  **/
var makingQueuedCall = false;
var queuedCalls = new Array();  
var temp_fieldMap = null;
var temp_fieldsPrefix = null;
/** 
 * We never want a field to be sized larger than this number.  If you need to customize this, talk
 * to Spencer or Darren about the best solution.
 */
var MAX_FIELD_SIZE = 40;

function AjaxAddressValidator(fieldsPrefix, fieldMap, requiredFieldsList) {
  this._fieldsPrefix = fieldsPrefix;

  if (fieldMap) {
    this._fieldMap = fieldMap;
  } else {
      // Default field names 
    this._fieldMap = {"address1":"Address1",
                      "address2":"Address2",
                      "city":"City", 
                      "stateProvinceGeoId":"State", 
                      "postalCode":"PostalCode", 
                      "country":"Country",
                      "county":"County",
                      "geoCode":"GeoCode"};
  }
  if (requiredFieldsList) {
    this._requiredFieldsList = requiredFieldsList;
  } else {
    this._requiredFieldsList = ["address1", "city", "stateProvinceGeoId", "postalCode", "country"];
  }

  this.validate = function (theFieldTriggeringValidation) {
    temp_fieldsPrefix = this._fieldsPrefix;
    temp_fieldMap = this._fieldMap;
    _fieldTriggeringValidation = theFieldTriggeringValidation;  // Try to use OOP instead of global
    var errMsg = "";
    var address1 = this._getAddressField("address1");
    var city = this._getAddressField("city");
    var county = this._getAddressField("county");
    var stateCode = this._getAddressField("stateProvinceGeoId");
    var postalCode = this._getAddressField("postalCode");
    var country = this._getAddressField("country");
    
    if ( country && country.value == "-1" ) {
      // Don't want to validate when country isn't set
      return;
    } 
    // If any of the required fields are blank, then don't make the AJAX call
    if (this._requiredFieldsArePopulated() ) {
      //does ajax call for further validation
      var address = new Object();
      address.address1 = address1.value;
      address.city = this._trimTrailingWhiteSpace(city.value);
      if ( county ) {
        address.county = county.value;
      }
      address.stateProvinceGeoId = stateCode.value;
      address.postalCode = postalCode.value;
      if ( country ) {
        address.countryGeoId = country.value;
      }
      address.fieldPrefix = temp_fieldsPrefix;
      var addressCall = new Object();
      addressCall.address = address;
      addressCall.callback = this._addressValidationCallback;
      callQueue(addressCall);
      //AjaxFacade.validateAddress(address, this._addressValidationCallback);
    }
    setCoolDownTimer(3000);
  }

  this._requiredFieldsArePopulated = function () {
    for ( var i = 0; i < this._requiredFieldsList.length; i++ ) {
      var field = this._getAddressField(this._requiredFieldsList[i]);
      if ( !field || !field.value || field.value.length < 1 || field.value == "-1" ) {
        return false;
      }
    }
    return true;
  }

  this._getAddressField = function(fieldSuffix) {
    return $(this._fieldsPrefix + this._fieldMap[fieldSuffix]);
  }
  
  this._trimTrailingWhiteSpace = function (value) {
  	if (value && value.length > 0) {
  		return value.replace(/\s*$/, "");
	} else {
		return "";
	}
  }

  /**
    * results will be an instance of AddressVerificationResults
    */
  this._addressValidationCallback = function (results) {

        if(document.getElementById(results.fieldPrefix + "lookup")){
          var zipLookup = document.getElementById(results.fieldPrefix + "lookup"); 
          var queue = Effect.Queues.get('global');
          
          if(queue.size() <= 1){ 
            new Effect.Appear(zipLookup,{queue: 'end',  limit: 1});
            //new Effect.Highlight(zipLookup,{queue: 'end',limit: 1});
          }
        }
        
        
        
    if (results.success == false) {
      for (var i = 0; i < results.errorMessages.length; i++) {
        alert(results.errorMessages[i]);
      }
      if ( results.suggestions ) {
        for (var i = 0; i < results.suggestions.length; i++ ) {
          var suggestion = results.suggestions[i];
          var field = $(results.fieldPrefix + temp_fieldMap[suggestion.field]);
          var hasPreviousValue = false;
          var previousValue = field.value;
          if (previousValue == "-1" && document.getElementById("current_"+results.fieldPrefix + temp_fieldMap[suggestion.field]) != undefined)
          {
            previousValue = document.getElementById("current_"+results.fieldPrefix + temp_fieldMap[suggestion.field]).value;  
          }
          if ( field.options ) { // if it is a drop-down
            //If we are a dropdown, make sure the field is showing
            field.style.display="block";
            
            //Destroy spans if they exist to ensure we show proper dropdowns.
              var destroySpans = field.parentNode.getElementsByTagName("SPAN");
              for (var x = 0; x < destroySpans.length; x++){
                if($(destroySpans[x]).hasClassName('addressTemp')) field.parentNode.removeChild($(destroySpans[x]));
              }
            
            if(suggestion.suggestions.length != 1){
              field.options.length = suggestion.suggestions.length + 1;
              field.options[0].value = -1;
              field.options[0].text = "Choose one...";
  
              for ( var j = 0; j < suggestion.suggestions.length; j++ ) {
                field.options[j+1].value = suggestion.suggestions[j];
                field.options[j+1].text = suggestion.suggestions[j];
                if ( !hasPreviousValue ) {
                  if ( previousValue == field.options[j+1].value ) {
                    hasPreviousValue = true;
                    field.value = previousValue;
                  }
                }
              }
              if ( !hasPreviousValue ) {
                field.value = "-1"
              }
            }else{
                field.options[0].text = suggestion.suggestions[0];
                field.options[0].value = suggestion.suggestions[0];

                if ( !hasPreviousValue ) {
                  if ( previousValue == field.options[0].value ) {
                    hasPreviousValue = true;
                    field.value = previousValue;
                  }
                }
              
              if ( !hasPreviousValue ) {
                field.value = "-1"
              }

              //Destroy spans if they exist to ensure we show proper dropdowns.
              var destroySpans = field.parentNode.getElementsByTagName("SPAN");

              for (var x = 0; x < destroySpans.length; x++){
                if($(destroySpans[x]).hasClassName('addressTemp')) field.parentNode.removeChild($(destroySpans[x]));
              }
              
              if ( suggestion.field == "county" ) {
                var value = suggestion.suggestions[0];
                var text = suggestion.suggestions[0];

                if ( value == 'ERROR' ) {
                  value = "-1";
                  text = "City/State does not match Zip Code.";
                } 

                field.style.display="none";
              
                //Create our text field and insert the value to show inside of it
                var singleField = document.createElement("span");
                singleField.className = "addressTemp";
                singleField.innerHTML = text;
              
                //Add our text field to the DOM
                field.parentNode.appendChild(singleField);
                field.value = value;
              }

             }
          } else { // it is an input field
            if ( suggestion && suggestion.suggestions.length > 0 ) {
              field.value = suggestion.suggestions[0];
            }
          }
        }
      } else {
          // OBW-1668 we don't want to erase the users input
        //_fieldTriggeringValidation.value = "";
        
        _fieldTriggeringValidation.focus();
      }
    }
    makingQueuedCall = false;
    makeQueuedCall();    
  };

  this.changeCountry = function () {
    temp_fieldsPrefix = this._fieldsPrefix;
    temp_fieldMap = this._fieldMap;
    
    if ( this._getAddressField("country") ) {
      var value = this._getAddressField("country").value;
      AjaxFacade.getStatesByCountry(value, this._stateDropdownCallback.bind(this));
      AjaxFacade.getAddressConfiguration( value, this._fieldsPrefix, this._reconfigureAddress );
    }
  };
  
  this._stateDropdownCallback = function (results) {

    var _currentStateDropdownToUpdate = $(this._fieldsPrefix + this._fieldMap["stateProvinceGeoId"]);

    var previousValue = _currentStateDropdownToUpdate.value;

    _currentStateDropdownToUpdate.length = results.length + 1;
    _currentStateDropdownToUpdate.options[0].value = -1;
    _currentStateDropdownToUpdate.options[0].text = "Choose one...";
    
    for (i = 0; i < results.length; i++) {
      _currentStateDropdownToUpdate.options[i+1].value = results[i].value;
      _currentStateDropdownToUpdate.options[i+1].text = results[i].name;
      
      if ( previousValue == _currentStateDropdownToUpdate.options[i+1].value ) {
        _currentStateDropdownToUpdate.value = previousValue;
      }
    }
  };
  
  this._reconfigureAddress = function( results ) {
    // TODO : update address configuration
    for ( var i = 0; i < results.fieldConfig.length; i++ ) {
      var f = results.fieldConfig[i]['fieldName'];
      var m = results.fieldConfig[i]['maxLength'];
      var control = $(results.fieldsPrefix + temp_fieldMap[f] );
      if ( control == null ) continue;
      if ( m > 0 ) {
        if ( control.maxLength ) {
          control.maxLength = m;
        }
        if ( control.size ) {
              if ( (m + 2) <= MAX_FIELD_SIZE ) {
            control.size = m + 2;
              } else {
          control.size = MAX_FIELD_SIZE;
              }
        }
      }
    }
  }

}

/*
* Use this so that the address validation doesn't happen "back to back".
*  This makes it wait a few seconds to avoid bogus events to be fired off too rapidly.
*/
var coolDownTimer = 0;
function setCoolDownTimer(amtToCoolDown) {
  if(amtToCoolDown) {
    coolDownTimer = amtToCoolDown;
  }

  if(coolDownTimer > 0) {
    setTimeout("setCoolDownTimer()", 1000); // recursive call every second.
    coolDownTimer -= 1000;
  }
}

/*
 * This code is used to queue up the validation calls. 
 * This is needed for when there is more than on address widget in the form which
 * leads to race conditions and strange results. 
 */

function callQueue(address) {
  queuedCalls.push(address);
  if (!makingQueuedCall)
  {
    makingQueuedCall = true;
    makeQueuedCall();
  }
}
function makeQueuedCall() {
  var addressToCall = queuedCalls.pop();
  if(addressToCall) {
    AjaxFacade.validateAddress(addressToCall.address, addressToCall.callback);
  }
}

/*******************************************************************************/
/*                                                                             */
/*        Form Fields Validation Methods                                       */
/*                                                                             */
/*******************************************************************************/
/*
      call attachValidationMethods via Event.observe(window, "load", yourFunction); to automatically validate
      fields on your page that have a class attribute of "validatable".
      
      ex:
          Event.observe(window, "load", attachValidationMethods );
          ...
          ...
          <input type="text" name="blah" class="validatable required etc">
          ...
  */
function attachValidationMethods() {
  var elements = document.getElementsByClassName("validatable");
  for (var x = 0; x < elements.length; x++) {
    Event.observe(elements[x], "change", Validation.attachValidation.bindAsEventListener(elements[x]));
	Event.observe(elements[x], "blur", Validation.attachValidation.bindAsEventListener(elements[x]));
  }
  elements = document.getElementsByClassName("required");
  for (var x = 0; x < elements.length; x++) {
    Event.observe(elements[x], "change", Validation.attachValidation.bindAsEventListener(elements[x]));
    Event.observe(elements[x], "blur", Validation.attachValidation.bindAsEventListener(elements[x]));
  }
  elements = document.getElementsByClassName("confirming");
  for (var x = 0; x < elements.length; x++) {
    var name = elements[x].name;
    var fieldsToConfirm = document.getElementsByName(name);
    if ( fieldsToConfirm && fieldsToConfirm.length == 2 ) {
      Event.observe(fieldsToConfirm[0], "change", Confirmation.attachConfirmation.bindAsEventListener(fieldsToConfirm[0]));
      Event.observe(fieldsToConfirm[1], "change", Confirmation.attachConfirmation.bindAsEventListener(fieldsToConfirm[1]));
      Event.observe(fieldsToConfirm[0], "blur", Confirmation.attachConfirmation.bindAsEventListener(fieldsToConfirm[0]));
      Event.observe(fieldsToConfirm[1], "blur", Confirmation.attachConfirmation.bindAsEventListener(fieldsToConfirm[1]));
    }
  }
}
var Validation = {
attachValidation:function () {
  validateMe(this);
}
}
var Confirmation = {
attachConfirmation:function () {
  var name = this.name;
  var fieldsToConfirm = document.getElementsByName(name);
  if ( fieldsToConfirm && fieldsToConfirm.length == 2 ) {
    confirmFields(fieldsToConfirm[0], fieldsToConfirm[1]);
  }
}
};
function validateMe(field, variant, validationKey, marketName) {
	// reset error in case of differences
	field.style.color = "black";
	document.getElementById(field.id + "-error").innerHTML = "";
	validateRequired(field, variant, validationKey, marketName);
}
function validateRequired(field, variant, validationKey, marketName) {
	 var fieldValue = (field.value) ? field.value : null;
  AjaxFacade.validateField(field.id, fieldValue, variant, validationKey, marketName,validateFieldCallback);
}
function validateFieldCallback(fieldAndMessage) {
  var fieldId = fieldAndMessage[0];
  var errorMessage = fieldAndMessage[1];
  var errorField = document.getElementById(fieldId + "-error");
  if ( errorMessage == "" || errorField.innerHTML == "" ) {
    $(fieldId).style.color = errorMessage == "" ? "black" : "red";
    if (errorField) {
      errorField.innerHTML = errorMessage;
    } else {
      alert("Cannot find the XHTML Field : " + fieldId + "-error");
    }
  }
  //if ( errorMessage != "" && focusFieldId == "" ) focusFieldId = fieldId;
  makingQueuedCall = false;
  makeQueuedCall();
}
function validateFieldsCallback(valArray) {
  if (valArray[0] == "error") {
    document.getElementById(valArray[1]).style.color = "red";
    document.getElementById(valArray[3]).style.color = "red";
    document.getElementById(valArray[1] + "-error").innerHTML = valArray[2];
  } else {
    document.getElementById(valArray[1]).style.color = "black";
    document.getElementById(valArray[3]).style.color = "black";
    document.getElementById(valArray[1] + "-error").innerHTML = "";
  }
}
var _formTemplateSuppressPageTopScroll = false;
function validateOnSubmit(form) {
  if ( validateGeneral(form) && ( typeof validatePage != 'function' || validatePage(form) ) ) {
    $('validationErrorMessage').style.display = "none";
    return true;
  } else {
  	$('validationErrorMessage').style.display = "block";
  	if (_formTemplateSuppressPageTopScroll == false) { location.href = "#top"; }
  	return false;
  }
}
function validateGeneral(form) {
  var isValid = true;
  var toValidate = document;
  if ( form ) toValidate = form;
  elements = $A(toValidate.getElementsByClassName("required"));
  elements = elements.concat(toValidate.getElementsByClassName("confirming"));
  for (var x = 0; x < elements.length; x++) {
    if (!elements[x].disabled && !elements[x].readonly) {
      if ( elements[x].value == "" || elements[x].value == "-1" ) {
                                var a = new Array(2);
                                a[0] = elements[x].id;
                                a[1] = "This field is required.";
        validateFieldCallback(a);
                                isValid = false;
      }
    }
  }
  elements = toValidate.getElementsByClassName("validatable");
  for (var x = 0; x < elements.length; x++) {
    if (!elements[x].disabled && !elements[x].readonly) {
      if ( elements[x].style.color == "red" ) {  // find a better way to decide if there is an error there already without re-validating.
                                isValid = false;
      }
    }
  }
  elements = toValidate.getElementsByClassName("confirming");
  for (var x = 0; x < elements.length; x++) {
    if (!elements[x].disabled && !elements[x].readonly) {
      if ( elements[x].style.color == "red" ) {  // find a better way to decide if there is an error there already without re-validating.
                                isValid = false;
      }
    }
  }

  return isValid;
}

function confirmFields(field1, field2) {
	var fieldValue1 = (field1.value) ? field1.value : null;
	var fieldValue2 = (field2.value) ? field2.value : null;
  AjaxFacade.confirmFields(field2.id, fieldValue1, fieldValue2,confirmFieldsCallback);
}
function confirmFieldsCallback(fieldAndMessage) {
  validateFieldCallback(fieldAndMessage);
}


function replaceTradeMark(value) {
	// &#129;
	// &trade;
	var sChar = String.fromCharCode(174);
	var str_check = value.search('&trade;');
	if (str_check != -1) { 
	    // alert('here');
		return value.replace('&trade;',sChar);
	}
	return value;
}

var FeatureDropDowns = Class.create();

FeatureDropDowns.prototype= {
  initialize: function(virtualFieldId, virtualProductId, featureCategories, largeImageObject) {
    this._virtualFieldId = virtualFieldId;
    this._virtualProductId = virtualProductId;
    this._featureCategories = featureCategories;
    this._dropDownIds = new Array(this._featureCategories.length);
    this._largeImageObject = $(largeImageObject);
    this._defaultLargeImageUrl = largeImageObject.src;
    this._selectedDropDownsArray = new Array();
  
    for ( var i = 0; i < this._featureCategories.length; i++ ) {
      this._dropDownIds[i] = this._featureCategories[i] + "_" + this._virtualProductId;
    }
  },

  selectFeature:function(dropDown) {
    if(dropDown) {
      if(dropDown.value != "" && !this._containsInArray(this._selectedDropDownsArray,dropDown)) {
        this._selectedDropDownsArray[this._selectedDropDownsArray.length] = dropDown;
      }
      else if(dropDown.value == "") {
        this._selectedDropDownsArray = this._removeFromArray(this._selectedDropDownsArray,dropDown);
      }
    }
    
    var _selectedFeatures = this._getSelectedFeatures();
    var _selectedFeatureCategories = this._getSelectedFeatureCategories();
    
    if ( _selectedFeatures.length == this._featureCategories.length ) {      
      AjaxFacade.getVariantProductId(this._virtualFieldId, this._virtualProductId, _selectedFeatureCategories, _selectedFeatures, this._getVariantProductIdCallback.bind(this));
    } else {
    this._largeImageObject.src = this._defaultLargeImageUrl;
      AjaxFacade.getFeatures(this._virtualFieldId, this._virtualProductId, _selectedFeatureCategories, _selectedFeatures, this._getFeaturesCallback.bind(this));
    }
  },

  _getSelectedFeatureCategories: function() {
      var _selectedFeatureCategories = new Array();

      for(var i=0 ; i<this._selectedDropDownsArray.length ; i++) {
        _selectedFeatureCategories[i] = this._selectedDropDownsArray[i].name;
      }
      
      for ( var i = 0; i < this._dropDownIds.length; i++ ) {
        if(!this._containsInArray(this._selectedDropDownsArray,$(this._dropDownIds[i]))) {
          _selectedFeatureCategories[_selectedFeatureCategories.length] = $(this._dropDownIds[i]).name;
        }
      }
      return _selectedFeatureCategories;
  },

  _getSelectedFeatures: function() {
      var _selectedFeatures = new Array();

      for(var i=0 ; i<this._selectedDropDownsArray.length ; i++) {
        _selectedFeatures[i] = this._selectedDropDownsArray[i].value;
      }

      return _selectedFeatures;
  },

  _getFeaturesCallback: function(returnValues) {
    var temp_virtualFieldId = returnValues[0];
    var temp_featureCategories = returnValues[1];
    var temp_virtualProductId = returnValues[2];
    var newFeatureDropDowns = returnValues[3];
    
    // if this flag is true, then user's next categories selection won't be considered
    var resetNextCategories = false;
    
    for ( var i = 0; i < temp_featureCategories.length; i++ ) {
      var features = newFeatureDropDowns[temp_featureCategories[i]];
      var dropDownId = $(temp_featureCategories[i] + "_" + temp_virtualProductId);
      var selectedValue = dropDownId.value;
      var selectedIndex = 0;
      
      dropDownId.options.length = features.length + 1;
      dropDownId.options[0].value = "";
      dropDownId.options[0].text = "Choose " + temp_featureCategories[i] + "...";
      for ( var j = 0; j < features.length; j++ ) {
        dropDownId.options[j+1].value = features[j];
        dropDownId.options[j+1].text = replaceTradeMark(features[j]);
        if(selectedValue == features[j]) {
          selectedIndex = j+1;
        }
      }
      
      if(selectedValue == "") {
        resetNextCategories=true;
      }
      
      if(resetNextCategories) {
        dropDownId.options[0].selected = true;
        if(this._containsInArray(this._selectedDropDownsArray,dropDownId)) {
          this._removeFromArray(this._selectedDropDownsArray,dropDownId);
        }
      } else {
        dropDownId.options[selectedIndex].selected = true;
      }
    }

    $(temp_virtualFieldId).value = "";
  },

  _getVariantProductIdCallback: function(returnValues) {
    var temp_virtualFieldId = returnValues[0];
    var variantProductId = returnValues[1];
    var newLargeImageUrl = returnValues[2];

    if ( !variantProductId ) {
      alert("We are currently not offering this combination at this time.  Please make another selection.");
      $(temp_virtualFieldId).value = "";
      $(temp_virtualFieldId).focus();
    } else {
      $(temp_virtualFieldId).value = variantProductId;
      if(newLargeImageUrl != "")
        this._largeImageObject.src = newLargeImageUrl;
      else
        this._largeImageObject.src = this._defaultLargeImageUrl;
    }
  },
  
  _containsInArray: function(arrayObject, elementToAdd) {
    var contains = false;
    for(var i=0 ; i<arrayObject.length ; i++) {
      if(arrayObject[i].id == elementToAdd.id) {
        contains = true;
        break;
      }
    }
    return contains;
  },
  _removeFromArray: function(arrayObject, elementToRemove) {
    var finalArray = new Array();
    var finalArrayIndex = 0;
    for(var i=0 ; i<arrayObject.length ; i++) {
      if(arrayObject[i].id != elementToRemove.id) {
        finalArray[finalArrayIndex++] = arrayObject[i];
      }
    }
    
    return finalArray;
  }
}
