// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

// =================================================
// This all needs a massive refactor, but I've done
// a quick hack job to get _something_ up and running
// =================================================
var CONTIKI = function() {
  // Private Variables
  // var myPrivateVar = 'foo';

  // Private Method
  // var myPrivateMethod = function() {}

  return {
    // Public properties
    // myPublicProperty: 'bar'

    // Public Methods
    // myPublicMethod: function() {}
  };
}();

function addEvent(element, type, func){
 if (element.addEventListener) {
     element.addEventListener(type, func, false);
     return true;
   } else if (element.attachEvent) {
     return element.attachEvent("on" + type, func);
   }
  return false;
}

function getURLParam( name ) {
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}

function hideDivs(exempt)
{
  if (!document.getElementsByTagName) return null;
  if (!exempt) exempt = "";

  for(var i=0; i < tourDivNames.length; i++)
  {
    if (document.getElementById(tourDivNames[i]))
    {
      var div = document.getElementById(tourDivNames[i]);
      var id = div.id;
      if (id != exempt)
      {
        div.style.display = "none";
      }
    }
  }
}

function show(what)
{
  if (!document.getElementById || !document.getElementById(what)) return null;
  showWhat = document.getElementById(what);
  showWhat.style.display = "";
  hideDivs(what);
}

function navSwitch(clicked_id, reveal_id)
{
  if (!document.getElementsByTagName || !document.getElementById) return null;
  show(reveal_id);
  var navElements = target_nav.getElementsByTagName('li');
  for(var i=0; i < navElements.length; i++)
  {
    var navElement = navElements[i];
    if (navElement.id == clicked_id)
    {
      navElement.className = "current";
    }
    else
    {
        navElement.className = "";
      }
  }

}


function init() {

  navSwitch('nav_itinerary', 'itinerary');

}

function unimplemented() {
  alert("NOTICE\n\nThis feature is not implemented yet. Please check back again soon!");
}

/*
* Counts the number of words within a form field element and updates
* an element in the DOM with the current count.
*/
function word_counter(form_field, element) {
  var count = 0;
  $(form_field).getValue().scan(/\w+/, function(match) { count++; });
  $(element).update(count);
}

function unhide_element(element_id) {
  Element.show(element_id);
}

function hide_element(element_id) {
  Element.hide(element_id);
}


/*
* Counts the number of words within a form field element and updates
* an element in the DOM with the current count.
*/

function x_html_engine_auto_helper(form_field) {

  obj = $(form_field);

  if(obj.selectionStart) {
    var start = obj.selectionStart;
    var end   = obj.selectionEnd;

    var content_array = obj.getValue().substr(0,start).toArray();

  }

  content_array.reverse();

  if ($('x_html_engine_open').getValue() == 't') {
    $('x_html_engine_auto_helper').childElements().each(function(node) { node.remove() } );
    $('x_html_engine_auto_helper').hide();
    $('x_html_engine_open').value = 'f';
  }

  if ($('x_html_engine_non_match_open').getValue() == 't') {
    $('x_html_engine_auto_helper_no_match').childElements().each(function(node) { node.remove() } );
    $('x_html_engine_auto_helper_no_match').hide();
    $('x_html_engine_non_match_open').value = 'f';
  }

  if (content_array[1] == ')') { }

  if (content_array[1] == '(') {
    // get an array of possible matches for key
    var possible_extensions = html_extensions_find_by_key(content_array[0]);
    var i = 0;
    possible_extensions.each(function(item) {
      var element = new Element('li', { id: 'x_extension_' + i } );
      element.innerHTML = '(' + content_array[0] + item + ')';
      $('x_html_engine_auto_helper').appendChild(element);
      i++;
    })
    $('x_html_engine_open').value = 't';
    $('x_html_engine_auto_helper').show();
  } else if (content_array[2] == '(') {
      var possible_extensions = html_extensions_find_by_key(content_array[1]);
      var found_match = 'f';
      possible_extensions.each(function(match) {
       if (match == content_array[0]) { found_match = 't'; }
      })
      if (found_match == 't') {
        // Turn off auto-fill
        // $(form_field).value = $(form_field).getValue() + ')';
        $('x_html_engine_open').value = 'f';
        $('x_html_engine_auto_helper').childElements().each(function(node) { node.remove() } );
      } else {
        var i = 0
        var modifiers = html_extension_modifiers_find_by_key(content_array[0]);

        // update span in error message with the input that the user provided
        var error_message = new Element('li', { id: 'x_non_match_error'});
        error_message.innerHTML = 'There is no special character for ' + '(' + content_array[1] + content_array[0] + ', 2)' + '. You might be thinking of...';
        $('x_html_engine_auto_helper_no_match').appendChild(error_message);

        modifiers.each(function(item) {
          var element = new Element('li', { id: 'x_non_match_' + i});
          element.innerHTML = '(' + item + content_array[0] + ')'
          $('x_html_engine_auto_helper_no_match').appendChild(element);
          i++;
        })


        $('x_html_engine_non_match_open').value = 't';
        $('x_html_engine_auto_helper_no_match').show();

      }
  } else {
    $('x_html_engine_open').value = 'f';
    $('x_html_engine_auto_helper').childElements().each(function(node) { node.remove() } );

  }
}

function html_extensions(key) {
  var extensions = new $H({});

  extensions.merge( { '!': [ "" ] });
  extensions.merge( { 'L': [ "-" ] });
  extensions.merge( { 'a': [ "'", "~", "o", "\"", "`", "e", "^" ] });
  extensions.merge( { 'A': [ "^", "'", "o", "`", "E", "\"", "~" ] });
  extensions.merge( { 'Y': [ "=", "'" ] });
  extensions.merge( { 'y': [ "\"", "'" ] });
  extensions.merge( { 'N': [ "~" ] });
  extensions.merge( { 'n': [ "~" ] });
  extensions.merge( { '.': [ "" ] });
  extensions.merge( { 'c': [ "", ",", "|" ] });
  extensions.merge( { 'C': [ "=", "," ] });
  extensions.merge( { 'D': [ "-" ] });
  extensions.merge( { 'O': [ "^", "~", "\"", "/", "'", "`", "E" ] });
  extensions.merge( { 'o': [
    "^",

    "",

    "~",

    "'",

    "`",

    "\"",

    "/"
     ] });


  extensions.merge( { 'd': [
    "-"
     ] });


  extensions.merge( { 'E': [
    "`",

    "^",

    "'",

    "\""
     ] });


  extensions.merge( { 'e': [
    "^",

    "\"",

    "`",

    "'"
     ] });


  extensions.merge( { 'r': [
    "",
     ] });


  extensions.merge( { 's': [
    "v"
     ] });


  extensions.merge( { 'S': [
    "v"
     ] });


  extensions.merge( { '?': [
    ""
     ] });


  extensions.merge( { 'i': [
    "'",

    "\"",

    "`",

    "^"
     ] });


  extensions.merge( { 'I': [
    "^",

    "`",

    "\"",

    "'"
     ] });


  extensions.merge( { 't': [
    "m"
     ] });


  extensions.merge( { '*': [
    ""
     ] });


  extensions.merge( { 'u': [
    "\"",

    "^",

    "'",

    "`"
     ] });


  extensions.merge( { 'U': [
    "\"",

    "`",

    "'",

    "^",
     ] });


  return extensions[key];
}

function html_extensions_find_by_key(key) {
  var keys = html_extensions(key);
  if (keys && keys.length > 0) {
    return keys;
  } else {
    return [''];
  }
}

function html_extension_modifiers(key) {
  var extensions = $H({});
  extensions.merge( {   'v': [
    "S",
    "s",
   ] });

  extensions.merge( {   '`': [
    "U",
    "E",
    "e",
    "A",
    "I",
    "a",
    "u",
    "o",
    "i",
    "O",
   ] });

  extensions.merge( {   ',': [
    "c",
    "C",
   ] });

  extensions.merge( {   'm': [
    "t",
   ] });

  extensions.merge( {   '-': [
    "d",
    "L",
    "D",
   ] });

  extensions.merge( {   '"': [
    "U",
    "u",
    "e",
    "O",
    "a",
    "i",
    "A",
    "I",
    "o",
    "y",
    "E",
   ] });

  extensions.merge( {   '/': [
    "O",
    "o",
   ] });

  extensions.merge( {   'o': [
    "A",
    "a",
   ] });

  extensions.merge( {   '': [
    "c",
    ".",
    "o",
    "?",
    "*",
    "!",
    "r",
   ] });

  extensions.merge( {   'e': [
    "a",
   ] });

  extensions.merge( {   'E': [
    "A",
    "O",
   ] });

  extensions.merge( {   '|': [
    "c",
   ] });

  extensions.merge( {   '=': [
    "C",
    "Y",
   ] });

  extensions.merge( {   'ooo': [
    "a",
    "A",
    "u",
    "U",
    "i",
    "o",
    "O",
    "E",
    "e",
    "y",
    "Y",
    "I",
   ] });

  extensions.merge( {   '~': [
    "a",
    "O",
    "o",
    "n",
    "N",
    "A",
   ] });

  extensions.merge( {   '^': [
    "A",
    "e",
    "o",
    "O",
    "u",
    "E",
    "I",
    "a",
    "U",
    "i",
   ] });

  return extensions[key];
}

function html_extension_modifiers_find_by_key(key) {
  var keys = html_extension_modifiers(key);
  if (keys && keys.length > 0) {
    return keys;
  } else {
    return [''];
  }
}

function toggle_channel_setting(id){
  field_value = parseInt($('x_channel_value_' + id).value) + 1

  // Bypass 'channel' assignment if it is not available to this channel
  if (field_value == 1 && $('x_channel_channel_' + id).value == "false") {
    field_value += 1
  }

  // Bypass 'featured' assignment if it is not available to this channel
  if (field_value == 2 && $('x_channel_feature_' + id).value == "false") {
    field_value += 1
  }

  // Reset assignment to 'off'
  if (field_value == 3) { field_value = 0 }

  $('x_channel_value_' + id).value = field_value
  setup_channel_selector_style(id)
}

function setup_channel_selector_style(id){
  // Set style of widget based upon value
  switch($('x_channel_value_' + id).value){
    case "0":
      $('x_channel_selector_' + id).className = 'channel_unselected';
      break;
    case "1":
      $('x_channel_selector_' + id).className = 'channel_selected';
      break;
    case "2":
      $('x_channel_selector_' + id).className = 'channel_featured';
      break;
  }
}

function insertAtCaret(obj, text) {
  if(document.selection) {
    obj.focus();
    var orig = obj.value.replace(/\r\n/g, "\n");
    var range = document.selection.createRange();

    if(range.parentElement() != obj) {
      return false;
    }

    range.text = text;
    range.select();

  } else if(obj.selectionStart) {
    var start = obj.selectionStart;
    var end   = obj.selectionEnd;

    obj.value = obj.value.substr(0, start)
      + text
      + obj.value.substr(end, obj.value.length);
  }

  if(start != null) {
    setCaretTo(obj, start + text.length);
  } else {
    obj.value += text;
  }
}

function setCaretTo(obj, pos) {
  if(obj.createTextRange) {
    var range = obj.createTextRange();
    range.move('character', pos);
    range.select();
  } else if(obj.selectionStart) {
    obj.focus();
    obj.setSelectionRange(pos, pos);
  }
}

function field_with_default_onfocus(element, default_value) {
  if(element.value == default_value) {
    element.value = '';
  }
  element.style.color = 'black';
}

function field_with_default_onblur(element, default_value) {
  if(element.value == "") {
    element.value = default_value;
    element.style.color = 'grey';
  }
}

// This script is for toggling interface visibility
// assuming we want to just load each comments edit-UI
// and avoid the dev overhead of doing it with ajax

function DisplayEditable(comment_id) {
  // Build the div id's
  edited_div_id = "edited_comment_" + comment_id;
  editing_div_id = "x_editing_comment_" + comment_id;

  // Toggle the divs visibility
  if($(edited_div_id)){
    new Effect.SwitchOff($(edited_div_id));
  }
  new Effect.Appear($(editing_div_id));
}
function HideEditable(comment_id) {
    // Build the div id's
  edited_div_id = "edited_comment_" + comment_id;
  editing_div_id = "x_editing_comment_" + comment_id;

  // Toggle the divs visibility
  if($(edited_div_id)){
  new Effect.Appear($(edited_div_id));
  }
  new Effect.SwitchOff($(editing_div_id));
}


/*
Functions used by Repository edit screens

*/
Object.extend(Array.prototype, {
  toQueryString: function(name) {
    return this.collect(function(item) { return name + "[]=" + encodeURIComponent(item) }).join('&');
    }
});

var OrderingWidget = Class.create();

OrderingWidget.prototype = {
  initialize: function(containerName, itemPrefix, resultUrl)
  {
    this.containerName = containerName;
    this.itemPrefix  = itemPrefix;
    this.resultUrl   = resultUrl;
  },

  startOrdering: function()
  {
    Sortable.create(this.containerName);
    // then disable all links so they can be used for dragging (kinda hackish)
    $$("#" + this.containerName + " li a").map(function(elem)
    {
      elem.onclick= function() {return false};
    });
    this.startButton.hide();
    this.doneButton.show();
  },

  cssSelector: function()
  {
    return '#' + this.containerName + ' li';
  },

  parseId: function(elem)
  {
    return elem.id.sub(this.itemPrefix, '');
  },

  doneOrdering: function()
  {
    var newOrder = $$(this.cssSelector()).map(this.parseId.bind(this));
    new Ajax.Request(this.resultUrl, {
      postBody: newOrder.toQueryString("order")
    });
  },

  associateButtons: function(startButton, doneButton)
  {
    this.startButton    = startButton;
    startButton.onclick = this.startOrdering.bindAsEventListener(this);
    this.doneButton     = doneButton;
    doneButton.onclick  = this.doneOrdering.bindAsEventListener(this);
    doneButton.hide();
  }
};


/**************
//  ManageFlag
//
//  Javascript to manage the flag/unflag as appropriate for photos and comments.
************/
var ManageFlag = Class.create();
ManageFlag.prototype = {
  initialize: function( element ) {
    this.element       = $(element);
    this.actions_container   = this.element.parentNode;
    this.actions_tag    = this.actions_container.tagName;
    this.flag_action     = 'flag';
    this.unflag_action     = 'unflag';

    // setup the current mode and the base href
    this.initializeCurrentModeAndHref();

    this.element.onclick = this.handleLinkClicked.bindAsEventListener( this );
  },

  initializeCurrentModeAndHref: function() {
    current_href = this.element.href;
    if ( current_href.indexOf('/unflag') > 0 ) {
      this.href = this.element.href.gsub('/unflag', '');
      this.current_mode = 'flagged';
    } else {
      this.href = this.element.href.gsub('/flag','');
      this.current_mode = 'unflagged';
    }
  },

  handleLinkClicked: function( event ) {
    if ( this.current_mode == 'unflagged' ) {
      this.flagItem();
    } else {
      this.unflagItem();
    }
    Event.stop( event );
  },

  flagItem: function() {
    _this = this;
    new Ajax.Request( this.href + "/" + this.flag_action, {
      method: 'post',
      onSuccess: _this.handleSuccessfulFlagging.bindAsEventListener( _this )
    });
  },

  handleSuccessfulFlagging: function( transport ) {
    parent_container = this.actions_container.parentNode;
    unflag_contents = this.getUnflagContents();
    parent_container.replaceChild( unflag_contents, this.actions_container );
    this.actions_container = unflag_contents;
    this.current_mode = 'flagged';
  },

  unflagItem: function() {
    _this = this;
    new Ajax.Request( this.href + "/" + this.unflag_action, {
      method: 'post',
      onSuccess: _this.handleSuccessfulUnflagging.bindAsEventListener( _this )
    });
  },

  handleSuccessfulUnflagging: function( transport ) {
    parent_container = this.actions_container.parentNode;
    flag_contents = this.getFlagContents();
    parent_container.replaceChild( flag_contents, this.actions_container );
    this.actions_container = flag_contents;
    this.current_mode = 'unflagged';
  },

  getUnflagContents: function() {
    if ( this.unflag_contents ) {
      return this.unflag_contents;
    }


    unflag_contents = document.createElement( this.actions_tag );
    unflag_contents.addClassName( 'actions' );

    undo_link = document.createElement( 'a' );
    undo_link.setAttribute( 'href', '#' );
    undo_link.onclick = this.handleLinkClicked.bindAsEventListener( this );
    undo_link.appendChild( document.createTextNode( 'undo this' ) );

    unflag_contents.appendChild( document.createTextNode( 'Flagged Inappropriate | ' ) );
    unflag_contents.appendChild( undo_link );

    this.unflag_contents = unflag_contents;
    return this.unflag_contents;

  },

  getFlagContents: function() {
    if ( this.flag_contents ) {
      return this.flag_contents;
    }

    flag_contents = document.createElement( this.actions_tag );
    flag_contents.addClassName( 'actions' );

    flag_link = document.createElement( 'a' );
    flag_link.setAttribute( 'href', '#' );
    flag_link.onclick = this.handleLinkClicked.bindAsEventListener( this );
    flag_link.appendChild( document.createTextNode( 'Flag as Inappropriate' ) );

    flag_contents.appendChild( flag_link );

    this.flag_contents = flag_contents;
    return this.flag_contents;
  }

};

function postProcessUpdateKeypress(box, e, name, maxlength) {
  var val = box.value;
  updateStatusTextCharCounter(name, val, maxlength);
}

function updateStatusTextCharCounter(name, value, max_length) {
  $(name).innerHTML = max_length - value.length + ' characters remaining';
  if (value.length > max_length) {
    $(name).setStyle({ color: '#d40d12' });
  } else {
    $(name).setStyle({ color: '#444444' });
  }
};

function disableTourAdditionButton() {
  $('x_add_tour').disable();
  $('x_remove_tour').enable();
}

function enableTourAdditionButton(maximum_tours) {
  if (total_selections() < maximum_tours) {
    $('x_add_tour').enable();
    }
  $('x_remove_tour').disable();
}

function total_selections() {
  var selections = $('x_tour_selections').getValue().split(',').length
  return selections;
}


function show_fields_for(element_id) {
 $(element_id).show();
}

function hide_fields_for(element_id) {
  $(element_id).hide();
}


function toggle_associated_itineraries(leg_description_id) {
$('x_see_associated_itineraries_' + leg_description_id ).toggle();
$('x_close_associated_itineraries_' + leg_description_id ).toggle();
$('x_leg_associations_' + leg_description_id ).toggle();
}

var DepartureScheduleCalendar = Class.create();

DepartureScheduleCalendar.prototype = {
  initialize: function( element, back_button_element, forward_button_element, all_day_link_element ) {
    this.element = element;
    this.back_button_element = back_button_element;
    this.forward_button_element = forward_button_element;
    this.all_day_link_element = all_day_link_element;

    this.schedule_days = $( this.element ).select( '.tour_day' ).toArray();
    this.itinerary_schedule_days_list = $( 'x_itinerary_schedule_days_list' ).select( '.x_schedule_day' ).toArray();

    this.current_day_index = 0; // first is zero

    this.back_button_disabled = 1;
    this.forward_button_disabled = 0;

    this.highlightCurrentDay();
    this.observeForwardButton();
    this.observeItineraryDays( this );
    this.observeAllItineraryDayLink();
  },

  handleDayClick: function( event, itinerary_calendar ) {
    var element = Event.element( event );
    itinerary_calendar.schedule_days.each( function(day, index) {
      if ( day == element ) {
        itinerary_calendar.current_day_index = index;
        itinerary_calendar.updateCalendar();
      }
    })
  },

  nextDay: function() { return this.current_day_index + 1 },
  previousDay: function() { return this.current_day_index - 1 },

  moveForward: function() {
    this.current_day_index = this.nextDay();
    this.updateCalendar();
  },

  moveBack: function() {
    this.current_day_index = this.previousDay();
    this.updateCalendar();
  },

  showAll: function() {
    $( this.all_day_link_element ).hide();
    this.showAllDays();
  },

  observeBackButton: function() {
    Event.observe( this.back_button_element, 'click', this.moveBack.bindAsEventListener(this), false );
  },

  observeForwardButton: function() {
    Event.observe( this.forward_button_element, 'click', this.moveForward.bindAsEventListener(this), false );
  },

  observeItineraryDays: function( itinerary_calendar ) {
    itinerary_calendar.schedule_days.each( function( schedule_day, index ) {
      Event.observe( schedule_day, 'click', itinerary_calendar.handleDayClick.bindAsEventListener( this, itinerary_calendar ), false );
    })
  },

  observeAllItineraryDayLink: function() {
    Event.observe( this.all_day_link_element, 'click', this.showAll.bindAsEventListener(this), false );
  },

  disableBackButton: function() {
    this.back_button_disabled = 1;
    $( this.back_button_element ).removeClassName( 'x_itinerary_schedule_button' );
    $( this.back_button_element ).addClassName( 'x_itinerary_schedule_button_disabled' );
    Event.stopObserving( this.back_button_element, 'click' );
  },

  disableForwardButton: function() {
    this.forward_button_disabled = 1;
    $( this.forward_button_element ).removeClassName( 'x_itinerary_schedule_button' );
    $( this.forward_button_element ).addClassName( 'x_itinerary_schedule_button_disabled' );
    Event.stopObserving( this.forward_button_element, 'click' );
  },

  enableBackButton: function() {
    this.back_button_disabled = 0;
    $( this.back_button_element ).removeClassName( 'x_itinerary_schedule_button_disabled' );
    $( this.back_button_element ).addClassName( 'x_itinerary_schedule_button' );
    this.observeBackButton();
  },

  enableForwardButton: function() {
    this.forward_button_disabled = 0;
    $( this.forward_button_element ).removeClassName( 'x_itinerary_schedule_button_disabled' );
    $( this.forward_button_element ).addClassName( 'x_itinerary_schedule_button' );
    this.observeForwardButton();
  },

  resetScheduleDays: function() {
    this.schedule_days.each( function( element ) {
      $( element ).removeClassName( 'current_day' );
    })

    this.itinerary_schedule_days_list.each( function( element ) {
      $( element ).hide();
    })
  },

  highlightCurrentDay: function() {
    $( this.schedule_days[ this.current_day_index ] ).addClassName( 'current_day' );
    $( 'x_itinerary_schedule_day_' + this.current_day_index ).show();
  },

  showAllDays: function() {
    this.itinerary_schedule_days_list.each( function( element ) {
      $( element ).show();
    })
  },

  updateCalendar: function() {
    // reset days
    this.resetScheduleDays();

    // highlight current day
    this.highlightCurrentDay();

    // update buttons
    if ( this.schedule_days[this.current_day_index] == this.schedule_days.first() ) {
      this.disableBackButton();
    }   else {
        if ( this.back_button_disabled == 1 ) {
          this.enableBackButton();
        }
      }

    if ( this.schedule_days[this.current_day_index] == this.schedule_days.last() ) {
      this.disableForwardButton();
    } else {
      if ( this.forward_button_disabled == 1 ) {
        this.enableForwardButton();
      }
    }
  }
}

var DepartureCalendar = Class.create();
DepartureCalendar.prototype = {
  initialize: function( element, back_button_element, forward_button_element ) {
    this.element = element;
    this.visible_calendar_size = 3;
    this.visible_calendar_month_first = 0;
    this.visible_calendar_month_last = 2;
    this.calendar_months = $( this.element ).select( '.calendar' ).toArray();

    this.departure_days = $( this.element ).select( 'td.departure_day' ).toArray();

    this.visible_calendar_month_first_element = this.calendar_months[1];
    this.visible_calendar_month_last_element = this.calendar_months[3];

    this.available_calendars_size = this.calendar_months.size();
    this.back_button_element = back_button_element;
    this.forward_button_element = forward_button_element;

    this.back_button_disabled = 1;

    if (this.calendar_months.size() <= 3) {
      $(back_button_element).hide();
      $(forward_button_element).hide();
      this.forward_button_disabled = 1;
    }
    else {
      this.forward_button_disabled = 0;
      this.observeForwardButton();
    }
  },

  nextMonth: function() { return this.visible_calendar_month_first + 1; },
  lastMonth: function() { return this.visible_calendar_month_first - 1; },

  moveForward: function( event ) {
    event.stop();
    this.visible_calendar_month_first = this.nextMonth();
    this.redrawCalendar();
  },

  moveBack: function( event ) {
    event.stop();
    this.visible_calendar_month_first = this.lastMonth();
    this.redrawCalendar();
  },

  hideAllCalendars: function() {
    $( this.element ).select( '.calendar' ).each(function(s) {
      s.hide();
      s.removeClassName( 'position-1' );
      s.removeClassName( 'position-2' );
      s.removeClassName( 'position-3' );
    });
  },

  disableBackButton: function() {
    this.back_button_disabled = 1;
    $( this.back_button_element ).select('img').first().src = '/img/icons/arrow-left-inactive.gif';
    Event.stopObserving( this.back_button_element, 'click' );
  },

  disableForwardButton: function() {
    this.forward_button_disabled = 1;
    $( this.forward_button_element ).select('img').first().src = '/img/icons/arrow-right-inactive.gif';
    Event.stopObserving( this.forward_button_element, 'click' );
  },

  enableBackButton: function() {
    this.back_button_disabled = 0;
    $( this.back_button_element ).select('img').first().src = '/img/icons/arrow-left.gif';
    this.observeBackButton();
  },

  enableForwardButton: function() {
    this.forward_button_disabled = 0;
    $( this.forward_button_element ).select('img').first().src = '/img/icons/arrow-right.gif';
    this.observeForwardButton();
  },

  observeBackButton: function() {
    Event.observe( this.back_button_element, 'click', this.moveBack.bindAsEventListener(this), false );
  },

  observeForwardButton: function() {
    Event.observe( this.forward_button_element, 'click', this.moveForward.bindAsEventListener(this), false );
  },

  handleDepartureClick: function( event ) {
    var element = Event.element( event );
    var departure = Event.element( event ).parentNode.select( 'input' ).first().value;
    new Ajax.Request('select_departure_for_calendar?departure_id=' + departure, {asynchronous:true, evalScripts:true} );
    return false;
  },

  redrawCalendar: function() {
    this.hideAllCalendars();

    var visible_range = [];
    visible_range[0] = this.visible_calendar_month_first;

    this.calendar_months[ ( visible_range[0] ) ].addClassName('position-1');
    this.calendar_months[ ( visible_range[0] ) ].show();

    for ( i = 1; i < this.visible_calendar_size; i++ ) {
      visible_range[i] =  ( visible_range[0] + i );
      this.calendar_months[ visible_range[i] ].addClassName('position-' + ( i + 1 ) );
      this.calendar_months[ visible_range[i] ].show();
      this.visible_calendar_month_last = visible_range[i];
    }

    this.visible_calendar_month_first_element = this.calendar_months[ visible_range[0] ];
    this.visible_calendar_month_last_element = this.calendar_months[ this.visible_calendar_month_last ];

    if ( this.visible_calendar_month_first_element == this.calendar_months.first() ) {
      this.disableBackButton();
    }   else {
        if ( this.back_button_disabled == 1 ) {
          this.enableBackButton();
        }
      }

    if ( this.visible_calendar_month_last_element == this.calendar_months.last() ) {
      this.disableForwardButton();
    } else {
      if ( this.forward_button_disabled == 1 ) {
        this.enableForwardButton();
      }
    }
  }
}

var ElementSlider = Class.create();

ElementSlider.prototype = {
  initialize: function( container_element, item_element, back_button_element, forward_button_element ) {
     this.container_element = container_element;

    this.items = $( this.container_element ).select( item_element ).toArray();

    this.back_button_element = back_button_element;
    this.forward_button_element = forward_button_element;

    this.current_item_index = 0;

    this.observeBackButton();
    this.observeForwardButton();
  },

  observeBackButton: function() {
    Event.observe( this.back_button_element, 'click', this.moveBack.bindAsEventListener(this), false );
  },

  observeForwardButton: function() {
    Event.observe( this.forward_button_element, 'click', this.moveForward.bindAsEventListener(this), false );
  },

  moveForward: function() {
    if ( this.items[this.current_item_index] == this.items.last() ) {
      this.current_item_index = 0;
    } else {
      this.current_item_index += 1;
    }
    this.resetItems();
  },

  moveBack: function() {
    // if first, set to last
    if ( this.items[this.current_item_index] == this.items.first() ) {
      this.current_item_index = ( this.items.size() - 1 );
    } else {
      this.current_item_index = ( this.current_item_index - 1 );
    }
    this.resetItems();
  },

  resetItems: function() {
    this.items.each( function( item ) { $( item ).hide(); })
    this.items[this.current_item_index].show();
  }
}


function DepartureClueTipItineraryRequest( departure ) {
  $( 'cluetip' ).hide();
  new Ajax.Request('select_departure_for_calendar?departure_id=' + departure, {asynchronous:true, evalScripts:true} );

}

function addDays(myDate,days) {
  return new Date(myDate.getTime() + days*24*60*60*1000);
}

var formatDate = function (formatDate, formatString) {
  if(formatDate instanceof Date) {
    var months = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
    var yyyy = formatDate.getFullYear();
    var yy = yyyy.toString().substring(2);
    var m = formatDate.getMonth();
    var mm = m < 10 ? "0" + m : m;
    var mmm = months[m];
    var d = formatDate.getDate();
    var dd = d < 10 ? "0" + d : d;

    var h = formatDate.getHours();
    var hh = h < 10 ? "0" + h : h;
    var n = formatDate.getMinutes();
    var nn = n < 10 ? "0" + n : n;
    var s = formatDate.getSeconds();
    var ss = s < 10 ? "0" + s : s;

    formatString = formatString.replace(/yyyy/i, yyyy);
    formatString = formatString.replace(/yy/i, yy);
    formatString = formatString.replace(/mmm/i, mmm);
    formatString = formatString.replace(/mm/i, mm);
    //formatString = formatString.replace(/m/i, m);
    formatString = formatString.replace(/dd/i, dd);
    //formatString = formatString.replace(/d/i, d);
    formatString = formatString.replace(/hh/i, hh);
    formatString = formatString.replace(/h/i, h);
    formatString = formatString.replace(/nn/i, nn);
    //formatString = formatString.replace(/n/i, n);
    //formatString = formatString.replace(/ss/i, ss);
    //formatString = formatString.replace(/s/i, s);
    return formatString;
  } else {
    return "";
  }
}

// **************** General Utils **************************

var ajax = {
    request_active: false,
    request_queue: [],

    queue_post: function queue_post(action, data, response_func, type) {
        if (this.request_active) {
            this.request_queue.push(arguments);
        }
        else {
            this.do_post(arguments);
        }
    },

    do_post: function do_post(args) {
        this.request_active = true;

        function response_handler(response) {
            ajax.request_active = false;
            args[2](response);
            if (ajax.request_queue.length > 0) {
                do_post(ajax.request_queue.shift());
            }
        }

        jQuery.post(args[0], args[1], response_handler, args[3]);
    }
}

function cache_images() {
    for (var i = 0; i<arguments.length; i++) {
        var img = new Image();
        img.src = arguments[i];
    }
}

function changeSubmitOnAjaxRequest(state, submitID) {
  var button = jQuery('#' + submitID);

  if (state == 'request') {
    button.fadeOut('fast', function() {
      jQuery('<img class="x_ajax_submit_progress submit" src="/img/spinner-results.gif" alt="Processing" />').insertAfter(button);
    });
  }
  else {
    jQuery('.x_ajax_submit_progress').remove();
    button.fadeIn('fast');
  }
}