/**
 *
 * @namespace
 */
ta.util.Toggle = {}

/**
 * Toggles (between block and none) all sibling nodes.
 * @param {Event} evnt The Event
 * @param {Element} elmt The Element
 */
ta.util.Toggle.siblings = function(evnt, elmt) {
  evnt.preventDefault();
  var open = true;
  if (elmt.hasClass('closed')) open = false;
  elmt.toggleClass('closed');
  elmt.getParent().getChildren().each(function(n) {
    if (n != elmt) n.setStyle('display', open ? 'none' : 'block');
  });
};

ta.util.Toggle.parentClass = function(evnt, elmt) {
  evnt.preventDefault();
  var parent = elmt.getParent('.toggle');
  parent.toggleClass('off');
};

/**
 * 
 * @param {Element} input radio button clicked on
 * @param {String} formType form type to toggle on
 * @param {Event} evnt The Event
 * @returns {boolean} false
 */
ta.util.Toggle.toggleForm = function(input, formType, event) {
  var container = $(input).getParent('.formToggle');
  if (/sel_(\w+)/.test(container.className)) {
    var sel = RegExp.$1;
    container.removeClass('sel_'+sel);
    container.getElement('.form_'+sel).hide();
    var hdr = container.getElement('.header_'+sel);
    if (hdr) hdr.hide();
  }
  container.addClass('sel_'+formType);
  var hdr = container.getElement('.header_'+formType);
  if (hdr) hdr.show();
  container.getElement('.form_'+formType).show();
  return false;
};

/**
 * Toggle for a group of siblings elements where there is element for show, folloed by elements to show, followed by an element to hide.
 */
ta.util.Toggle.toggleLI = function(showElmt, hideElmt, show)
{
  var nextE = showElmt.getNext();

  // Loop siblings (or some reasonable max) until the hide element is reached.
  for(var i = 0; i<1000 && nextE && nextE.id != hideElmt.id; i++) {
    if (show) nextE.show(); else nextE.hide();
    nextE = nextE.getNext();
  }

  if (show) showElmt.hide(); else showElmt.show();
  if (show) hideElmt.show(); else hideElmt.hide();
};
/** @namespace */
ta.util.element = {};

/*
 * Replace the contents of an element via XHR
 */
ta.util.element.replaceContent = function(/* Event */ event,
                                          /* HTMLElement */ element,
                                          /* String */ href)
{
    //  local copies for our callbacks
    var myEvent = event;
    var myElement = element;

    //  if we haven't already sent a request (filters out double clicks)
    if (!myElement.getElement('.progresstab'))
    {
        //  add an 'xhr' request parameter to indicate what this is for
        var myHref = href + (href.indexOf('?') == -1 ? '?' : '&') + 'xhr=true';

        // Set content to placeholder graphic
        var imgCntr = new Element('div', { 'class': 'progresstab' } );
        (new Asset.image("/img2/generic/site/loop.gif")).injectInside(imgCntr);
        imgCntr.injectInside(myElement);

        // Make AJAX call to get content.
        new Ajax(myHref,
        {
            onComplete: function(txt, xml)
            {
                myElement.empty();
                myElement.innerHTML = txt;

                // apply any defined behavior
                if (window.behavior)
                {
                    window.behavior.apply(myElement);
                }

                //  notify anyone listening we are done
                myElement.fireEvent('onContentReplaced', [myEvent, myElement]);
            },
            evalScripts:true
        }).request();
    }
};/**
 * @class
 * Adds support for storing information in the location hash.
 *
 * @author wasche
 * @since  2009.02.16
 */
ta.util.LocationHash = Hash.extend({
  VERSION: '02', // this must start with 0

  /**
   * Parses the location hash.
   */
  load: function() {
    hash = window.location.hash.replace(/^#/, '');
    this.parse(hash);
    this._loaded = true;
    if (!this.empty()) this.fireEvent('onLoad', this);
    return this;
  },

  /**
   * Function to call after the location hash is parsed.
   * @name ta.util.LocationHash#onLoad
   * @event
   * @param {Hash} options The options
   */

  /**
   * Update the location hash.
   */
  save: function() {
    window.location.hash = '#' + this.asString();
    return this;
  },

  /**
   * Checks the emptyness of this Hash.
   * @returns {boolean} true if there are no keys in this Hash
   */
  empty: function() {
    return this.length == 0;
  },

  /**
   * Parses a string version of a LocationHash, as built by toString().
   * @example new LocationHash().parse(str)
   * @param {String} str String version of a LocationHash
   * @returns {LocationHash} This LocationHash
   */
  parse: function(str) {
    if (str.length < 1) return this;
    ops = str.split(',');
    version = (/^0\d+$/.test(ops[0])) ? parseInt(ops.shift()) : false; // remove version #
    time = (/^\d+$/.test(ops[0])) ? ops.shift() : false; // remove timestamp
    if (time && !version) return this; // OLD hac search - not backwards compat, ignore
    ops.each(function(op){
      kv = op.split(':');
      if (kv.length != 2) return;
      t = kv[1].charAt(0);
      v = unescape(kv[1].substring(1));
      switch(t) {
        case 'B': v = (v == 't'); break;
        case 'A': v = v.split('|'); break;
        case 'S': v = v.replace(/\|/g,','); break;
        default:
          break;
      }
      this.set(kv[0], v);
    }, this);
    return this;
  },

  /**
   * Returns a string representation of this LocationHash, suitable for passing to parse().
   * @returns {String} string representation of this hash
   */
  asString: function() {
    str = this.collect(function(v, k){
      ret = k + ':';
      switch ($type(v)) {
        case 'string':
          ret += 'S' + v.replace(/,/g,'|'); break;
        case 'array':
          ret += 'A' + v.join('|');
          break;
        case 'boolean':
          ret += 'B' + (v ? 't' : 'f'); break;
        default:
          ret += '-' + v;
          break;
      }
      return ret;
    }).join(',');
    return [this.VERSION, new Date().getTime().toString(), str].join(',');
  },

  /**
   * Returns true if the LocationHash has already been loaded.
   * @returns {boolean} true if LocationHash is loaded, false if not.
   */
  loaded: function() { return this._loaded; }
});
ta.util.LocationHash.implement(new Events);
ta._locationHash = new ta.util.LocationHash();

// need this to be loaded first
ta._loadQ.unshift(ta._locationHash.load.bind(ta._locationHash));

/**
 * @class
 * Interface for interacting with the LocationHash. Call registerForLocationHash after your class
 * is set up (usually as last thing in initialize). Implement the function restoreOptions:
 * <pre>
 *   restoreOptions: function(options) {
 *     // handle any options
 *     if (options.hasKey('optionA')) {
 *       var optionA = options.get('optionA');
 *     }
 *   }
 * </pre>
 */
ta.util.Saveable = new Class({
  /**
   * Registers this class with the LocationHash.
   */
  registerForLocationHash: function() {
    ta._locationHash.addEvent('onLoad', this.restoreOptions.bind(this, ta._locationHash));
    if (ta._locationHash.loaded() && !ta._locationHash.empty()) this.restoreOptions(ta._locationHash);
  },

  /**
   * Saves the current options.
   */
  saveOptions: function() {
    ta._locationHash.save();
  },

  /**
   * Records an option in the hash. In order for it to persist, you must call saveOptions().
   * @param {String} key The key
   * @param {mixed} value The value
   */
  setOption: function(key, value) {
    ta._locationHash.set(key, value);
  },

  /**
   * Removes and option from the hash. In order for it to persist, you must call saveOpotions().
   * @param {String} key The key
   */
  removeOption: function(key) {
    ta._locationHash.remove(key);
  }
});

/**
  @class
  ProgressBar widget.
  
  @option {integer} [overload=20]       Additional % to increase towards while waiting for a response.
  @option {integer} [delay=100]         Delay in ms between updates
  @option {integer} [distance=1]        Ratio of distance to move
  @option {integer} [speed=1500]        Time in ms to cover the distance
  @option {String}  [text=.bar span b]  Selector to get text element
  @option {String}  [bar=.bar .pcnt]    Select to get bar element
  @option {integer} [limit=100]         Maximum number of results
*/
ta.widgets.ProgressBar = new Class({
  options: {
    overload: 20,
    delay: 100,
    distance: 1,
    speed: 1500,
    text: '.text b',
    bar: '.bar .pcnt',
    limit: 100
  },
  
  /**
    @param {Element} elmt container
    @param {object} options See below.
  */
  initialize: function(elmt, options) {
    this.setOptions(options);
    this.ctnr = elmt;
    this.text = this.ctnr.getElement(this.options.text);
    this.bar = this.ctnr.getElement(this.options.bar);
    // # beyond limit to make the overload %
    this.options.limit = this.options.limit * 1.0;
    this.overload = this.options.overload / 100.0 * this.options.limit;
  },
  
  /**
    Start animating.
    @returns {ta.widgets.ProgressBar} this
  */
  start: function() {
    this.ctnr.show();
    if (!this.width) {
      this.bar.setStyle('width', 'auto');
      this.width = this.bar.getSize().size.x;
      this.bar.setStyle('width', 0);
    }
    this.current = 0;
    this.max = this.overload; // % limit
    this.timer = this.tick.periodical(this.options.delay, this);
    return this;
  },
  
  /**
    Stop animating.
    @returns {ta.widgets.ProgressBar} this
  */
  stop: function() {
    $clear(this.timer);
    this.ctnr.hide();
    return this;
  },

  /**
    Update the progress limit to the current # of results.
    @param {integer} count current # complete
    @returns {ta.widgets.ProgressBar} this
  */
  update: function(count) {
    this.max = Math.min(this.options.limit, count + this.overload);
    return this;
  },
  
  /**
    Animation step.
    @private
  */
  tick: function() {
    // recalculate progress
    var d = (this.max - this.current) * this.options.distance;
    this.current += (d / this.options.speed) * this.options.delay;
    var p = this.current / this.options.limit;
    // update display
    this.text.setContent(Math.round(p * 100));
    this.bar.setStyle('width', Math.round(this.width * p));
    return this;
  }
});
ta.widgets.ProgressBar.implement(new Events, new Options);/**
 * @class
 * Support functions used on HACSearch servlet.
 */
ta.servlet.HACSearch = {
  /**
   * MorphableMap#onMorph event handler.
   * @see ta.maps.MorphableMap#event:onMorph
   * @param {integer} idx Morph index
   * @param {ta.maps.MorphableMap} map MorphableMap instance
   */
  mapMorphed: function(idx, map) {
    var div = $(ta.retrieve('maps.container'));
    if (idx == 0) { // thumbnail
      if (!map.thumbnailClickHandler) map.thumbnailClickHandler = map.morph.bind(map, 1);
      div.onclick = map.thumbnailClickHandler;
      ta.servlet.HACSearch.hideMapSponsor();
      // save map state until next update
      ta.store('maps.returnTo', {
        center: map.mapCenter(),
        zoom: map.getZoom()
      });
      $('RESULT_COUNT').setStyle('display', 'block');
      // reset map to default
      $('RESET_MAP').setStyle('display', 'none');
      map._reset();
      // make sure to hide the zoom error
      $('MPZM_ERR').hide();
      ta.store('maps.moved', false);

      //new Ajax('/ActionRecord?action=' + ta.servlet.HACSearch.getLoggingName() + 'close').request();
    }
    else if (idx == 1) { // large map
      if (!ta.has('maps.suppressHACActionRecord')) {
        ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'open');
      }
      ta.util.pending.lock('maps.nearbyStarted', function() { // only do this once
        new Ajax(getHACFormURL(), {data: getHACFormData(false).include({nearbyHac:true})}).request();
      });
      $('RESULT_COUNT').setStyle('display', 'none');
      ta.servlet.HACSearch.showMapSponsor();
      div.onclick = null;
      if (ta.has('maps.returnTo')) {
        ta.store('maps.moved', true);
        var data = ta.remove('maps.returnTo');
        map._move(data.center.lat(), data.center.lng(), data.zoom);
        $('RESET_MAP').setStyle('display', 'block');
      }

      var hideNav = $$('#LEFTNAV .toggle');
      if (hideNav && hideNav[0]) {
        hideNav[0].addClass('off');
      }
    }
  },

  hideMapSponsor: function() {
    var sponsor = $('MAP_SPONSOR');
    if (sponsor) {
      var sponsorcbx = sponsor.getElement('input[type=checkbox]');
      if (sponsorcbx && sponsorcbx.checked) sponsorcbx.click();
      sponsor.hide();
    }
  },

  showMapSponsor: function() {
    var sponsor = $('MAP_SPONSOR');
    if (sponsor) sponsor.show();
  },

  showMoreMapSponsor: function() {
      var sponsorList = $('SPONSOR_LIST');
      if(sponsorList) {
          new Ajax("/ActionRecord?action=sponsor_see_more").request()
          sponsorList.getElements('.js_sponsor_see_more').each(function(row) {
              row.removeClass('hide');
          });
          sponsorList.getElements('.js_sponsor_see_less').each(function(row) {
              row.addClass('hide');
          });
      }
  },

  showLessMapSponsor: function() {
      var sponsorList = $('SPONSOR_LIST');
      if(sponsorList) {
          sponsorList.getElements('.js_sponsor_see_more').each(function(row) {
              row.addClass('hide');
          });
          sponsorList.getElements('.js_sponsor_see_less').each(function(row) {
              row.removeClass('hide');
          });
      }
  },
  
  getLoggingName: function() {
    var sLoggingName = ta.retrieve('maps.overrideLoggingName');
    if (sLoggingName)
    {
      return sLoggingName;
    }
    return 'HACMap_';
  },
  
  /**
   * Event handler to morph the map thumbnail to the large map. Only called once, is replaced in
   * mapMorphed handler.
   * @param {Event} evnt The Event
   * @param {Element} elmt The Element
   */
  morphBig: function(evnt, elmt) {
    if (evnt) evnt.stop();
    var map = ta.retrieve('maps.map');
    if (map) map.morph(1);
  },
  
  /**
   * Map#onMove event handler.
   * @see ta.maps.Map#event:onMove
   * @param {boolean} zoomChanged true if move was a zoom change
   * @param {integer} zoom Current zoom level
   */
  mapMoved: function(zoomChanged, zoom) {
    var minZoom = ta.retrieve('maps.map').options.minZoom;
    if (zoom < minZoom) return; // zoomed out too far
    ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'move');
    ta.store('filter.map', true);
    $('RESET_MAP').setStyle('display', 'block');
    $('RESET_MAP').setStyle('border-left', '1px solid #656565');
    ta.util.pending.lock('maps.firstMove', function() { // first time map is moved
      // open nearby cities
      var nearby = $$('#HOTEL_FILTERS fieldset.nearbyCities');
      if (nearby) nearby.show();
    });
    ta.servlet.HACSearch.adjustTopValueState(); // panning map selects new hotels so causes top value to disappear
    ta.servlet.HACSearch.filtersChanged();
    ta.servlet.HACSearch.showNearbyCities();
  },

  showNearbyCities: function() {
    var sidebar = $('SIDEBAR');
    if (sidebar) {
      var nearbyCities = sidebar.getElement('#nearbyCities');
      if (nearbyCities) {
        if (nearbyCities.hasClass('hidden')) {
          nearbyCities.removeClass('hidden');
          ta.maps.Sidebar.openNearbyCities(null, nearbyCities.getElement('#toggle_nearby_cities'));
        }
      }
    }
  },
  
  /**
   * Map#onReset event handler.
   * @see ta.maps.Map#event:onReset
   */
  mapReset: function() {
    $('RESET_MAP').setStyle('display', 'none');

    // reset nearby cities filters
    var citiesContainer = ta.retrieve('nearbycities.container');
    $$(citiesContainer + ' fieldset.nearbyCities input[type=checkbox]').each(function(cb) {
      if (cb.checked) {
        ta.servlet.HACSearch.setCheckSetChecked(cb, false);
        checked = true;
      }
    });
    
    var unear = $('unear');
    if (unear) unear.value = "";
    
    ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'reset');

    ta.servlet.HACSearch.filtersChanged();
  },
  
  /**
   * Map#onZoom event handler.
   * @see ta.maps.Map#event:onZoom
   * @param {integer} was Previous zoom level
   * @param {integer} now Current zoom level
   */
  mapZoomed: function(was, now) {
    var minZoom = ta.retrieve('maps.map').options.minZoom;
    if (now < minZoom) { // too far out
      var box = $('MPZM_ERR');
      if (!box.hasClass('rdy')) $(document.body).adopt(box.addClass('rdy'));
      box.setStyles({left:-9999, top:-9999}).show();
      var sOuter = $(ta.retrieve('maps.container')).getCoordinates();
      var sInner = box.getCoordinates();
      box.setStyles({
        left: sOuter.left + (sOuter.width - sInner.width) / 2,
        top:  sOuter.top + (sOuter.height - sInner.height) / 2
      });
    }
    else {
      $('MPZM_ERR').hide();
    }
  },
  
  /**
   * Pass-thru function to the old code until it can be ported over.
   * @deprecated
   */
  filtersChanged: function() {
    filtersChanged();
  },

  /**
   * Called when user clicks the search button next to name contains field
   */
  nameFilterChanged: function(event) {
    event.preventDefault();
    filtersChanged();
  },

  /**
   * Called when user clicks the reset link under name contains field
   */
  nameFilterReset: function(event) {
      event.preventDefault();
      var field = $('nameContains');
      if(field && field.value && field.value.length > 0)
      {
          field.value = '';
          filtersChanged();
      }
  },
  
  /**
   * Called when a user clicks on a filter checkbox in the left nav.
   * @param {Event} evnt The event
   * @param {Element} elmt The checkbox element
   */
  toggleFilter: function(evnt, elmt) {
    var wait = true;
    if (elmt.getParent('fieldset.nearbyCities')) { // nearby city checkbox
      var unear = $('unear');
      var snear = $('snear');
      var ulist = unear.value.length > 0 ? unear.value.split(',') : [];
      var slist = snear.value.length > 0 ? snear.value.split(',') : [];
      if (elmt.checked) {
        ulist.remove(elmt.id);
        slist.include(elmt.id);
      }
      else {
        ulist.include(elmt.id);
        slist.remove(elmt.id);
      }
      unear.value = ulist.join(',');
      snear.value = slist.join(',');
      ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'nearby');
      if (elmt.hasClass('default')) {
        ta.remove('sel.nearby');
      }
      else {
        var selNearby = ta.retrieve('sel.nearby') || [];
        if (elmt.checked) selNearby.push(elmt.id);
        else selNearby.remove(elmt.id);
        ta.store('sel.nearby', selNearby);
      }
    }
    else {
      var parent = elmt.getParent('fieldset');
      if (elmt.hasClass('default')) { // clicked 'All', uncheck others
        parent.getElements('input[type=checkbox]').each(function(cb) {
          if (!cb.hasClass('default')) ta.servlet.HACSearch.setCheckSetChecked(cb, false);
        });
      }
      else {
        var dflts = parent.getElements('input.default');
        if (dflts) {
          if (elmt.checked) { // checked a specific one, make sure default is unchecked
            dflts.each(function(dflt){ ta.servlet.HACSearch.setCheckSetChecked(dflt, false);});
          }
          else { // unchecked a specific one, check default if none are checked
            if (!parent.getElements('input[type=checkbox]').some(function(cb) {
                return cb.checked;
              })) {
              dflts.each(function(dflt){ ta.servlet.HACSearch.setCheckSetChecked(dflt, true);});
            }
          }
        }
      }
      
      if (parent.hasClass('neibrhd')) { // neighborhood
        if (elmt.hasClass('default')) {
          ta.store('sel.neighborhood', [elmt.id]);
        }
        else {
          var selNeighborhood = ta.retrieve('sel.neighborhood') || [];
          if (elmt.checked) selNeighborhood.push(elmt.id);
          else selNeighborhood.remove(elmt.id);
          ta.store('sel.neighborhood', selNeighborhood);
        }
      }
      
      // filter update lockout
      if (parent.hasClass('lockout')){
        wait = false;
        ta.store('filter.lockout', true);
      }
    }

    if(elmt.getParent('fieldset.hotelBrand')) {
        var dupElmt = brandDup(elmt);
        if(dupElmt)
        {
            dupElmt.checked = elmt.checked;
        }
    }
    ta.servlet.HACSearch.adjustTopValueState(); // any filter change causes top value to disappear
    
    if (wait) ta.util.pending.waitForMore('filters', ta.servlet.HACSearch.filtersChanged, 1000);
    else ta.servlet.HACSearch.filtersChanged();
  },

  toggleAllAvailability: function(evnt, elmt) {
    $('HOTEL_FILTERS').availability.value = elmt.value;
    ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'avail');
    ta.servlet.HACSearch.filtersChanged();

    // need to keep all availablity radio buttons in sync 
    //   - they all have a class of avail_<their value>

    // first get all with same class and set those
    $$('input.avail_' + elmt.value).each(function (el) {
          el.checked = true;
        });
    // now find all with other class and set them off.
    var offValue = elmt.value == "1" ? "0" : "1";
    $$('input.avail_' + offValue).each(function (el) {
          el.checked = false;
        });        
  },
  
  toggleAvailability: function(evnt, elmt) {
    $('HOTEL_FILTERS').availability.value = elmt.value;
    ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'avail');
    ta.servlet.HACSearch.filtersChanged();
    if (/.*_(\d)$/.test(elmt.id)) {
      var other = $('map_avail_'+RegExp.$1);
      if (other) other.checked = elmt.checked;
    }
  },
  
  toggleAvailabilityAlt: function(evnt, elmt) {
    if (/.*_(\d)$/.test(elmt.id)) {
      $('availability_'+RegExp.$1).click();
    }
  },
  
  /**
   * Updates various portions of the page. Called after the result list is updated.
   */
  updateData: function() {
    // (un)check nearby when they come into/out of view
    if (ta.has('maps.nearby')) {
      var near = ta.remove('maps.nearby');
    var citiesContainer = ta.retrieve('nearbycities.container');
      $$(citiesContainer + ' fieldset.nearbyCities input[type=checkbox]').each(function(cb) {
        ta.servlet.HACSearch.setCheckSetChecked(cb, near.contains(cb.id));
      });
    }
    
    // pager links above map
    var map_pager = $('map_pager');
    var top_pager = $('pager_top2');
    if (map_pager && top_pager) {
      map_pager = map_pager.getElement('div.pgLinks');
      map_pager.innerHTML = top_pager.innerHTML;
      behavior.apply(map_pager);
    }
    
    // keep Top Values check box on map in sync with one in list
    var mapTV = $('mapSG');
    var bvf = $('BEST_VALUE_FORM');
    if (mapTV && bvf) {
      mapTV.checked = bvf.sortGroup.checked;
      mapTV.disabled = bvf.sortGroup.disabled;
      mapTV.getParent().getElement('span').innerHTML = bvf.getElement('label.bv span').innerHTML;
      if(mapTV.disabled) {
        mapTV.getParent().addClass('disabled');
      } else {
        mapTV.getParent().removeClass('disabled');
      }
    }
    
    // showing X-Y of Z
    var lgMap = $('LARGE_MAP');
    if (lgMap) {
      var showing = lgMap.getElement('.showing');
      if (showing) {
        var count = $('ACCOM_OVERVIEW');
        if (count) {
          var span = showing.getElement('span');
          count = count.getElement('.pagination .pgCount');
          if (count) {
            span.innerHTML = count.innerHTML;
          }
          else {
            span.innerHTML = "0";
          }
        }
      }
    }
  },
  
  /**
   * Toggles sponsor pins on the map the requests a data update.
   * @param {Event} event The Event
   * @param {Element} elmt Checkbox or Radio button
   */
  toggleSponsor: function(evnt, elmt) {
    ta.maps.Factory.toggleTypeByValue(evnt, elmt);
    var addSponsorship = $('addSponsorship');
    var addSponsorshipToggle = $('addSponsorshipToggle');
    if (addSponsorship && addSponsorshipToggle) {
      if (addSponsorship.checked) {
        addSponsorshipToggle.value = "turnOn " + addSponsorship.value;
      } else {
        addSponsorshipToggle.value = "turnOff " + addSponsorship.value;
      }
    }
    ta.servlet.HACSearch.filtersChanged();
    if (addSponsorship && addSponsorshipToggle) {
      addSponsorshipToggle.value = "";
    }
  },
  
  toggleTopValue: function(evnt, elmt) {
    $('BEST_VALUE_FORM').sortGroup.click();
  },
  
  /**
   * Hande an onclick event from the 'includeNearby' checkbox before update
   * @param {Event} event The Event
   * @param {Element} elmt the 'includeNearby' Checkbox
   */
  handleIncludeNearbyOnClick:function(event, includeNearby)
  {
    var fieldset = includeNearby.getParent('fieldset');
    var distance = fieldset.getElement('select');
    
    //  enable/disable the select and geo checkboxes to if the includeNearby box
    //  is checked/unchecked
    fieldset.getElements('input[type=checkbox]').extend(fieldset.getElements('select')).each(function(input)
    {
        if (input != includeNearby)
        {
            input.disabled = !includeNearby.checked;
        }
    });
    
    //  mark that the user modified the include nearby checkbox 
    $('includeNearbyModified').value = true;
    
    //  update the results
    ta.servlet.HACSearch.toggleFilter(event, includeNearby);
  },
  
  /**
   * Hande an onchange event from the 'distance' select before update
   * @param {Event} event The Event
   * @param {Element} distanceSelect the 'distance' select
   */
  handleDistanceOnChange:function(event, distanceSelect)
  {
    //  grab the corresponding hidden input and set its new value
    var distance = $('distance');
    if (distance)
    {
        distance.value = distanceSelect.options[distanceSelect.selectedIndex].value;
    }
      
    //  update the results
    ta.servlet.HACSearch.toggleFilter(event, distanceSelect);
  },
  
  /**
   * Update the hidden checked/unchecked indices lists for a check set
   * @param {Element} checkbox the checkbox
   */
  updateCheckedIndices:function(checkbox)
  {
      //  if the value is not an index then just return
      if (isNaN(checkbox.value)) return;
      
      //  update the checked/unchecked indices lists
      var checkedIndices = checkbox.getParent('fieldset').getElement('input.checkedIndices');
      var uncheckedIndices = checkbox.getParent('fieldset').getElement('input.uncheckedIndices');
      
      //  remove from one list
      var removeFrom = checkbox.checked ? uncheckedIndices : checkedIndices;
      if (removeFrom) removeFrom.value = removeFrom.value.split(',').remove(checkbox.value).remove('').join(',');

      //  add to another if not already there
      var addTo = checkbox.checked ? checkedIndices : uncheckedIndices;
      if (addTo) addTo.value = addTo.value.split(',').include(checkbox.value).remove('').join(',');
  },
  
  /**
   * Set a checkbox in a checkset as checked/unchecked
   * @param {Element} checkbox the checkbox
   * @param {Boolean} checked if the checkbox should be checked
   */
  setCheckSetChecked:function(checkbox, checked)
  {
    if (checkbox)
    {
      checkbox.checked = checked;
      ta.servlet.HACSearch.updateCheckedIndices(checkbox);
    }
  },
  
  /**
   * Hande an onclick event from a check set checkbox before update
   * @param {Event} event The Event
   * @param {Element} elmt the check set Checkbox
   */
  handleCheckSetOnClick:function(event, checkbox)
  {
      //  update the checked/unchecked indices
      ta.servlet.HACSearch.updateCheckedIndices(checkbox);
     
      //  update the results
      ta.servlet.HACSearch.toggleFilter(event, checkbox);
  },

  /**
   * Callback to trigger a full update using date fields in hac form.
   */
  doDateSearch:function(event, elmt) {
    if (ta.servlet.HACSearch.areDateFieldsSet()) {
      $('searchAll').value = 'false';
      ta.servlet.HACSearch.filter.update();
    }
    ta.servlet.HACSearch.adjustTopValueState();
    updateResults(true);
  },

  /**
   * Return whether the visible date fields are in 'empty' state, which means
   * they contain the date template string (ie. mm/dd/yyyy)
   */
  areDateFieldsSet:function() {
    var hacForm = $('HAC_FORM');
    var isEmpty = false;
    if (hacForm) {
      hacForm.getElements('.cal input[type=text]').each(function(e){
        if (e.value == JS_DateFormat) {
          isEmpty |= true;
        }
      });
    }
    return !isEmpty;
  },

  /**
   * fire off one of the recent search links - by updating the form
   */
  doRecentHacSearch: function(event, elmt) {
    var recentHacSearches = ta.retrieve('recentHacSearches');
    if(recentHacSearches) {
        var hacForm = $('HAC_FORM');
        if(hacForm) {
            if(classMatch = elmt.className.match(/js_rhs(\d+)/)) {
                ta.util.cookie.setPIDCookie(2184);
                var index = classMatch[1];
                var searchObj = recentHacSearches[index - 1];
                hacForm.geo.value = searchObj.geo;
                hacForm.q.value = searchObj.geoName;
                var checkinDate = searchObj.checkin;
                var checkoutDate = searchObj.checkout;
                hacForm.checkIn.value = formatDate(checkinDate.getDate(), checkinDate.getMonth(), checkinDate.getFullYear());
                hacForm.checkOut.value = formatDate(checkoutDate.getDate(), checkoutDate.getMonth(), checkoutDate.getFullYear());
                hacForm.inDay.value = checkinDate.getDate();
                hacForm.inMonth.value = (checkinDate.getMonth() + 1) + '/' + checkinDate.getFullYear();
                hacForm.outDay.value = checkoutDate.getDate();
                hacForm.outMonth.value = (checkoutDate.getMonth() + 1) + '/' + checkoutDate.getFullYear();
                ta.servlet.HACSearch.doDateSearch(event, elmt);
            }
        }
    }
  },

  /**
   * Callback for triggering display of large map.  The map container
   * will be shown immediately.  The map Javascript will be loaded first
   * if it is not already present.
   */
  showLargeMap:function(event, elmt) {
    if (event) event.preventDefault();
    ta.servlet.HACSearch.loadOrShowLargeMap(true);
  },
  
  _isMapLoaded:function() {
    return ta.has('maps.map') || ta.has('maps.create_called');
  },

  /**
   * display the large map, triggering an asynchronous load of map if
   * it has not already been loaded.
   * @param updateFilter whether the location hash should be updated.  This
   * may be false because this method can be called form the location hash
   * deserialization code.
   */
  loadOrShowLargeMap:function(updateFilter) {
    ta.store('maps.is_open', true);
    if (updateFilter) {
      ta.servlet.HACSearch.filter.update();
    }
    $('SMALL_MAP').setStyle('display', 'none');
    var largeMap = $('LARGE_MAP');
    
    // show numbered pins
    if (ta.retrieve('maps.is_open')) {
      showTitlePins();
    }

    if (!ta.servlet.HACSearch._isMapLoaded()) {      
      // we only want this to happen once but maps.map will not be created until load finishes, hence create_called flag
      ta.store('maps.create_called', true); 
      ta.store('maps.landmarks', []);

      // old tracking variable
      if (!ta.has('maps.suppressHACActionRecord')) {
        ta.store('lma', ta.servlet.HACSearch.getLoggingName() + 'open');
      }
      ta.util.load.LocalSearch();
      ta.util.pending.waitForFile('createmap', 'ta-maps.js', function() {
        ta.store('maps.callback', 'ta.servlet.HACSearch.createMapCaller');
        ta.util.load.GMaps();      
        largeMap.setStyle('display', 'block');
        ta.servlet.HACSearch.showMapSponsor();
      });
    } else {
      largeMap.setStyle('display', 'block');
      ta.servlet.HACSearch.showMapSponsor();
    }
  },

  createMapCaller: function() {
    ta.store('maps.postcreate', function(map) {
        var options = ta._locationHash;
        if (options.hasKey('mc') && options.hasKey('mz')) {
          var mc = options.get('mc').split(',');
          map._move(parseFloat(mc[0]), parseFloat(mc[1]), parseInt(options.get('mz')));
          ta.store('maps.moved', true);
        }
        var queuedFunctions = ta.retrieve('maps.queuedSidebar');
        if(queuedFunctions) queuedFunctions.each(function(fn) { fn(); });
        var addressSearch = ta.remove('maps.address_search_deferred');
        if (addressSearch) {
          addressSearch();
        }
      });
    ta.util.pending.waitForFn("mapfactory", "ta.maps.Factory.createMap");

    return;
  },

  /**
   * Callback to hide the large map, and make the small static map visible.
   */
  hideLargeMap:function(event, elmt) {
    $('LARGE_MAP').setStyle('display', 'none');
    $('SMALL_MAP').setStyle('display', 'block');  
    ta.servlet.HACSearch.hideMapSponsor();
    ta.remove('maps.is_open');
    ta.servlet.HACSearch.filter.update();
    
    // hide numbered pins
    hideTitlePins();
  },

  /**
   * Callback for clearing date range on results.  This will trigger a page update.
   */
  clearDates:function(event, elmt) {
    var oldValue = $('searchAll').value;
    $('searchAll').value = true;
    if (oldValue == 'trueButShow') {
      // trueButShow means we are already ignoring dates, but now we want to actually
      // clear them from the text box.  We don't need to update in this case since
      // we haven't been using them.
      ta.servlet.HACSearch.clearDateFields();
    } else {
      // we are going from 'false' to 'true', so we need to update data.
      showUpdatingMessage();
      updateResults(true);
    }
  },

  /**
   * Cause the calendar date fields to be cleared out, replacing dates with 'mm/dd/yyyy' text.
   */
  clearDateFields:function() {
    // trigger calendar date clear - pass any field as it will look up form from the field
    var form = $('checkIn').form;
    if (form.calendar) form.calendar.clearFields();
    ta.servlet.HACSearch.hideClearDates();
  },

  /**
   * Write the stored dates back into the visible text date fields in the hac search bar.
   */
  restoreDateFields:function() {
    var form = $('checkIn').form;
    if (!form.calendar) {
      new ta.overlays.PairedCalendar(form);
    }
    form.calendar.updateFields();
    ta.servlet.HACSearch.showClearDates();
  },

  hideClearDates:function() {
    $$('#HAC_SMRY .smry .hvrIE6').each(function(el) {
        el.setStyle('display', 'none');
      });
  },

  showClearDates:function() {
    $$('#HAC_SMRY .smry .hvrIE6').each(function(el) {
        el.setStyle('display', 'inline');
      });
  },

  /**
   * Callback for show all top value link.  Triggers top value sort.
   */
  showAllTopValue:function(event, elmt) {
    event.preventDefault();
    ta.servlet.HACSearch.adjustTopValueState();
    ta.servlet.HACSearch.filtersChanged();
  },

/*
 * topvalue state responds to filters getting set or map being panned by switching to 'hidden' 
 * and setting sort by best value checkbox
 */
  adjustTopValueState:function() {
    var tvState = ta.remove('topvalue.state'); // any filter change causes top value to disappear
    if ($defined(tvState)) {
     // check the best value box
     $('BEST_VALUE_FORM').sortGroup.checked = true; 
     // push change to sort form
     bestValueChanged(); 
     // pull sort form back into filters form
     $('HOTEL_FILTERS').sortOrder.value = $('SORT_FORM').sortOrder.value; 
   }
  },

  /**
   * Callback for when a category tab is clicked.  We set the category criteria and do submit.
   */
  tabClicked:function(event, elmt) {
    if (elmt.tagName != 'H2') {
      elmt = elmt.getParent('H2');
    }
    var match = elmt.className.match(/cat_(\d+)/);
    var disabled = elmt.hasClass('disabled');
    if (match) {
      event.preventDefault();
      if (!disabled) {
        ta.store('sel.category', match[0]);
        filtersChanged();
        // unselect old by removing 'current', then select new one
        $(elmt.getParent()).getElements('.tab').each(function(el) {
            el.removeClass('current');
          });
        elmt.addClass('current');
      }
    }
  },

  /**
   * Returns the CenteredOverlay for the filter wait dialog, creating it if necessary.
   * @returns {CenteredOverlay} the wait dialog
   */
  getFilterWaitOverlay: function(){
    var dialog = ta.retrieve('filters.waitDialog');
    if (!dialog) {
      dialog = new ta.overlays.CenteredOverlay({
        style:'mg s1 fatNotice',
        showCloseButton: false,
        autoShow: false
      });
      dialog.inner.setHTML('<b>'+JS_UpdatingYourResults+'</b>');
      ta.store('filters.waitDialog', dialog);
    }
    return dialog;
  },

  _getMiniMapAddress: function() {
    return $('SMALL_MAP_ADDRESS').getFirst().address.value;
  },
  
  _setMiniMapAddress: function(text) {
    $('SMALL_MAP_ADDRESS').getFirst().address.value = text;
  },
  
  onMiniMapAddressSubmit: function(event, elmt) {
    var form = $('SMALL_MAP_ADDRESS').getFirst();
    document.location.href = form.action + ",bc_address:S" + ta.servlet.HACSearch._getMiniMapAddress();
    return false;
  },
  
  _doAddressSearch: function() {
    var address = ta.servlet.HACSearch._getMiniMapAddress();
    $("add_location_input").value = address;
    ta.maps.Sidebar.addLocation();
    ta.servlet.HACSearch._setMiniMapAddress(map_findhotelnear);
  },

  onMiniMapAddressSearch: function(event, elmt) {
    // map may not be loaded - if not, we need to defer the search until after it is
    if (!ta.servlet.HACSearch._isMapLoaded()) {
      ta.store("maps.address_search_deferred", ta.servlet.HACSearch._doAddressSearch);
    } else {      
      ta.servlet.HACSearch._doAddressSearch();
    }
    ta.servlet.HACSearch.showLargeMap(event, elmt);
  },

  onLargeMapAddressFocus: function(event, elmt) {
    var field = $('add_location_input');
    field.value = "";
    field.removeClass("unfocused");
  },
  
  onLargeMapAddressBlur: function(event, elmt) {
    var field = $('add_location_input');
    if (field.value.length == 0) {
      field.value = map_enteraddress;
      field.addClass("unfocused");
    }
  }

};
/**
 * @class
 * Support functions used on VRACSearch servlet as well as the VRAC form (typeahead, etc.).
 */
ta.servlet.VRACSearch = {

    /**
     * @param {HTMLElement} elmt the typeahead elemnt
     * @param {Object} response the typeahead response 
     */
    homeVRGeoChanged:function(elmt, response)
    {
      $('VRAC_FORM').geo.value = response.value;
      var vrAlternatives = $('vrAlternatives');
      if (!response.vrpresent)
      {
        var buffer = [];
        buffer.push('<div class="sorry">');
        buffer.push(msg_no_vrs.replace('{0}', response.name));
        buffer.push('</div>');
    
        if (response.hasHotels)
        {
            var href = response.hotelUrl;
            if (!href)
            {
                href = '/Hotels-g' + response.value;
            }
    
            buffer.push('<div class="searchHotels">');
            buffer.push('<a href="' + href + '" rel="nofollow">');
            buffer.push(msg_search_hotels.replace('{0}', response.name));
            buffer.push('</a>');
            if (response.vralternatives.length == 0)
            {
                buffer.push('&nbsp;');
                buffer.push(msg_try_nearby);
            }
            buffer.push('</div>');
        }
        if (response.vralternatives.length > 0)
        {
            buffer.push('<div class="check">');
            buffer.push(msg_check_nearby);
            buffer.push('</div>');
            buffer.push('<ul class="locations">');
            var length = response.vralternatives.length;
            for (var i = 0; i < length; i++)
            {
                var vrAlt = response.vralternatives[i];
                buffer.push('<li><span class="fkLnk hvrIE6" onclick="ta.servlet.VRACSearch.chooseVracAlternative(\'');
                buffer.push(vrAlt.name);
                buffer.push('\',\'');
                buffer.push(vrAlt.value);
                buffer.push('\');">');
                buffer.push(vrAlt.name);
                buffer.push('</span></li>');
            }
            buffer.push('</ul><ul class="distance">');
            for (var i = 0; i < length; i++)
            {
                var vrAlt = response.vralternatives[i];
                buffer.push('<li>');
                buffer.push((vrAlt.unit == 'm' ? msg_miles_away : msg_km_away).replace('{0}', vrAlt.dist));
                buffer.push('</li>')
            }
            buffer.push('</ul>')
        }
    
        //  set the content
        var content = vrAlternatives.getElement('.content');
        content.innerHTML = buffer.join('');
        
        //  now that the new elements are part of the DOM add the 'hvrIE6' behavior
        if (window.ie6)
        {
            content.getElements('.hvrIE6').each(rules['span.hvrIE6']);
        }
        
        //  show the alternatives
        ta.servlet.VRACSearch.showVracAlternatives();
      }
      else
      {
          ta.servlet.VRACSearch.hideVracAlternatives();
      }
    },
    
    chooseVracAlternative:function(name, value)
    {
        $('vracGeo').value = name;
        $('VRAC_FORM').geo.value = value;
        ta.servlet.VRACSearch.hideVracAlternatives();
    },
    
    showVracAlternatives:function(event, element)
    {
        //  'vrMidForm' is present on the home page and lander typeaheads but not the /VRACSearch typeahead
        var vrMidForm = $('vrMidForm');
        if (vrMidForm)
        {
            vrMidForm.style.display = 'none';
        }

        $('vrAlternatives').style.display = 'block';
    },
    
    hideVracAlternatives:function(event, element)
    {
        $('vrAlternatives').style.display = 'none';

        //  'vrMidForm' is present on the home page and lander typeaheads but not the /VRACSearch typeahead
        var vrMidForm = $('vrMidForm');
        if (vrMidForm)
        {
            vrMidForm.style.display = 'block';
        }
    },
    
    hideVracAlternativesAndClearBox:function(event, element)
    {
        ta.servlet.VRACSearch.hideVracAlternatives();
        $('vracGeo').value = '';
    }
};/**
 * @class
 *
 * @extends ta.util.Saveable
 *
 * @author wasche
 * @since  2009.02.17
 */
ta.servlet.HotelFilter = new Class({
  initialize: function() {
    this.registerForLocationHash();
  },

  /**
   * Function to call after the location hash is parsed.
   * @param {Hash} options The options
   */
  restoreOptions: function(options) {
    var form = $('HOTEL_FILTERS');
    if (!form) return; // form is required in order to restore it

    //  child geos defaults to being checked so we need to uncheck them all
    //  before applying the checkbox state from the hash
    var fieldset = $$('fieldset.childGeos')[0];
    if (fieldset)
    {
      fieldset.getElements('input[type=checkbox]').each(function(checkbox)
      {
        ta.servlet.HACSearch.setCheckSetChecked(checkbox, false);
      });
    }

    //  the nearby geos master checkbox defaults to being checked so uncheck it
    //  so we can apply the state from the hash
    var includeNearby = $('includeNearby');
    if (includeNearby)
    {
        includeNearby.checked = false;
    }

    if (options.hasKey('cb')) {
      //  apply the checkbox state from the hash
      options.get('cb').each(function(id){
        cb = $(id);
        if (!cb || id == 'sortGroup') return; // sortGroup (top value sort checkbox) is not a regular criteria filter
        // make sure it is enabled...
        if (cb.disabled) {
          cb.disabled = false;
          document.getElementById(id + "_count").style.display = 'inline';
          $(id + '_lbl').removeClass('disabled');
        }
        var type = cb.id.replace(/_.*/, '');
        // if not a default, make sure panel is open
        if (!cb.hasClass('default')) {
          var elmt = $(type + '_toggle');
          if (elmt && elmt.hasClass('closed')) {
            elmt.toggleClass('closed');
      	    elmt.getParent().getChildren().each(function(n) {
    	      if (n != elmt) n.setStyle('display', 'block');
    	    });
          }
        }
        if (cb.checked) return;
        ta.servlet.HACSearch.setCheckSetChecked(cb, true);
        // if not a default, make sure default is unchecked
        if (!cb.hasClass('default')) {
          var filterDefault = $(type + '_default');
          if (filterDefault) ta.servlet.HACSearch.setCheckSetChecked(filterDefault.getElement('input'), false);
          if(type == 'zfb') { //brand has extra default
            var filterDefaultI = $('zfb_i_default');
            if (filterDefaultI) filterDefaultI.getElement('input').checked = false;
            var filterDefaultA = $('zfb_a_default');
            if (filterDefaultA) filterDefaultA.getElement('input').checked = false;
          }
        }
      });
    }

    //  now make sure the state of the distance select matches the include nearby checkbox
    var distanceSelect = $('distanceSelect');
    if (includeNearby && distanceSelect)
    {
        distanceSelect.disabled = !includeNearby.checked;
    }

    //  if we have a list of checked/unchecked nearby geos then apply the states.
    //  note that this is to indicate checked boxes and not necessarily
    //  enabled ones
    if (options.hasKey('nearbyGeosChecked'))
    {
        options.get('nearbyGeosChecked').split(',').each(function(index)
        {
            if (!isNaN(index)) ta.servlet.HACSearch.setCheckSetChecked($('nearbyGeos_' + index), true);
        });
        form.nearbyGeosChecked.value = options.get('nearbyGeosChecked');
    }
    if (options.hasKey('nearbyGeosUnchecked'))
    {
        options.get('nearbyGeosUnchecked').split(',').each(function(index)
        {
            if (!isNaN(index)) ta.servlet.HACSearch.setCheckSetChecked($('nearbyGeos_' + index), false);
        });
        form.nearbyGeosUnchecked.value = options.get('nearbyGeosUnchecked');
    }
    sliderMap = {
      'l1price':  'priceSelect',
      'l1rating': 'ratingSelect',
      'sleeps':   'sleepsSelect',
      'bedrooms': 'bedroomsSelect'
    }
    for (op in sliderMap) {
      if (options.hasKey(op) && options.get(op) != $(op).value) {
        var slider = $(sliderMap[op]);
        if (slider.slider) slider.slider.setKnobs(options.get(op));
        // for price we need to stash values so when slider range is set,
        // selected values are not lost - bug 37881
        if (op == 'l1price') {
          var prices = options.get(op).split(',');
          if (prices.length == 2) {
            ta.store('hacform.slider.price.min', prices[0]);
            ta.store('hacform.slider.price.max', prices[1]);
          }
        }
      }
    }

    if (options.hasKey('pricePeriod')) $('pricePeriod_'+options.get('pricePeriod')).checked = true;

    /*if (options.hasKey('rpp')) {
      rpp = $('rpp');
      v = options.get('rpp');
      for (var op = 0; op < rpp.options; op++) {
        if (rpp.options[op].value == v) rpp.selectedIndex = opp;
      }
    }*/

    if (options.hasKey('availability')) {
      $('availability_'+options.get('availability')).checked = true;
    }

    if (options.hasKey('o')) {
      ta.store('hac.filterOffset', parseInt(options.get('o')));
    }

    if (options.hasKey('nameContains')) {
        $('nameContains').value = options.get('nameContains');
    }

    if (options.hasKey('bathrooms'))
    {
        $('bathrooms').selectedIndex = options.get('bathrooms');
    }

    if (options.hasKey('distance'))
    {
        $('distance').value = options.get('distance');
    }

    if (options.hasKey('includeNearbyModified'))
    {
        $('includeNearbyModified').value = options.get('includeNearbyModified');
    }

    //  update select elements
    ['bathrooms', 'distanceSelect'].each(function(criteria)
    {
      if (options.hasKey(criteria))
      {
        var optionValue = options.get(criteria);
        var distanceSelect = $(criteria);
        var selectedOption = distanceSelect.getElement('option[value=' + optionValue + ']');
        $(criteria).selectedIndex = selectedOption.index;
      }
    });

    //brand dupe check
    if(subBrandSelected())
    {
        brandsFull();
    }

    if (ta.retrieve('redesignEnabled') && options.hasKey('map') && options.get('map') == 1) {
      ta.servlet.HACSearch.loadOrShowLargeMap(false);
    }

    // top value box state
    if (options.hasKey('tv')) {
      ta.store('topvalue.state', options.get('tv'));
    }

    // ignore dates flag
    if (options.hasKey('sa')) {
      var searchAll = $('searchAll');
      if (searchAll && searchAll.type == 'hidden') {
        if (options.get('sa') == 1) {
          searchAll.value = true;
          ta.servlet.HACSearch.clearDateFields();
        } else if (options.get('sa') == 2) {
          searchAll.value = 'trueButShow';
          ta.servlet.HACSearch.restoreDateFields();
        } else {
          searchAll.value = false;
        }
      }
    }

    if(options.hasKey('sponsor') && options.get('sponsor')) {
        var addSponsorship = $('addSponsorship');
        if(addSponsorship) addSponsorship.checked = true;
    }

    filterInProgress = false;
    ta.servlet.HACSearch.filtersChanged();
  },

  /**
   * Update the location hash. Call this any time the filters change.
   */
  update: function() {
    var form = $('HOTEL_FILTERS');
    // only need to track changes to filters
    var sel = [];
    var nonDefault = false;

    // record only those checked - clicking 'any' or other is handled automatically
    form.getElements('input[type=checkbox]').each(function(cb)
    {
      //  if it is checked, non-default, and not disabled (and not cat_1 or a nearbyGeo)
      var isNearbyGeoCB = cb.name.indexOf('nearbyGeos') != -1;
      if (cb.checked && !cb.hasClass('default') && cb.id != 'cat_1' && !isNearbyGeoCB)
      {
        //  record the selection
        sel.push(cb.id);

        // if this is not a 'childGeos' checkbox then the form is in a non-default state
        // also ignore top value checkbox since this is actually a sort
        if (cb.name.indexOf('childGeos') == -1 && cb.name.indexOf('sortGroup') == -1)
        {
            nonDefault = true;
        }
      }
      //  else if it is a 'childGeos' checkbox and not check the form is in a non-default state
      else if (!cb.checked && (cb.name.indexOf('childGeos') != -1))
      {
          nonDefault = true;
      }
    });

    // for hotels redesign, nearby cities moved out of HOTEL_FILTERS form to sidebar
    var sidebar = $('SIDEBAR');
    if (sidebar) {
      var nearbyCities = sidebar.getElement('.nearbyCities');
      if (nearbyCities) {
        nearbyCities.getElements('input[type=checkbox]').each(function(cb) {
          if (cb.checked && !cb.hasClass('default'))
          {
            //  record the selection
            sel.push(cb.id);
            nonDefault = true;
          }
        });
      }
    }

    if (sel.length > 0) this.setOption('cb', sel);
    else this.removeOption('cb');

    if (form.availability.value.length > 0 && form.availability.value != '0') this.setOption("availability", form.availability.value);
    if (form.sortOrder.value != 'popularity') this.setOption("sortOrder", form.sortOrder.value);
    if (form.l1price)   this.setOption("l1price", form.l1price.value);
    if (form.l1rating && form.l1rating.value != '1,5') this.setOption("l1rating", form.l1rating.value);
    if (form.sleeps)    this.setOption("sleeps", form.sleeps.value);
    if (form.bedrooms)  this.setOption("bedrooms", form.bedrooms.value);
    if (form.bathrooms) this.setOption("bathrooms", form.bathrooms.value);
    if (form.nameContains) this.setOption("nameContains", form.nameContains.value);
    if (form.distance) this.setOption("distance", form.distance.value);
    if (form.distanceSelect) this.setOption("distanceSelect", form.distanceSelect.value);
    if (form.nearbyGeosChecked) this.setOption("nearbyGeosChecked", form.nearbyGeosChecked.value);
    if (form.nearbyGeosUnchecked) this.setOption("nearbyGeosUnchecked", form.nearbyGeosUnchecked.value);
    if (form.includeNearbyModified) this.setOption("includeNearbyModified", form.includeNearbyModified.value);

    var pricePeriod_d = $('pricePeriod_d');
    if (pricePeriod_d) this.setOption('pricePeriod', (pricePeriod_d.checked ? "d" : "w"));

    //var rpp = $('rpp');
    //if (rpp && rpp.selectedIndex > 0) this.setOption('rpp', rpp.options[rpp.selectedIndex].value);

    //  check if any of the sliders have changed
    if (!nonDefault) {
      [['priceSelect', 'l1price'],
       ['ratingSelect', 'l1rating'],
       ['sleepsSelect', 'sleeps'],
       ['bedroomsSelect', 'bedrooms']].each(function(arr)
      {
        var elmt = $(arr[0]);
        if (!elmt) return;
        var inputName = arr[1];
        nonDefault = nonDefault || (form[inputName].value != "0,999999");
      });
    }

    //  check if our nearby geos have changed
    var includeNearby = $('includeNearby');
    if (includeNearby)
    {
        nonDefault = nonDefault || includeNearby.checked;
    }

    //  check if # of bathrooms have been changed
    var bathrooms = $('bathrooms');
    if (bathrooms)
    {
      //  we are assuming the first option is always the default
      nonDefault = nonDefault || (bathrooms.value != 0);
    }

    var nameContains = $('nameContains');
    if(nameContains)
    {
       nonDefault = nonDefault || ( nameContains.value && nameContains.value.length > 0);
    }

    //  hide/show the clear filter link
    if (!ta.has('redesignEnabled')) {
      var count = $('RESULT_COUNT');
      if (count) {
        var hvr = count.getElement('.hvrIE6');
        if (hvr) { 
          hvr.setStyle('display', nonDefault ? 'inline' : 'none'); 
        }
      }

      var clear = $$('#LARGE_MAP span.clear');
      if (clear) clear.setStyle('display', nonDefault ? 'block' : 'none');
    } else {
      // keep map Clear link in sync with the link in hacResults
      var mapClear = $('mapClear');
      var hacClear = $('hacResultClear');
      if (mapClear && hacClear) {
        mapClear.setStyle('display', hacClear.getStyle('display'));
      }
    }

    if (ta.has('hac.offset')) {
      var o = parseInt(ta.remove('hac.offset'));
      if (o > 0) this.setOption('o', o);
      else this.removeOption('o');
    }

    // store top value box state - expanded(1), collapsed(0), hidden(not present)
    var tvState = ta.retrieve("topvalue.state");
    if (tvState) {
      this.setOption('tv', tvState);
    } else {
      this.removeOption('tv');
    }

    // store searchAll
    var searchAll = $('searchAll');
    if (searchAll && searchAll.type == 'hidden') {
      if (searchAll.value == 'true') {
        this.setOption('sa', 1);
      } else if (searchAll.value == 'trueButShow') {
        this.setOption('sa', 2);
      } else {
        this.removeOption('sa');
      }
    }

    if (ta.retrieve('redesignEnabled') ) {
      if (ta.retrieve('maps.is_open')) {
        this.setOption('map',  1);
      } else {
        this.removeOption('map');
      }
    }

    var addSponsorship = $('addSponsorship');
    if(addSponsorship) this.setOption('sponsor', addSponsorship.checked);

    this.saveOptions();
  }
});
ta.servlet.HotelFilter.implement(new ta.util.Saveable);
ta.servlet.HACSearch.filter = new ta.servlet.HotelFilter();
