/**
 *
 * @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');
};

ta.util.Toggle.toggleTarget = function(evnt, elmt, target) {
  evnt.preventDefault();
  var open = true;
  if ($(elmt).hasClass('closed')) open = false;
  $(elmt).toggleClass('closed');
  $(target).setStyle('display', open ? 'none' : 'block');
};

/**
 * 
 * @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(CDNHOST + "/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();
    }
};

/**
 * Show a spinner in place of content.
 *
 * @param event the event
 * @param element the element
 */
ta.util.element.spinner = function(event, element)
{
  $(element).getParent('.spinnerReplaceable').getChildren().each(function(child){
    if (child.hasClass('spinner')) child.show();
    else child.hide();
  });
};

ta.util.element.clearDefault = function(event, element)
{
  if (element.value == element.defaultValue) element.value = "";
}
/**
 * @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.queueForLoad(ta._locationHash.load.bind(ta._locationHash), 1);

/**
 * @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(evnt, elmt) {
      var sponsor = /sponsor_(\w+)/.exec(elmt.className)[1];
      var sponsorList = $('SPR_HTLS_RHS');
      var toggleMore = $('SPR_HTL_MORE_' + sponsor);
      var toggleLess = $('SPR_HTL_LESS_' + sponsor);
      if(sponsorList) {
          new Ajax("/ActionRecord?action=sponsor_see_more").request()
          sponsorList.getElements('.list_' + sponsor).each(function(row) {
              row.removeClass('hide');
          });
      }
      if(toggleMore && toggleLess)
      {
          toggleMore.hide();
          toggleLess.show();
      }
  },

  showLessMapSponsor: function(evnt, elmt) {
      var sponsor = /sponsor_(\w+)/.exec(elmt.className)[1];
      var sponsorList = $('SPR_HTLS_RHS');
      var toggleMore = $('SPR_HTL_MORE_' + sponsor);
      var toggleLess = $('SPR_HTL_LESS_' + sponsor);
      if(sponsorList) {
          sponsorList.getElements('.list_' + sponsor).each(function(row) {
              row.addClass('hide');
          });
      }
      if(toggleMore && toggleLess)
      {
          toggleMore.show();
          toggleLess.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.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'));
        }
      }
    }
  },
  
  isNearbyCitiesHidden: function() {
    // HAC check
    var sidebar = $('SIDEBAR');
    if (sidebar) {
      var nearbyCities = sidebar.getElement('.nearbyCities');
      if (nearbyCities) {
        if (!nearbyCities.hasClass('hidden')) {
          return false;
        }
      }
    }
    // VRAC check
    var includeNearby = $('includeNearby');
    if (includeNearby && includeNearby.checked) {
      return false;
    }
    return true;
  },
  
  /**
   * 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.
   */
  filtersChanged: function(e, newPage) {
    filtersChanged(e, newPage);
  },

  /**
   * filtersChanged function that prevents the default action of an event.
   * This prevents a form being submitted when attached to an onsubmit event.
   */
  filtersChangedPreventDefault: function(e, newPage) {
    e.preventDefault();
    filtersChanged(e, newPage);
  },
  
  /**
   * Called when user clicks the search button next to name contains field
   */
  nameFilterChanged: function(event) {
    event.preventDefault();
    filtersChanged(null, true);
  },

  /**
   * 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(null, true);
      }
  },
  
  /**
   * 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;
    var newPage = 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);
      }
      newPage = false;
    }
    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);
        }
        // don't carry map settings when using neighborhood filter on LocalMaps
        if (window["pageServlet"] == 'LocalMapsRedesign') ta.remove('maps.keep_filters');
      }
      
      // 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, [null, newPage]);
    else ta.servlet.HACSearch.filtersChanged(null, newPage);
  },

  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();
    }
  },
  
  toggleListPhotoView: function(evnt, elmt) {
    var isListView = $('js_LIST_VIEW');
    var isPhotoView = $('js_PHOTO_VIEW');
    var isListChecked = isListView.getProperty('checked');
    var isPhotoChecked = isPhotoView.getProperty('checked');
    var isListCurrent = isListView.hasClass('current');
    var isPhotoCurrent = isPhotoView.hasClass('current');
    if ((isListCurrent && isPhotoChecked) || (isPhotoCurrent && isListChecked))
    {
      isListView.removeClass('current');
      isPhotoView.removeClass('current');
      $(elmt).addClass('current');
      filtersChanged();
    }
  },

  /**
   * 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) {
        var enabled = near.contains(cb.id);
        ta.servlet.HACSearch.setCheckSetChecked(cb, enabled);
        updateFilterStyle(cb, enabled);
      });
    }
    
    // pager links above map
    var map_pager = $('map_pager');
    var top_pager = $('pager_top2');
    if (map_pager) {
      if (top_pager) {
        map_pager = map_pager.getElement('div.pgLinks');
        if (map_pager) 
        {
          map_pager.innerHTML = top_pager.innerHTML;
          behavior.apply(map_pager);
        }
      } else {
        map_pager.innerHTML = '<div class="pgLinks"></div>';
      }
    }
    
    // keep Top Values check box on map in sync with one in list
    // this is pre-redesign only - see below for post redesign
    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');
      }
    }

    // keep sort bar and best value checkbox above map in sync with one in list
    // this only affects hotels_redesign mode
    var fromSortDiv = $('SORT_FORM');
    var toSortDiv = $('mapSortForm');
    if (fromSortDiv && toSortDiv) {
      toSortDiv.setHTML(fromSortDiv.innerHTML);
    }
    var mapTVRedesign = $('mapRedesignSG');
    if (mapTVRedesign && bvf) {
      var checkbox = mapTVRedesign.sortGroup
      checkbox.checked = bvf.sortGroup.checked;
      checkbox.disabled = bvf.sortGroup.disabled;

      var label = mapTVRedesign.getElement('span');
      label.innerHTML = bvf.getElement('label.bv span').innerHTML;
      if(mapTVRedesign.sortGroup.disabled) {
        label.addClass('disabled');
      } else {
        label.removeClass('disabled');
      }
    }

    // make sure availability toggles are in sync
    var fromDateBar = $('resultsDateBar');
    var toDateBar = $('mapDateBar');
    if (fromDateBar && toDateBar) {
        fromDateBar.getChildren('radio').each(function(from) {
                var to = toDateBar.getElement(".avail_" + from.value);
                if (to) {
                    to.checked = from.checked;
                }
            });
    }
    
    // showing X-Y of Z
    var lgMap = $('LARGE_MAP');
    if (lgMap) {
      var showing = lgMap.getElement('.showing');
      if (showing) {
        var count = $('ACCOM_OVERVIEW');
        var span = showing.getElement('span');
        if (count) {
          count = count.getElement('.pagination .pgCount');
          if (count) {
            span.innerHTML = count.innerHTML;
          }
          else {
            span.innerHTML = "0";
          }
        }
        else {
          span.innerHTML = "0";
        }
      }
    }
  },
  
  // real ad calls
  updateSponsorAds: function(type, sponsor) {
    new Ajax('/MapAdAjax?fromServlet='+window['pageServlet']+'&t='+type+'&sponsor='+sponsor, {
      method: 'get',
      evalScripts: true,
      onComplete: function(txt,xml) {
        var adContainer;
        if(type=='leader') {
          var lbArr = $('BODYCON').getElements('.iab_leaBoa');
          adContainer = lbArr[0];
          if(!adContainer) {
            adContainer = new Element('div', {'class': 'ad iab_leaBoa'});
            adContainer.injectTop($('BODYCON'));
          }
          adContainer.empty();
        } else {
          adContainer = $('MAP_SPONSOR'); 
        }
        adContainer.setHTML(txt);
        injectAdsTargeted(adContainer);
      }
    }).request();
  },
  
  // static ad content via ajax
  staticSponsorAd: function( sAction, sTarget, sFromServlet, sponsor ) {
    var params = [ {from:sFromServlet}, {Action:sAction}, {g:window['modelGeoId']}, {sponsors: sponsor} ]
    new Ajax('/GMapsLocationController', {
      data:params,
      update: $(sTarget)
    }).request();
  },
  
  
  /**
   * Toggle a marker type using the value of a checkbox or radio button.
   * @param {Event} evnt The Event
   * @param {Element} elmt Checkbox or Radio button
   */
  toggleTypeByValue: function(evnt, elmt) {
    if (!['checkbox', 'radio'].contains(elmt.type)) return;
    if (!ta.has('maps.map')) return;
    
    var map = ta.retrieve('maps.map');
    map.showOrHideType(elmt.checked, elmt.value);
  },
  
  /**
   * 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);
    // we need to be able to toggle before full map is loaded
    ta.servlet.HACSearch.toggleTypeByValue(evnt, elmt);
    var elmtValid = elmt && elmt.getTag()=='input';
    var addSponsorshipToggle = $('addSponsorshipToggle');  // ? no such element
    if (elmtValid) { 
      var staticMapToggle = $( elmt.id.replace('sidebar', 'thumb'));    // thumb_sponsor_bstWst
      if (elmt.checked) {
        ta.store('addSponsorship',1);
        ta.store('addSponsorshipToggle',"turnOn " + elmt.value);
        ta.store('addSponsorshipValue', elmt.value);
        // sync static map chkbx 
        if( staticMapToggle ) {
          staticMapToggle.checked = true;
        }
      } else {
        ta.store('addSponsorship',0);
        ta.store('addSponsorshipToggle',"turnOff " + elmt.value);
        ta.store('addSponsorshipValue', null);
        // sync static map chkbx
        if( staticMapToggle ) {
          staticMapToggle.checked = false;
          $('STMAP_OVERLAYS').empty();
        }
      }
    }
    ta.servlet.HACSearch.filtersChanged();
    if(elmt.checked) {
      ta.servlet.HACSearch.updateSponsorAds('leader', elmt.value);
      // traded real ad for static: ta.servlet.HACSearch.updateSponsorAds('bottom');
      ta.servlet.HACSearch.staticSponsorAd( 'hacmapBanner', 'HACMAP_AD_PARENT', 'HACSearch', elmt.value); 
      if (window['pageServlet'] == 'LocalMapsRedesign')
        ta.servlet.HACSearch.updateSponsorAds('bottom', elmt.value);
      ta.store('sponsor.active', elmt.value);
    } else {
      var featuredListings = $('SPR_HTLS_RHS');
      if(featuredListings) {
        featuredListings.empty();
      }
    }
  },
  
  /**
   * Toggles sponsor pins on the STATIC map ( requests a data update).
   * @param {Event} event The Event
   * @param {Element} elmt Checkbox or Radio button
   */
  toggleThumbSponsor: function(evnt, elmt) {
    var elmtValid = elmt && elmt.getTag()=='input';
    if (elmtValid) { 
      var largeMapToggle = $( elmt.id.replace('thumb', 'sidebar'));   // sidebar_sponsor_bstWst
      if (elmt.checked) { 
        ta.servlet.HACSearch.staticSponsorAd( 'staticmapBanner', 'STATMAP_AD_PARENT', 'HACSearch', elmt.value);
        largeMapToggle.click(); 
      } else {
        largeMapToggle.click(); 
        $('STMAP_OVERLAYS').empty();
      }
    }
  },
  
  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} checkbox 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);
  },

  /**
   * Handle clicking on the count for a check set checkbox
   * This should check the box for the count and disable the rest
   * @param {Event} event The Event
   * @param {Element} element The span containing the count
   * #param {String} checkboxId The id of the checkbox for this count
   */
  handleCheckSetClickOnCount: function(event, element, checkboxId)
  {
    // prevent event propagation so that we don't see a click on the checkbox
    new Event(event).stop();
    // iterate over all checkboxes setting only checking the selected
    var checkBoxes = $(checkboxId).getParent('fieldset').getElements('div.chkSet input');
    for (var i = 0; i < checkBoxes.length; ++i) {
      ta.servlet.HACSearch.setCheckSetChecked($(checkBoxes[i]), $(checkBoxes[i]).id == checkboxId);
    }
    //  update the results
    ta.servlet.HACSearch.toggleFilter(event, $(checkboxId));
  },

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

    // don't keep map position when doing a date search
    ta.remove('maps.keep_filters');

    updateResults(true);
  
    //check for flights search selected
    var chkFlights = $('findFlights');
    if( chkFlights && chkFlights.checked ) {
       if(ta.popups.FlightSearch) {
         try {
           ta.popups.FlightSearch.popFlightSearch();
         }
         catch(e) {}
      }
    }
  },

  /**
   * 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;
  },
  
  /**
   * 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();
    if(ta.has('sponsor.active') && (elmt.getTag()=='a' || elmt.getTag()=='span' || elmt.getTag()=='img' )) {
      ta.store('sponsor.record_map_open');
    }
  
    // register sponsored map tracking pixels
    $$('.hacMapAdPixelHolder').each( function(elt) { ta.servlet.HACSearch._downloadTrackPixel(elt); });
    
    ta.servlet.HACSearch.loadOrShowLargeMap(true);

    // close the window shade if it is currently open
    if(typeof autoCloseWindowShade != "undefined")
    {
      autoCloseWindowShade();    
    }
  },
  
  _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) {
    window.windowShade = false;
    ta.store('maps.is_open', true);

    if (ta.retrieve('moveResultSummary')) { 
      var resultSummaryDiv = $('HAC_SMRY'); 
      var resultsDiv = $('LARGE_MAP'); 
      if(resultSummaryDiv && resultsDiv) { 
        resultSummaryDiv.injectBefore(resultsDiv); 
      } 
    }

    if (updateFilter) {
      ta.servlet.HACSearch.filter.update();
    }
    if ($('SMALL_MAP')) {
      $('SMALL_MAP').setStyle('display', 'none');
    }
    //show the sponsor's featured listings
    if ($('SPR_HTLS_RHS')) {
      $('SPR_HTLS_RHS').setStyle('display','block');
    }
    
    //load sponsor track pixels
    $$('.sponsorTrkHolder').each( function(elt) { ta.servlet.HACSearch._downloadTrackPixel(elt); });
    
    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', []);

      if(ta.has('sponsor.record_map_open')) {
        ta.remove('sponsor.record_map_open');
        new Ajax('/ActionRecord?action=sponsor_hacmap_open').request();
      }
      
      // 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();
        }
        
        if (ta.has('maps.actionrecord')) {
          var actionrecord = ta.remove('maps.actionrecord');
          new Ajax(actionrecord).request();
        }
        
      });
    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');  
    if($('SPR_HTLS_RHS')) {
      $('SPR_HTLS_RHS').setStyle('display', 'none');
    }
    ta.servlet.HACSearch.hideMapSponsor();
    //load sponsor track pixels for small map
    $$('.thumbPixelHolder').each( function(elt) { ta.servlet.HACSearch._downloadTrackPixel(elt); });
    $$('.thumbAdPixelHolder').each( function(elt) { ta.servlet.HACSearch._downloadTrackPixel(elt); });
    if( ta.retrieve('addSponsorship') ==1 ) {
      ta.servlet.HACSearch.staticSponsorAd( 'staticmapBanner', 'STATMAP_AD_PARENT', 'HACSearch', ta.retrieve('addSponsorshipValue'));
    }
    ta.remove('maps.is_open');
    ta.servlet.HACSearch.filter.update();
    
    // hide numbered pins
    hideTitlePins();

    if (ta.retrieve('moveResultSummary')) { 
      var resultSummaryDiv = $('HAC_SMRY'); 
      var resultsDiv = $('HAC_RESULTS'); 
      if(resultSummaryDiv && resultsDiv) { 
        resultSummaryDiv.injectBefore(resultsDiv); 
      } 
    }
  },

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

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

  showClearDates:function() {
    $$('#HAC_SMRY .smry .hvrIE6').each(function(el) {
        el.setStyle('display', 'inline');
      });
    
    $$('#HAC_DATES .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();
    // check the best value box
    if ($('BEST_VALUE_FORM')) {
      $('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; 
    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
     if ($('BEST_VALUE_FORM')) {
       $('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');
    }
    if (elmt.className.match(/current/)) return;
    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');
      }
    }
  },
  


  /**
   * Callback for when a paging link is clicked.
   *
   * @param event the event
   * @param elmt element that was clicked
   */
  changeOffset: function(event, elmt, offset)
  {
    new Event(event).preventDefault();
    ta.store('hacform.data', {o: 'a' + offset});
    filtersChanged();
  },

  /**
   * 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() {
    if($('add_location_input_filter'))
    {
      return $('add_location_input_filter').value;
    }
    return $('SMALL_MAP_ADDRESS').getFirst().address.value;
  },
  
  _setMiniMapAddress: function(text) {
    if($('add_location_input_filter'))
    {
      if(text != map_findhotelnear)
      {
        $('add_location_input_filter').value = text;
      }
    } 
    $('SMALL_MAP_ADDRESS').getFirst().address.value = text;
  },
  
  onMiniMapAddressSubmit: function(event, elmt) {
    new Event(event).stop();
    var form = $('SMALL_MAP_ADDRESS').getFirst();
    var uri = form.action;
    var address = ta.servlet.HACSearch._getMiniMapAddress();
    if (address != "" && address != map_findhotelnear) uri += ",bc_address:S" + address;
    document.location.href = uri;
    return false;
  },
  
  _doAddressSearch: function() {
    var address = ta.servlet.HACSearch._getMiniMapAddress();
    var input = $("add_location_input");
    if(input)
    {
      input.value = address;
    }
    var input_filter = $("add_location_input_filter");
    if(input_filter)
    {
      input_filter.value = address;
    }   
    //needs evnt, elmt?
    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 input = $("add_location_input");
    if(input)
    {
      input.value = "";
      input.removeClass("unfocused");
    }
    var input_filter = $("add_location_input_filter");
    if(input_filter)
    {
      input_filter.value = "";
      input_filter.removeClass("unfocused");
    }   
  },
  
  onLargeMapAddressBlur: function(event, elmt) {
    var input = $("add_location_input");
    if(input && input.value.length == 0)
    {
      input.value = map_enteraddress;
      input.addClass("unfocused");
    }
    var input_filter = $("add_location_input_filter");
    if(input_filter && input.value.length == 0)
    {
      input_filter.value = "";
      input_filter.addClass("unfocused");
    }   
  },
  
  _downloadTrackPixel: function (holderElmt) {
    if(holderElmt) {
      var imgSrc = "http://" + holderElmt.getText().trim();
      var imgElmt = $(document.createElement('img')).injectInside(holderElmt.empty());
      imgElmt.src = imgSrc;
      holderElmt.className = "";  // handle all variants of sponsorTrkHolder
    }
  }

};
/**
 * @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')) {
      var ddLinkBar = $('DAODAO_LINKBAR');
      //  apply the checkbox state from the hash
      options.get('cb').each(function(id){
        cb = $(id);
        if ($defined(ddLinkBar)) {
          setSelected(ddLinkBar.getElement('span.' + 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'
    };
    
    var ddLinkBar = $('DAODAO_LINKBAR');
    for (op in sliderMap) {
      if (options.hasKey(op) && options.get(op) != $(op).value) {
        if( $defined(ddLinkBar) ) {
          var ddLink = ddLinkBar.getElement('span.' + op + options.get(op).replace(',', '-').replace('\.', ''));
          if ($defined(ddLink)) {
            setSelected(ddLink);
          } else if (op == 'l1price') {
            setCustomPrice(options.get(op).split(','));
          }
        }
        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')) {
      var item = options.get('availability');
      var availToggle = $('availability_'+item);
      if (availToggle) {
        // non-redesign version
        availToggle.checked = true;
      }
      else {
        // for redesign, there are two.  Get parent by id to avoid full document search
        var mapDatebar = $('mapDateBar');
        if (mapDatebar) {          
          mapDatebar.getElement('.avail_' + item).checked = true;
        }
        var resultsDatebar = $('resultsDateBar');
        if (resultsDatebar) {
          resultsDatebar.getElement('.avail_' + item).checked = true;                    
        }
      }
    }

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

    if (options.hasKey('nameContains')) {
        $('nameContains').value = options.get('nameContains');
        if ($defined(ddLinkBar) && $('ddnameContains') != null) {
          $('ddnameContains').value = options.get('nameContains');
        }
    }

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

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

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

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

    //  update select elements
    ['bathrooms', 'distanceSelect', 'minStay'].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');
    var filterForm = $('HAC_FILTER_CONTROLS');
    // only need to track changes to filters
    var sel = [];
    var nonDefault = false;

    var formSet = [];
    if(form) formSet.push(form);
    if(filterForm) formSet.push(filterForm);
    
    // record only those checked - clicking 'any' or other is handled automatically
    formSet.each(function(aForm){
      aForm.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');

    formSet.each(function(aForm){ 
      if (aForm.availability && aForm.availability.value.length > 0 && aForm.availability.value != '0') this.setOption("availability", aForm.availability.value);
      if (aForm.sortOrder && aForm.sortOrder.value != 'popularity' && aForm.sortOrder.value != 'popHigh') this.setOption("sortOrder", aForm.sortOrder.value);
      if (aForm.l1price && aForm.l1price.value != '0,999999') this.setOption("l1price", aForm.l1price.value);
      if (aForm.l1rating && aForm.l1rating.value != '1,5' && aForm.l1rating.value != '0,999999') this.setOption("l1rating", aForm.l1rating.value);
      if (aForm.sleeps)    this.setOption("sleeps", aForm.sleeps.value);
      if (aForm.bedrooms)  this.setOption("bedrooms", aForm.bedrooms.value);
      if (aForm.bathrooms) this.setOption("bathrooms", aForm.bathrooms.value);
      if (aForm.minStay) this.setOption("minStay", aForm.minStay.value);
      if (aForm.nameContains) this.setOption("nameContains", escape(aForm.nameContains.value));
      if (aForm.distance) this.setOption("distance", aForm.distance.value);
      if (aForm.distanceSelect) this.setOption("distanceSelect", aForm.distanceSelect.value);
      if (aForm.nearbyGeosChecked) this.setOption("nearbyGeosChecked", aForm.nearbyGeosChecked.value);
      if (aForm.nearbyGeosUnchecked) this.setOption("nearbyGeosUnchecked", aForm.nearbyGeosUnchecked.value);
      if (aForm.includeNearbyModified) this.setOption("includeNearbyModified", aForm.includeNearbyModified.value);
    }, this);
    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
    var altForm = filterForm ? filterForm : form;
    if (!nonDefault) {
      [['priceSelect', 'l1price', altForm],
       ['ratingSelect', 'l1rating', form],
       ['sleepsSelect', 'sleeps', form],
       ['bedroomsSelect', 'bedrooms', form]].each(function(arr)
      {
        var elmt = $(arr[0]);
        if (!elmt) return;
        var inputName = arr[1];
        var sliderForm = arr[2];
        nonDefault = nonDefault || (sliderForm[inputName].value != "0,999999");
      });
    }

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

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

    //  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
    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');

    
    if (ta.has('redesignEnabled')) {
      // 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 (mapClear.getStyle('display') == 'none') {
          resetMap = $('RESET_MAP');
          if (resetMap) {
            resetMap.setStyle('border-left', 'none');
          }
        }
      }
    } else if ($('VR_MAP2_CLEAR')) {
      $('VR_MAP2_CLEAR').setStyle('display', $('hacResultClear').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();
