var Search = {
  
  WAIT_TIMEOUT:           800,
  DURATION_MAPPING:       {_21: "3Weeks", _14: "2Weeks", _7: "1Week", _3: "LongWeekend", _2: "Weekend", _4: "Midweek"},
  COUNTRY_MAPPING:        {Belgium: 1, Germany: 2, Netherlands: 13, Austria: 14},

  _allDropDowns:          null,
  _allInputs:             null,
  
  _country:               0,
  _area:                  0,
  _price:                 0,
  _duration:              0,
  
  _countryEl:             null,
  _areaEl:                null,
  _priceEl:               null,
  _durationEl:            null,
  
  _cache:                 [],

  /**
   * Set internal variables and references
  **/
  doLoad: function()
  {
    if (!document.getElementById('dropdowns') || !document.getElementById('checkboxen'))
      return false;
  
    this._allDropDowns  = document.getElementById('dropdowns').getElementsByTagName('select');
    this._allInputs     = document.getElementById('checkboxen').getElementsByTagName('input');
    
    this._countryEl     = this._allDropDowns[0];
    this._arrivalDateEl = this._allDropDowns[2];
    this._areaEl        = this._allDropDowns[3];
    this._durationEl    = this._allDropDowns[4];
    this._priceEl       = this._allDropDowns[5];
    
    this._country       = this.getValue(this._countryEl);
    this._arrivalDate   = this.getValue(this._arrivalDateEl)
    this._area          = this.getValue(this._areaEl);
    this._price         = this.getValue(this._priceEl);
    this._duration      = this.getValue(this._durationEl);
    
    this.initSearchBox();
  },
  
  getValue: function(el)
  {
    return el && el.options ? el.options[el.selectedIndex].value : null;
  },
  
  /**
   * Initialise some elements, attach some handlers, reset some dropdowns
  **/
  initSearchBox: function()
  {
    var countrySelected = this._country.length > 0;
    this.toggle(countrySelected);
    
    if (countrySelected)
    {
      this.handleCountryChange();
      this.handleDurationChange();
    }
    else
    {
      // no country selected, meaning no handlers executed.. show first price dropdown as default
      Spif.ClassNameAbstraction.add(this._priceEl, "show");
    }
    
    //this.setStayTypes(this._country == this.COUNTRY_MAPPING["Netherlands"] || this._country == this.COUNTRY_MAPPING["Belgium"]);
    this.setStayTypes(this._country.substring(0,2) == "Be" || this._country.substring(0,2) == "Ne" || this._country.substring(0,3) == "Nie");
    
    this.attachEventListeners();
  },
  
  attachEventListeners: function()
  {
    Spif.DOMEvents.attach(this._countryEl, "change",  this.handleCountryChange, this);
    Spif.DOMEvents.attach(this._durationEl, "change", this.handleDurationChange, this);
    
    Spif.DOMEvents.attach(document.getElementById('searchbox').getElementsByTagName('form')[0], "submit", this.handleSubmit, this);
    
    for (var i = 0; i < this._allDropDowns.length; i++)
    {
      var dd = this._allDropDowns[i];
      // arrival dates should be reloaded when changing any dropdown except numpersons and arrivaldate 
      if (i != 1 && i != 2 && i != 3) Spif.DOMEvents.attach(dd, "change", this.reloadArrivalDates, this);
      if (i > 0)  Spif.DOMEvents.attach(dd, "change", this.toggleDropDownColoration, this);
      Spif.DOMEvents.attach(dd, "keydown", this.handleKeyDown, this);
    }
    
  },
  
  handleKeyDown: function(evt)
  {
    var el = evt.subject;
    if (evt.keyCode == 13)
      document.getElementById('searchbox').getElementsByTagName('form')[0].submit();
  },
  
  /**
   * When we change our country selection, load a new area list appropriate for the newly selected country
  **/
  handleCountryChange: function(evt)
  {
    var el = this._countryEl;
    var selectedCountry = this.getValue(el); // new selection
    var currentCountry = this._country; // old selection
    var countrySelected = selectedCountry.length > 0;
    var currentInCache = (this._cache["area" + currentCountry] != null);
    
    if (countrySelected)
    {

      // if the old area has more than 2 options, it's filled, so add it to the cache
      if (!currentInCache && this._areaEl.options.length > 2)
        this._addToCache("area", currentCountry);
        
      var selectedInCache = (this._cache["area" + selectedCountry] != null);

      // if the new area isn't in the cache yet, fetch it from the server
      if (!selectedInCache)
      {
        this._areaEl.options[0].innerHTML = Resources.Global.Wait;
        xmlhttp.request({
          url:                      "/Search/GetAreaList.aspx?date=" +
            new Date().getTime() + "&areaNum=" + selectedCountry,
          send:                     "",
          asynchronous:             true,
          processReqChangeFunction: "Search._updateAreaListFromServer",
          post:                     false
        });
      }
      else
        this._updateListFromCache("area", selectedCountry);
      
      //Search.setStayTypes(selectedCountry == Search.COUNTRY_MAPPING["Belgium"] ||
        //selectedCountry == Search.COUNTRY_MAPPING["Netherlands"]);
      Search.setStayTypes(selectedCountry.substring(0,2) == "Be" || selectedCountry.substring(0,2) == "Ne" || selectedCountry.substring(0,3) == "Nie");
      
      //Search.reloadArrivalDates();
      Search.showArrivalDates();
    }

    // update the current country with our new selection
    this._country = selectedCountry;
  
    // handle dependencies on other dropdowns
    setTimeout(function() {
      this.toggle(countrySelected);
    }.closure(this), this.WAIT_TIMEOUT);
    
  },
  
  /**
   * When we change duration, we show an appropriate pricing dropdown
  **/
  handleDurationChange: function()
  {
    var el = this._durationEl;
    var selectedDuration = this.getValue(el);
    var mapping = this.DURATION_MAPPING;
        
    // If we selected a duration
    if (selectedDuration > 0)
    {
      // reset and hide old price el
      if (selectedDuration != this._duration)
      {
        this._resetDropDown(this._priceEl);
        this._disableDropDown(this._priceEl);
        Spif.ClassNameAbstraction.remove(this._priceEl, "show");
      }      
      
      // set new price el
      var newPriceEl = document.getElementById('prices' + mapping["_" + selectedDuration]);
      if (!newPriceEl)
        newPriceEl = this._priceEl;
      
      // reset and show the new price list
      Spif.ClassNameAbstraction.remove(newPriceEl, "selected");
      newPriceEl.disabled = false;
      Spif.ClassNameAbstraction.add(newPriceEl, "show");
      
      // update current price dropdown
      this._priceEl = newPriceEl;
      
      // update current duration
      this._duration = selectedDuration;
    }
      
    // Otherwise, disable it and return
    else
    {
      this._duration = 0;
      this._disableDropDown(this._priceEl);
      Spif.ClassNameAbstraction.add(this._priceEl, "show");
      return;
    }

  },
  
  handleSubmit: function(evt)
  {
    // we can only submit 1 price dropdown on each search, so remove all disabled dropdowns
    var dropDowns = document.getElementById('priceDropDowns');
    var selects = dropDowns.getElementsByTagName('select');
    for (var i = selects.length - 1; i >= 0; i--)
    {
      var select = selects[i];
      if (select.disabled)
        dropDowns.removeChild(select);
    }
  },
  
  
  
  /**
   * Attach an event handler to a <select> that resets it if the user tries to select an <option> that has disabled=true
  **/
  _attachDisabledDropDownOptionListener: function(dropDown)
  {
    Spif.DOMEvents.attach(dropDown, "change", function() {
      if (this.options[this.selectedIndex].disabled)
        this.selectedIndex = 0;
    }, dropDown);
  },
  
  
  
  
  /**
   * Remove class=selected, reset selection, and set disabled=false on a <select>
  **/
  _resetDropDown: function(dropDown)
  {
    Spif.ClassNameAbstraction.remove(dropDown, "selected");
    dropDown.selectedIndex = 0;
    dropDown.disabled = false;
  },
  
  /**
   * Remove class=hidden, set disabled=false, and set colour to black on an <option>
  **/
  _resetDropDownOptions: function()
  {
    for (var i = 0; i < arguments.length; i++)
    {
      var option = arguments[i];
      Spif.ClassNameAbstraction.remove(option, "hidden");
      option.style.color = "black";
      option.disabled = false;
    }
  },
  
  /**
   * Set disabled=true on a <select>
  **/
  _disableDropDown: function(dropDown)
  {
    dropDown.disabled = true;
  },
  
  /**
   * Set disabled=false and class=hidden on an <option> .. colour the text gray too
  **/
  _disableDropDownOptions: function()
  {
    for (var i = 0; i < arguments.length; i++)
    {
      var option = arguments[i];
      Spif.ClassNameAbstraction.add(option, "hidden");
      option.style.color = "#aaa";
      option.disabled = true;
    }
  },
  _enableDropDownOptions: function()
  {
    for (var i = 0; i < arguments.length; i++)
    {
      var option = arguments[i];
      Spif.ClassNameAbstraction.remove(option, "hidden");
      option.style.color = 'black';
      option.disabled = false;
    }
  },
  
  
  
  
  /**
   * Store a dropdown in the cache
  **/
  _addToCache: function(name, index)
  {
    var dd = this["_" + name + "El"].cloneNode(false);
    dd.innerHTML = this["_" + name + "El"].innerHTML;
    this._cache[name + index] = dd.innerHTML;
  },
  
  
  
  
  /**
   *  Put the results of an xmlhttp call to GetAreaList.aspx into the area dropdown
  **/
  _updateAreaListFromServer: function()
  {
    var result = xmlhttp.req["Search._updateAreaListFromServer"];
    try {
      if (result.readyState == 4 && result.status == 200)
      {
        var basicOptions = '<option value="">' + Resources.Global.Area + '</option><option value="">' +
                            Resources.Global.NoPreference + '</option>';

        Search._areaEl = Search._getNewDropDown(Search._areaEl, basicOptions + result.responseText);
        
        Spif.DOMEvents.attach(Search._areaEl, "change", Search.reloadArrivalDates, Search);
        Spif.DOMEvents.attach(Search._areaEl, "change", Search.toggleDropDownColoration, Search);
      }
    }
    catch (e) {}
  },
  
  toQueryString: function()
  {
    var str = "?date=" + new Date().getTime();
    for (var i = 0; i < this._allDropDowns.length; i++)
    {
      if (i == 1 || i == 3) continue;
      var dd = this._allDropDowns[i];
      var value = this.getValue(dd);
      if (value.length > 0 && !dd.disabled)
        str += "&" + dd.name + "=" + dd.value;
    }
    return str;
  },
  
  reloadArrivalDates: function(evt)
  {        
    if (evt.subject.selectedIndex == 0) return;
    this._arrivalDateEl.options[0].innerHTML = Resources.Global.Wait;
    this._arrivalDateEl.disabled = true;
    xmlhttp.request({
      url:                      "/Search/GetArrivalDateList.aspx" + this.toQueryString(),
      send:                     "",
      asynchronous:             true,
      processReqChangeFunction: "Search._updateArrivalDateListFromServer",
      post:                     false
    });    
  },
  _updateArrivalDateListFromServer: function()
  {
    var result = xmlhttp.req["Search._updateArrivalDateListFromServer"];
    try {
      if (result && result.readyState == 4 && result.status == 200)
      {
        var basicOptions = '<option value="">' + Resources.Global.ArrivalDate + '</option><option value="">' +
                           Resources.Global.NoPreference + '</option>';

        var oldSelectedValue = Search._arrivalDateEl.options[Search._arrivalDateEl.selectedIndex].value;        
        
        Search._arrivalDateEl = Search._getNewDropDown(Search._arrivalDateEl, basicOptions + result.responseText);
        
        // loop through the new dropdown and see if it has the same value as the oldselected
        // if so, reselect
        for (var i = 0; i < Search._arrivalDateEl.options.length; i++)
        {
          var option = Search._arrivalDateEl.options[i];
          if (option.value == oldSelectedValue)
          {
            Search._arrivalDateEl.selectedIndex = i;
            Search._arrivalDate = option.value;
            break;
          }
        }
        
        Spif.DOMEvents.attach(Search._arrivalDateEl, "change", Search.toggleDropDownColoration, Search);        
        Search.showArrivalDates();
      }
    }
    catch (e) {}
  },
  // Remove options whose innerHTML matches any of the members of the "days" array
  // Then loop again and remove all "In %month% %year%" options that are followed by each other (implying they're empty)
  showArrivalDates: function()
  {
    var selectedCountry = Search._country;
//    Search._showArrivalDates(
//      (selectedCountry == Search.COUNTRY_MAPPING["Belgium"] || selectedCountry == Search.COUNTRY_MAPPING["Netherlands"])
//        ?["vr", "ma"]
//        :["za"]
//      );

      // translations!
			Search._showArrivalDates(
				(selectedCountry == Resources.Global.BelgiumUrlized || selectedCountry == Resources.Global.NetherlandsUrlized)
					?["vr", "ma", "fr", "mo"]
					:["za", "sa"]
      );
  },
  _showArrivalDates: function(days)
  {
    var el = this._arrivalDateEl;
    var removedOptions = [];
    
    // remove days that don't match the days param
    for (var i = el.options.length - 1; i >= 2; i--)
    {
      var option = el.options[i];
      var value = option.innerHTML.replace(/^\s+|\s+$/g,"").replace(/\s+/g, ' ').toLowerCase().substring(0,2);      
      
      if (!value.match(days.join("|")) && !Spif.ClassNameAbstraction.contains(option, "month"))
        removedOptions.push(el.removeChild(option));
    }
    
    // loop again and remove duplicate month titles
    for (var i = el.options.length - 1; i >= 2; i--)
    {
      var option = el.options[i];
      var regExStartEndSpace = /^\s+|\s+$/g;
      var regExMultiSpace = /\s+/g;
      var value = option.innerHTML.replace(regExStartEndSpace,"").replace(regExMultiSpace, ' ').toLowerCase().substring(0,2);
      var prevValue = el.options[i-1].innerHTML.replace(regExStartEndSpace,"").replace(regExMultiSpace, ' ').toLowerCase().substring(0,2);
      
      if (Spif.ClassNameAbstraction.contains(option, "month") && value.match("in") && prevValue.match("in"))
        removedOptions.push(el.removeChild(option));
    }
    
    // finally, remove the last option if it's a month title
    var lastOption = el.options[el.options.length - 1];
    if (Spif.ClassNameAbstraction.contains(lastOption, "month"))
      removedOptions.push(el.removeChild(lastOption));
      
  },
  
  setStayTypes: function(all)
  {
    // true = all stay types allowed
    // false = only weeks allowed
    if (!all && this._durationEl.length > 4)
    {
      this._disableDropDownOptions(this._durationEl.options[5], this._durationEl.options[6], this._durationEl.options[7]);
      this._attachDisabledDropDownOptionListener(this._durationEl);
    }
    else
    {
      if (this._durationEl.length > 4)
        this._enableDropDownOptions(this._durationEl.options[5], this._durationEl.options[6], this._durationEl.options[7]);
    }
  },
  
  /**
   * Fetch appropriate dropdown from cache (generic)
  **/
  _updateListFromCache: function(name, index)
  {
    name = name.toLowerCase();
    this["_" + name + "El"] = this._getNewDropDown(this["_" + name + "El"], this._cache[name + index]);
    var selectEl = this["_" + name + "El"];
    
    Spif.DOMEvents.attach(selectEl, "change", this.reloadArrivalDates, this);
    Spif.DOMEvents.attach(selectEl, "change", this.toggleDropDownColoration, this);
  },
  
  /**
   * Return some html used to put a new dropdown in the place of an old one
   * Used when updating the area list
  **/
  _getNewDropDown: function(selectEl, content)
  {
    var div = document.createElement("div");
    selectEl.parentNode.insertBefore(div, selectEl);
    div.appendChild(selectEl.cloneNode(true));
    
    var selectHTML = div.innerHTML;
    selectHTML = selectHTML.substring(0, selectHTML.indexOf(">") + 1);
    selectHTML += content;
    selectHTML += "</select>";
    div.innerHTML = selectHTML;
    
    var newSelectBox = div.firstChild;
    selectEl.parentNode.insertBefore(newSelectBox, selectEl);
    selectEl.parentNode.removeChild(div);
    selectEl.parentNode.removeChild(selectEl);
    newSelectBox.disabled = false;
    return newSelectBox;
  },
  
  
  
  toggle: function(countrySelected)
  {
    // The functioning of the searchbox depends on whether a country is selected
    // if a country is selected:
    if (countrySelected)
    {
      // - all dropdowns, inputs and the search button become active
      this.toggleDropDowns(true);
      this.toggleInputs(true);
      
      // - the selected country becomes green
      this.toggleDropDownColoration();
      if (this._area.length > 0)
        Spif.ClassNameAbstraction.add(this._areaEl, "selected");
      
      // - price becomes inactive IF no duration is selected
      if (this._duration.length == 0)
        this._disableDropDown(this._priceEl);
    }
    
    // if no country is selected:
    else
    {
      // - all dropdowns, inputs and the search button become disabled
      this.toggleDropDowns(false);
      
      // - all dropdowns have their selectedindex set to 0
      this.toggleInputs(false);
      
      // - all dropdowns have their colour removed
      this.toggleDropDownColoration();
    }
  },
  
  /**
   * Logic for toggling disabled attribute on dropdowns depending on countrySelected
  **/  
  toggleDropDowns: function(countrySelected)
  {
    var durationSelected = this._duration > 0;
    for (var i = 1; i < this._allDropDowns.length; i++)
    {  
      // Price is an exception: only enable the prices associated with the selected duration
      var dd = this._allDropDowns[i];
      var selectedDuration = "prices" + this.DURATION_MAPPING["_" + this._duration];
      var isPriceDropDown = /priceDropDown\b/.test(dd.className);
      
      // 20061114: Empty all selections if no country is selected
      if (!countrySelected)
        dd.selectedIndex = 0;
      
      if (isPriceDropDown)
      {
        if (dd.id == selectedDuration)
          dd.disabled = !(countrySelected && durationSelected);
        else
          dd.disabled = true;
      }
      else
      {
        dd.disabled = !countrySelected;
      }
    }
  },
  
  /**
   * Disable checkboxes and search button if no country selected, otherwise enable them
  **/
  toggleInputs: function(countrySelected)
  {
    for (var i = 0; i < this._allInputs.length; i++)
    {
      var input = this._allInputs[i];
      input.disabled = !countrySelected;
      if (input.type == "image")
        input.src = countrySelected ?
          ("/images/" + Resources.Images.Searchbutton) :
          ("/images/" + Resources.Images.SearchbuttonDisabled);
    }
  },
  
  /**
   * Make dropdowns green or not depending on whether they're set to a value
   * If an event is passed, this is executed as an event handler; otherwise, it runs on all dropdowns
   * Whatever happens, an unselected dropdown can't be coloured!
  **/
  toggleDropDownColoration: function(evt)
  {
    for (i = 0; i < (evt ? 1 : this._allDropDowns.length); i++)
    {
      var dd = evt ? evt.subject : this._allDropDowns[i];
      var isSelected = dd.options.length > 0 && this.getValue(dd).length > 0;
      Spif.ClassNameAbstraction[isSelected ? "add" : "remove"](dd, "selected");
    }
  }
  
};

FireOnLoad(Search.doLoad.closure(Search));