/**
    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);">

  **/

/**
 * 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"];
  }

	/**
	 * The control passed in will have its countryCallback method called whenever the value of Country is updated
	 */
	this.addCountryListener = function(control) {
		if(!this.countryListeners ){
			this.countryListeners = new Array();
		}
		if(control) {
			this.countryListeners[this.countryListeners.length] = control;
		}
	};

  this.validate = function (theFieldTriggeringValidation) {
    _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 = city.value;
      if ( county ) {
        address.county = county.value;
      }
      address.stateProvinceGeoId = stateCode.value;
      address.postalCode = postalCode.value;
      if ( country ) {
        address.countryGeoId = country.value;
      }
      AjaxFacade.validateAddress(address, this._addressValidationCallback.bind(this));
    }

    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]);
  }

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

        if(document.getElementById(this._fieldsPrefix + "lookup")){
          var zipLookup = document.getElementById(this._fieldsPrefix + "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 = $(this._fieldsPrefix + this._fieldMap[suggestion.field]);
          var hasPreviousValue = false;
          var previousValue = field.value;
          if (previousValue == "-1" && document.getElementById("current_"+this._fieldsPrefix + this._fieldMap[suggestion.field]) != undefined)
          {
            previousValue = document.getElementById("current_"+this._fieldsPrefix + this._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.show();

            //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{
				//we need to remove existing drop down
				field.options.length = 1;
                field.options[0].value = suggestion.suggestions[0];
                field.options[0].text = suggestion.suggestions[0];
                if ( !hasPreviousValue ) {
                  if ( previousValue == field.options[0].value ) {
                    hasPreviousValue = true;
                    field.value = previousValue;
                  }
                }

               if ( !hasPreviousValue ) {
                 field.value = "-1"
               }

               //we need to remove existing drop down


              //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.addClassName("error");
                  } else {
                	  field.removeClassName("error");
                  }

                  //We don't want the field to display if we're replacing it with text
                  field.hide();

                  //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();
      }
    }
  };

  this.executeCountryListeners = function (country) {
    if(this.countryListeners) {
  		for(i=0;i<this.countryListeners.length;i++) {
  			this.countryListeners[i].countryCallback(country);
  		}
    }
  }

  this.changeCountry = function () {
    if ( this._getAddressField("country") ) {
      var value = this._getAddressField("country").value;
      this._currentStateDropdownToUpdate = $(this._fieldsPrefix + this._fieldMap["stateProvinceGeoId"]);
      AjaxFacade.getStatesByCountry(value, this._stateDropdownCallback.bind(this));
      AjaxFacade.getAddressConfiguration( value, this._reconfigureAddress.bind(this) );
    }
	this.executeCountryListeners(value);
  };

  this.abstractStateUpdateView = function () {
    //TODO: hack around using custom events. Need to change this when we add a library that supports custom events.
  };

  this._stateDropdownCallback = function (results) {

    var previousValue = this._currentStateDropdownToUpdate.value;
	this._currentStateDropdownToUpdate.selectedIndex = 0;
    this._currentStateDropdownToUpdate.length = results.length + 1;
    this._currentStateDropdownToUpdate.options[0].value = -1;
    this._currentStateDropdownToUpdate.options[0].text = "Choose one...";

    for (i = 0; i < results.length; i++) {
      this._currentStateDropdownToUpdate.options[i+1].value = results[i].value;
      this._currentStateDropdownToUpdate.options[i+1].text = results[i].name;

      if ( previousValue == this._currentStateDropdownToUpdate.options[i+1].value ) {
        this._currentStateDropdownToUpdate.value = previousValue;
      }
    }
    this.abstractStateUpdateView();
  };

  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 = $(this._fieldsPrefix + this._fieldMap[f] );
      if ( control == null ) continue;
      if ( m > 0 ) {
        if ( control.maxLength ) {
          control.maxLength = m;
          var controlValueLength = control.value.length
          if(controlValueLength > 0) {
          	if(controlValueLength > 0) {
          		control.value = control.value.substring(0,m);
          	}
          	if(control.hasClassName('validatableAddressField')) {
          		var addressFieldValidateFunction = Validation.attachAddressValidation.bind(control);
          		addressFieldValidateFunction();
          	}
          }
        }
        if ( control.size ) {
              if ( (m + 2) <= MAX_FIELD_SIZE ) {
            control.size = m + 2;
              } else {
          control.size = MAX_FIELD_SIZE;
              }
        }
      }
    }
  }

}

function updateDropDownFromNameValuePairs( control, results ) {
    var previousValue = control.value;
    	attachAddressValidation = function() {
  		var countryCode = "AU";
  		validateMe(this, countryCode);
	}

    control.length = results.length + 1;
    control.options[0].value = -1;
    control.options[0].text = "Choose one...";

    for (i = 0; i < results.length; i++) {
      control.options[i+1].value = results[i].value;
      control.options[i+1].text = results[i].name;

      if ( previousValue == control.options[i+1].value ) {
        control.value = previousValue;
      }
    }
}
/*
* 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;
  }
}

/*******************************************************************************/
/*                                                                             */
/*        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:	attachAddressValidation:function() {
  		var countryCode = "AU";
  		validateMe(this, countryCode);
	}

          Event.observe(window, "load", attachValidationMethods );
          ...
          ...
          <input type="text" name="blah" class="validatable required etc">
          ...
  */
function _attachValidationMethodsToElements(elements) {
  /**

                                     onblur vs onchange
  We can change the event to "onchange" from "onblur". But there are couple of disadvantages,
  1. if we are changing the value of the text field programatically (for example using Mask),
  then IE won't fire on change event.
  2. If we choose from the form cached data, the browsers (neither IE not firefox) won't trigger
  the onchange event

  But onblur has problems too

  1. It is too aggressive, Even if you didn't change the value it will try to validate it as soon as
  the fields loses its focus.

  So, please change this carefully, if you need to

  **/


  for (var x = 0; x < elements.length; x++) {
    Event.observe(elements[x], "blur", Validation.attachValidation.bindAsEventListener(elements[x]));
  }
  elements = document.getElementsByClassName("validatableAddressField");  // Attach AJAX
  for (var x = 0; x < elements.length; x++) {
    Event.observe(elements[x], "blur", Validation.attachAddressValidation.bindAsEventListener(elements[x]));
  }
  elements = document.getElementsByClassName("required");  // Attach Javascript
  for (var x = 0; x < elements.length; x++) {
    Event.observe(elements[x], "blur", Validation.attachRequiredValidation.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], "blur", Confirmation.attachConfirmation.bindAsEventListener(fieldsToConfirm[0]));
      Event.observe(fieldsToConfirm[1], "blur", Confirmation.attachConfirmation.bindAsEventListener(fieldsToConfirm[1]));
    }
  }
}

function attachValidationMethods() {
	var elements = document.getElementsByClassName("validatable");  // Attach AJAX
	_attachValidationMethodsToElements(elements);
}

function attachValidationMethodsToElementChildren(elementId) {
	var elements = $(elementId).getElementsByClassName("validatable");
	_attachValidationMethodsToElements(elements);
}

var Validation = {

	attachValidation:function () {
		validateMe(this);
	},

	attachAddressValidation:function() {
		var prefix = this.id.substring( 0, this.id.lastIndexOf("_"));
		var countryGeoId = "countryGeoId";
		var countryControlName = (prefix) ? prefix + "_" + countryGeoId : countryGeoId;
		var countryCode = $(countryControlName).value;
		validateMe(this, countryCode);
	},

	attachRequiredValidation:function() {
		resetError(this);
		if (!Validation.checkForRequired(this)) {
			var a = new Array(2);
            a[0] = this.id;
            a[1] = " This field is required";;
        	validateFieldCallback(a);
        }
	},

	checkForRequired:function(field) {
		var result=true;
		if ( field.value == "" || field.value == "-1" ) {
			result=false;
		}
		return result;
	}
};

var Confirmation = {
attachConfirmation:function () {
  var name = this.name;
  var fieldsToConfirm = document.getElementsByName(name);
  var thisField = $(this);
  if ( fieldsToConfirm && fieldsToConfirm.length == 2) {
    confirmFields(fieldsToConfirm[0], fieldsToConfirm[1], this);
  }
  thisField.addClassName("touched");
}

};
function validateMe(field, marketName) {
	// reset error in case of differences
	resetError(field);
	validateRequired(field, null, null, marketName);
}

function resetError(field) {
	var field = $(field.id);
  field.removeClassName("error");

	var messageElement = $(field.id + "-error");
  messageElement.hide();
	messageElement.update();

}

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 field = $(fieldId);
  var errorField = $(fieldId + "-error");

  if ( errorMessage != "") {
    if (errorMessage != "") field.addClassName("error");
    if (errorField) {
      errorField.update(errorMessage);
		  errorField.show();
    } else {
      alert("Cannot find the XHTML Field : " + fieldId + "-error");
    }
  } else {
    field.removeClassName("error");
    errorField.hide();
    errorField.update();
  }

}
function validateFieldsCallback(valArray) {

  if (valArray[0] == "error") {
    $(valArray[1]).addClassName("error");
    $(valArray[3]).show();
    $(valArray[1] + "-error").update(valArray[2]);
  } else {

    $(valArray[1]).removeClassName("error");
    $(valArray[3]).hide();
    $(valArray[1] + "-error").update();
  }
}
function validateGeneral() {
  var isValid = true;
  elements = document.getElementsByClassName("required");
  elements = elements.concat(document.getElementsByClassName("confirming"));
  for (var x = 0; x < elements.length; x++) {
    var element = $(elements[x]);
    if (!element.disabled && !element.readonly) {
      if (!Validation.checkForRequired(element)) {
                                var a = new Array(2);
                                a[0] = element.id;
                                a[1] = "This field is required.";
        validateFieldCallback(a);
                                isValid = false;
      }
    }
  }
  elements = document.getElementsByClassName("validatable");
  for (var x = 0; x < elements.length; x++) {
    var element = $(elements[x]);
    if (!element.disabled && !element.readonly) {
      if ( element.hasClassName("error") ) {  // find a better way to decide if there is an error there already without re-validating.
                                isValid = false;
      }
    }
  }
  elements = document.getElementsByClassName("validatableAddressField");
  for (var x = 0; x < elements.length; x++) {
    var element = $(elements[x]);
    if (!element.disabled && !element.readonly) {
      if ( element.hasClassName("error")) {
                                isValid = false;
      }
    }
  }
  elements = document.getElementsByClassName("confirming");
  for (var x = 0; x < elements.length; x++) {
    var element = $(elements[x]);
    if (!element.disabled && !element.readonly) {
      if ( element.hasClassName("error") ) {  // find a better way to decide if there is an error there already without re-validating.
                                isValid = false;
      }
    }
  }

  return isValid;
}

function confirmFields(field1, field2, fieldBlurredFrom) {
  if (confirmFieldHasBeenTouched(fieldBlurredFrom, field1) ||
      confirmFieldHasBeenTouched(fieldBlurredFrom, field2) ) {

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

function confirmFieldHasBeenTouched(originalField, testField) {
  return originalField != testField && testField.hasClassName("touched");
}

function confirmFieldsCallback(fieldAndMessage) {
  validateFieldCallback(fieldAndMessage);
}

var temp_virtualProductId;
var temp_featureCategories;
var temp_dropDownIds;
var temp_virtualFieldId;

function FeatureDropDowns(virtualFieldId, virtualProductId, featureCategories) {
  this._virtualFieldId = virtualFieldId;
  this._virtualProductId = virtualProductId;
  this._featureCategories = featureCategories;
  this._dropDownIds = new Array(this._featureCategories.length);
  this._firstDropDown;

  for ( var i = 0; i < this._featureCategories.length; i++ ) {
    this._dropDownIds[i] = this._featureCategories[i] + "_" + this._virtualProductId;
  }

  this.selectFeature = function(dropDown) {
    temp_virtualProductId = this._virtualProductId;
    temp_featureCategories = this._featureCategories;
    temp_dropDownIds = this._dropDownIds;
    temp_virtualFieldId = this._virtualFieldId;

    if ( !this._firstDropDown ) this._firstDropDown = dropDown;

    // if they select "choose one...", then let's just choose the first selected drop-down as the first drop-down, in its stead.
    if ( this._firstDropDown && this._firstDropDown.value == "" ) {
      this._firstDropDown = null;
      for ( var j = 0; j < this._dropDownIds.length; j++ ) {
        var candidateDropDown = $(this._dropDownIds[j]);
	if ( candidateDropDown && candidateDropDown.value != "" ) {
          this._firstDropDown = candidateDropDown;
        }
      }
    }

    var _selectedFeatures = this._getSelectedFeatures();
    var _selectedFeatureCategories = this._getSelectedFeatureCategories();

    if ( _selectedFeatures.length == this._featureCategories.length ) {
      AjaxFacade.getVariantProductId(this._virtualFieldId, this._virtualProductId, _selectedFeatureCategories, _selectedFeatures, this._getVariantProductIdCallback);
    } else {
      AjaxFacade.getFeatures(this._virtualFieldId, this._virtualProductId, _selectedFeatureCategories, _selectedFeatures, this._getFeaturesCallback);
    }
  }

  this._getSelectedFeatureCategories = function() {
      var _selectedFeatureCategories = new Array();
      if ( this._firstDropDown )
        _selectedFeatureCategories[0] = this._firstDropDown.name;
      for ( var i = 0; i < this._dropDownIds.length; i++ ) {
        if ( (!this._firstDropDown || this._dropDownIds[i] != this._firstDropDown.id) && $(this._dropDownIds[i]) ) {
          _selectedFeatureCategories[_selectedFeatureCategories.length] = $(this._dropDownIds[i]).name;
        }
      }
      return _selectedFeatureCategories;
  }

  this._getSelectedFeatures = function() {
      var _selectedFeatures = new Array();
      if ( this._firstDropDown )
        _selectedFeatures[0] = this._firstDropDown.value;
      for ( var i = 0; i < this._dropDownIds.length; i++ ) {
        if ( (!this._firstDropDown || this._dropDownIds[i] != this._firstDropDown.id) && $(this._dropDownIds[i]) && $(this._dropDownIds[i]).value != "" ) {
          _selectedFeatures[_selectedFeatures.length] = $(this._dropDownIds[i]).value;
        }
      }
      return _selectedFeatures;
  }

  this._getFeaturesCallback = function(returnValues) {
    var temp_virtualFieldId = returnValues[0];
    var temp_featureCategories = returnValues[1];
    var temp_virtualProductId = returnValues[2];
    var newFeatureDropDowns = returnValues[3];

    for ( var i = 0; i < temp_featureCategories.length; i++ ) {
      var features = newFeatureDropDowns[temp_featureCategories[i]];
      var dropDownId = $(temp_featureCategories[i] + "_" + temp_virtualProductId);
      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 = features[j];
      }
    }

    $(temp_virtualFieldId).value = "";
  }

  this._getVariantProductIdCallback = function(returnValues) {
    var temp_virtualFieldId = returnValues[0];
    var variantProductId = returnValues[1];

    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;
    }
  }
}
