/*
 * The filtermap is a map of key,val pairs. The object is checked for the key. If it exists then
 * the corresponding value is compared to the value specified in filtermap. If they are unequal
 * the match fails
 */
var ObjectFilter = function(filterMap)
{
  this.filterMap = filterMap;
  var matchesAll = 'All';

  this.matches = function(object)
  {
    for(key in filterMap)
    {
      var trimmedValue = Trim(filterMap[key]);
      if(object[key] != undefined && trimmedValue != "" && trimmedValue != matchesAll && object[key] != trimmedValue && object[key] != filterMap[key])
      {
        return false;
      }
    }
    return true;
  }
}

/*
 * Used to store a set of objects under a key(which is a property of that object)
 * keyPropName   : The property of the object that is used as key. Note that the object is stored only if the key exists
 */
var Set = function(keyPropName)
{
  this.keyPropName = keyPropName;
  this.values = {};

  this.add = function(object)
  {
    if(!object[this.keyPropName])
    {
      return;
    }
    this.values[object[this.keyPropName]] = object;
  }

  this.remove = function(value)
  {
    this.values[value] = false;
  }
}

/*
 * name     : Name of select box
 * propName   : Name that is searched for in object for display text
 * valueName : Name that is searched for in object for selected value
 * isRequired: If false a value All is added
 * allValueDisplay : The display text value for the 'all' option
 */
var SelectBox = function(name, propName, valueName, isRequired, allValueDisplay, objSorter)
{
  this.name = name;
  this.propName = propName;
  this.valueName = valueName;
  this.isRequired = isRequired;
  this.selectVehicleValue;

  if(objSorter)
  {
    this.objSorter = objSorter;
  }

  this.allValueDisplay = (allValueDisplay)? allValueDisplay : "All";

  /*
   * Adds an option to select box
   */
  this.addOption = function(selectElement, option)
  {
    try
    {
      selectElement.add(option, null);
    }
    catch(ex)
    {
      selectElement.add(option);
    }
  }

  /*
   * Returns the selected value for this select box
   */
  this.getVal = function(formElement)
  {
    return formElement[this.name].options[formElement[this.name].selectedIndex].value;
  }

  /*
   * Removes all elements. Adds an 'All' selection if required
   */
  this.clear = function(formElement)
  {
    formElement[this.name].innerHTML = "";
    if(!this.isRequired)
    {
      var allOption = document.createElement('option');
      allOption.value = 'All';
      allOption.text = this.allValueDisplay;
      this.addOption(formElement[this.name], allOption);
    }
  }

  /*
   * Populates the this.propName from Obsectset in this select box
   */
  this.populate = function(objectSet, formElement)
  {
    this.clear(formElement);
    // Need to create a set of values(We don't want to populate a value more than once)
    var optionSet = new Set('text');

    for(object in objectSet)
    {
      var option = document.createElement('option');
      option.value = objectSet[object][this.valueName];
      option.text = objectSet[object][this.propName];

      if(option.value && option.text)
      {
        optionSet.add(option);
      }
    }

    var optionList = [];
    var index = 0;
    for(var i in optionSet.values)
    {
      optionList[index] = optionSet.values[i];
      index++;
    }

    if(this.objSorter)
    {
      var optionSorter = new ObjectSorter('text',simpleComparator);
      optionList = optionSorter.sort(optionList);
    }

    for(var j in optionList)
    {
      this.addOption(formElement[this.name], optionList[j]);
    }
    
    if(typeof(newInvSearch) != "undefined" && newInvSearch.isCheckUrlReqPara)
    {
        this.checkUrlReqPara(formElement,optionList,objectSet);
    }
    else if(typeof(newInventorySearch) != "undefined" && newInventorySearch.isCheckUrlReqPara)
    {
        this.checkUrlReqPara(formElement,optionList,objectSet);
    }
  };
  
  this.checkUrlReqPara = function(formElement,optionList,objectSet)
  {
    var vehiclePara = "vehicle";
    var urlReqPara = getRequestParams();
    var urlReqParaValue;
    urlReqParaValue = ( this.valueName == "id") ? unescape(urlReqPara[vehiclePara]):unescape(urlReqPara[this.valueName]);
    if ( urlReqParaValue != undefined && urlReqParaValue != 'undefined')
    {
      if ( this.checkIsValid(urlReqParaValue, optionList) )
      {
        formElement[this.name].value = this.selectVehicleValue;
        if( this.name == "Model")
        {
          for(object in objectSet)
          {
            if( urlReqParaValue.toLowerCase() == objectSet[object][this.propName].toLowerCase() )
            {
              formElement["Make"].value = objectSet[object]["make"];
            }
          }
        }
          this.selectVehicleValue = "";
      }
      else
      {
        formElement[this.name].value = optionList[0].value;
      }
    }
  };

  this.checkIsValid = function(urlReqParaValue, optionList)
  {
    var isMatch = false;
    for(var i in optionList)
    {
      if( urlReqParaValue.toLowerCase() == optionList[i].text.toLowerCase() )
      {
        this.selectVehicleValue = optionList[i].value;
        isMatch = true;
      }
      else if( urlReqParaValue.toLowerCase() == this.allValueDisplay.toLowerCase() )
      {
        this.selectVehicleValue = this.allValueDisplay;
        isMatch = true;
      }
    }
    return isMatch;
  };
}

/*
 * Used to Filter based on a Text field, where value is entered by the user
 * name      : Name of Text Field
 * valueName : Name of the field to be searched for in Object
 */
var TextField = function(name,valueName)
{
  this.name = name;
  this.valueName = valueName;

  this.populate = function(objectSet, formElement)
  {
    // No need to populate a text field
  }

  this.getVal = function(formElement)
  {
    return formElement[this.name].value;
  }
}

/*
 * FormName    Name of the form.
 * selectList  List of selection filters
 * allModels  List of models
 * crossFiltering  boolean to disable/enable crossFiltering
 */
var ModelSearch = function(formName, selectList, allModels, crossFiltering)
{
  // The list of selection boxes that are to be populated
  // The dependency is assumed to be 0->1->2 ...
  this.selectList = selectList;
  this.invForm = document.forms[formName];
  this.allModels = allModels;
  this.currentSelection = [];
  this.crossFiltering = crossFiltering;
  this.isCheckUrlReqPara = true;

  /*
   * Initializes the object. Populates the select boxes
   */
  this.init = function()
  {
    this.currentSelection = this.allModels;
    this.refreshSelects(-1);
    this.selectionChanged(0);
  }

  /*
   * Index denotes selectBox in the selectList that has changed
   */
  this.selectionChanged = function(index)
  {
    // If cross filtering is disabled don't do any thing
    if(!this.crossFiltering)
    {
      return;
    }

    this.filterModels(index);
    this.refreshSelects(index);
  }

  /*
   * Selects vehicles based on the set of values set for selects <= index
   */
  this.filterModels = function(index)
  {
    var filterMap = {};
    for(var i = 0;i <= index; i++)
    {
      filterMap[this.selectList[i].valueName] = this.selectList[i].getVal(this.invForm);
    }

    var filter = new ObjectFilter(filterMap);
    this.currentSelection = [];
    var counter = 0;

    for(i in this.allModels)
    {
      if(filter.matches(this.allModels[i]))
      {
        this.currentSelection[counter] = this.allModels[i];
        counter++;
      }
    }
  }

  /*
   * Refreshes the models that are displayed depending upon the current selections
   */
  this.refreshSelects = function(index)
  {
    for(var i = index + 1; i< this.selectList.length; i++)
    {
      this.selectList[i].populate(this.currentSelection, this.invForm);
    }
  }
}
