(function($) {


  // TODO: need to remove the region ui, since the page will reload for each region.
  //  ie,
  //     /trip_finder/europe will load trip finder for europe
  //      /trip_finder/new_zealand will load trip finder for new zealand

  // public methods

  jQuery.fn.trip_finder = function( options ) {

    var opts = $.extend({}, $.fn.trip_finder.defaults, options);

    return this.each( function() {
      $this = $(this);
      $this.options = opts;

      // attributes
      $this.current_region_id = opts['region_id'];
      $this.current_region_name = options['region'];
      $this.selling_company_id = opts['selling_company_id'];
      $this.current_page = 1;
      $this.results_per_page = parseInt( opts["results_per_page"], 10 );
      $this.result_count = parseInt( opts['result_count'], 10 );


      // filters
      $this.valid_entries = opts['valid_entries'];
      $this.filter = {};
      $this.filter_nav = $( opts['filter_nav_element'] );

      // sort defaults
      $this.sort_by = $this.options['default_sort_by'];
      $this.sort_direction = $this.options['default_sort_direction'];
      $this.sort_drop_down = $( '.sort select' );

      $this.start = function() {
        $this.find('input[type="checkbox"]').each( function(index, checkbox) {
          $(checkbox).get(0).checked = false; // on page refresh remove any checkboxes that were checked.
          if ( $(checkbox).hasClass('select_all') ) {
            $(checkbox).click( $this.handleSelectAllClicked );
          } else {
            $(checkbox).click( $this.handleFilterClicked );
          }
        });
        $this.setupFilterNav();
        $this.setupFilters();
        $this.updatePagination();
        $this.setupSortOptions();
      };

      $this.handleFilterClicked = function(e) {
        $this.updateFilter( this );
      };

      $this.handleSelectAllClicked = function(e) {
        var filter = $this.currentFilterFromCheckbox( this );
        $(this).parents('ul').find('input[type=checkbox]').each( function(index, checkbox) {
          if ( !$(checkbox).hasClass('select_all') ) {
            if ( !checkbox.checked ) {
              $this.addFilter( filter, checkbox );
            }
          }
        });
        $this.sendRequest(filter);
      };

      $this.setupFilterNav = function() {
        $('.tag_filter .picked').parents("ul").append("<li class=\"default\">" + $this.options['default_filter_text'] + "</li>");
        $('.tag_filter .picked').hide();
      };

      $this.setupFilters = function() {
        var filter_names = $this.getFilterNames();
        jQuery.each( filter_names, function( index, filter_name ) {
          $this.filter["'" + filter_name + "'"] = [];
          $this.updateFilterOptions( filter_name );
        });
      };

      $this.getFilterNames = function() {
        return [ $this.options['tour_lengths_class_name'], $this.options['tour_types_class_name'], $this.options['tour_filters_class_name'] ];
      };

      $this.getValidEntriesFor = function( filter_name ) {
        return eval( "$this.valid_entries." + filter_name + "_ids"  );
      };

      $this.hasValidEntryFor = function( filter_name, id ) {
        var valid_ids = $this.getValidEntriesFor( filter_name );
        var result = false;
        jQuery.each( valid_ids, function( index, valid_id ) {
          if ( valid_id == id ) {
            result = true;
            return;
          }
        });
        return result;
      };

      // responsible for updating the options based on the valid entries.
      $this.updateFilterOptions = function( filter_name ) {
        debug("we are updating options for: " + filter_name );
        if ( filter_name == $this.options['tour_lengths_class_name'] ) {
          var tour_types = $this.getSelectedCheckboxesForFilter( $this.options['tour_types_class_name'] );
          var tour_filters = $this.getSelectedCheckboxesForFilter( $this.options['tour_filters_class_name'] );
          debug( "we found: " + tour_types.size() + " tour types and " + tour_filters.size() + " tour filters");
          if ( tour_types.size() == 0 && tour_filters.size() == 0 ) {
            $('.' + filter_name + " :checkbox:not(.select_all)").each( function(index, checkbox){
              $this.enableFilter( checkbox );
            });
          } else {
            $this.enableOrDisableCheckboxesForFilter( filter_name );
          }
        } else {
          $this.enableOrDisableCheckboxesForFilter ( filter_name );
        }
      };

      $this.enableOrDisableCheckboxesForFilter = function( filter_name ) {
        $('.' + filter_name + ' :checkbox:not(.select_all)').each( function( index, checkbox ) {
          var checkbox_id = checkbox.id.match(/[0-9]+/)[0];
          if( $this.hasValidEntryFor( filter_name, checkbox_id ) ) {
            $this.enableFilter( checkbox );
          } else {
            $this.disableFilter( checkbox );
          }
        });
      };

      $this.getSelectedCheckboxesForFilter = function( filter_name ) {
        return $('.' + filter_name + ' :checkbox:not(.select_all):checked');
      };

      $this.enableFilter = function( checkbox ) {
        checkbox.disabled = false;
        $(checkbox).parents('li').removeClass('disabled');
      };

      $this.disableFilter = function( checkbox ) {
        checkbox.disabled = true;
        $(checkbox).parents('li').addClass('disabled');
      };

      // responsible triggering updates for all the other
      // filters.
      $this.updateOtherFilters = function( filter_name ) {
        var filter_names = $this.getFilterNames();
        var filter_names_to_update = [];
        jQuery.each( filter_names, function(index, name ) {
          if ( name != filter_name ) {
            filter_names_to_update.push( name );
          }
        });
        jQuery.each( filter_names_to_update, function( index, name ) {
          $this.updateFilterOptions( name );
        });
      };

      // responsible for setting up the sort options, a drop down widget.
      $this.setupSortOptions = function() {
        debug( "we will be adding to: " + $this.sort_drop_down );
        jQuery.each( $.fn.trip_finder.sort_options, function(index, option) {
          $this.sort_drop_down.append( $this.createSortOption( option ) );
        });
        $this.sort_drop_down.change( $this.handleSortChange );
      };

      $this.createSortOption = function( option ) {
        return "<option value=\"" + option.name + "\">" + option.name + "</option>";
      };

      $this.handleSortChange = function(e) {
        $this.updateSortWithSortOption( $this.getSortOptionByName( this.value ) );
        $(this).trigger('blur');
      };

      $this.getSortOptionByName = function( name ) {
        var found_option = null;
        jQuery.each( $.fn.trip_finder.sort_options, function( index, option ) {
          debug(" option.name = '" + option.name + "' = '" + name + "'");
          if ( option.name == name ) {
            found_option = option;
          }
        });
        return found_option;
      };

      $this.updateSortWithSortOption = function( sort_option ) {
        if ( sort_option ) {
          $this.sort_by = sort_option.sort_by;
          $this.sort_direction = sort_option.sort_direction;
          $this.current_page = 1; //reset current page
          $this.sendRequest();
        }
      };

      $this.updatePagination = function() {
        var content = "";
        if ( $this.result_count > $this.results_per_page ) {
          debug("we have " + $this.result_count + " for " + $this.results_per_page );
          var start_page      = (($this.current_page - 1) * $this.results_per_page) + 1;
            var end_page        = (start_page - 1) + $this.results_per_page;
          var total_pages   = parseInt( ($this.result_count / $this.results_per_page), 10 );
          if ( ($this.result_count % this.results_per_page) > 0 ) {
            total_pages     = total_pages + 1;
          }

          content = content.concat("<ul>");

          if ( $this.current_page > 1 ) {
            content = content.concat( "<li><a href=\"#\" class=\"previous_page prev\"><< prev</a></li>");
          } else {
            content = content.concat("<li class=\"disabled\"><< prev</a>");
          }

          for( var i = 1; i <= total_pages; i++ ) {
            if ( i == $this.current_page ) {
              content = content.concat( "<li class=\"current\">" + i + "</li>" );
            } else {
              content = content.concat("<li><a href=\"#\" class=\"page_links\">" + i + "</a></li>");
            }
          }

          if ( total_pages > $this.current_page ) {
            content = content.concat( "<li><a href=\"#\" class=\"next_page next\">next >></a></li>");
          } else {
            content = content.concat("<li class=\"disabled\">next >></li>");
          }

          content = content.concat("</ul>");
          $this.find('.pagination').html( content );

          $this.find('a.previous_page').click( $this.showPreviousPage );
          $this.find('a.next_page').click( $this.showNextPage );
          $this.find('.pagination .page_links').click( $this.showPage );

        } else {
          $this.find('.pagination').html(""); // we don't have any pages to display.
        }
      };

      $this.showPreviousPage = function() {
        $this.current_page = $this.current_page - 1;
        $this.sendRequest();
        return false;
      };

      $this.showNextPage = function() {
        $this.current_page = $this.current_page + 1;
        $this.sendRequest();
        return false;
      };

      $this.showPage = function() {
        $this.current_page = parseInt( $(this).text(), 10 );
        $this.sendRequest();
        return false;
      };

      // responsible for updating the overall filter with the given checkbox.
      // if the checkbox is clicked then the filter is added, otherwise the
      // filter is removed.
      $this.updateFilter = function( checkbox ) {
        var filter = $this.currentFilterFromCheckbox( checkbox );
        if ( checkbox.checked ) {
          // checkbox was just checked
          $this.addFilter( filter, checkbox );
        } else {
          // checkbox was just unchecked
          $this.removeFilter( filter, checkbox );
          $this.removeFromFilterNavigation( checkbox );
        }
        $this.current_page = 1; // reset back to the current page. TODO: reset sorting prefs too.
        $this.sendRequest(filter);
      };

      $this.sendRequest = function(filter) {
        var pathname = window.location.pathname;

        if (pathname.indexOf("agents") > 0){
          var url_path = '/agents/trip_finder/'
        } else {
          var url_path = '/trip_finder/'
        }

        debug( "we will be sending: " + $this.filterToParams() );
        $.ajax( {
          type: 'POST',
          dataType: 'json',
          data: $this.filterToParams() + "&page=" + $this.current_page,
          url: url_path + $this.current_region_name + '/filter',
          success: function(data) {
            $this.updateUIWithResults( data );
            debug("data valid options", data.valid_options);
            if ( filter ) {
              $this.updateOtherFilters( filter );
            }
          },
          error: function( request, status, exception ) {
            debug( 'we have a problem ' + status );
          }
        });
      };

      $this.updateUIWithResults = function( data ) {
        $this.result_count = parseInt( data.result_count, 10 );
        $.fn.trip_finder.updateResultCount( data.result_count );
        $this.updatePagination();

        var content = "";
        var results = data.results;
        if ( results ) {

          $this.valid_entries = data.valid_options;

          jQuery.each( results, function(index, value) {
            content = content.concat( $.fn.trip_finder.createResultEntry( index, value ) );
          });
          $.fn.trip_finder.updateResultsWithContent( content );

          // add lightbox for all lbOn classes
          $('.lbOn').each( function(index, element)  {
            new lightbox( element );
          });
        } else {
          // we have no results
          $.fn.trip_finder.updateResultsWithContent("<li>No tours were found.</li>");
        }
      };

      // responsible for adding a filter based on the current checkbox and its parent list item.
      $this.addFilter = function( filter, checkbox ) {
        var checkbox_id = checkbox.id.match(/[0-9]+/)[0];  // we just want to record the id
        checkbox.checked = true;
        $this.addToFilters( filter, checkbox_id );
        $this.addToFilterNavigation( filter, checkbox );
      };

      $this.addToFilters = function( filter, checkbox_id ) {
        $this.filter[filter] = $this.filter[filter] || [];
        $this.filter[filter].push( checkbox_id );
      };

      $this.addToFilterNavigation = function( filter, checkbox ) {
        var checkbox_label = $(checkbox).parent().text();
        var list_element = "<li class=\"last\"><a href=\"#\">" + checkbox_label + "</a></li>";
        $this.filter_nav.find('.default').hide();
        $this.filter_nav.find('.picked').show();
        $this.addListElementToFilterNavigation( list_element, filter, checkbox );
      };

      $this.addListElementToFilterNavigation = function( list_element, filter, checkbox ) {
        var checkbox_full_id = checkbox.id;
        $($this.filter_nav).children('.last').removeClass('last');
        $($this.filter_nav).append( list_element );
        $($this.filter_nav).children('.last').click(
          function(e) {
            $this.removeFilter( filter, checkbox );
            $(this).remove();

            if ( $($this.filter_nav).children(':last').hasClass( 'default' ) ||  $($this.filter_nav).children(':last').hasClass( 'default' ) ) {
              $($this.filter_nav).find('.picked').hide();
              $($this.filter_nav).find('.default').show();
            } else {
              $($this.filter_nav).children(':last').addClass('last');
            }
            $this.sendRequest(filter);
            return false;
          }
        );
      };

      // responsible for removing a filter based on the current checkbox and its parent list item.
      $this.removeFilter = function( filter, checkbox ) {
        var checkbox_id = checkbox.id.match(/[0-9]+/)[0];
        checkbox.checked = false;
        $(checkbox).parents('ul').find(".select_all").get(0).checked = false;
        if ($this.filter[filter]) {
          $this.filter[filter] = jQuery.map( $this.filter[filter], function(n) { return ( n != checkbox_id ? n : null ); } );
        }
      };

      $this.removeFromFilterNavigation = function( checkbox ) {
        var filter_name = $(checkbox).parents('li').text();
        var filter_nav_element = $this.findFilterNavByName( filter_name );
        debug("filter_nav_element is " + filter_nav_element + " for " + filter_name );
        if ( filter_nav_element ) {
          $(filter_nav_element).remove();
          var last_element = $($this.filter_nav).children(':last').get(0);
          debug("last element is " + last_element);
          if ( !$(last_element).hasClass('picked') && !$(last_element).hasClass('default') ) {
            $(last_element).addClass('last');
          } else {
            $($this.filter_nav).find('.picked').hide();
            $($this.filter_nav).find('.default').show();
          }
        }
      };

      $this.findFilterNavByName = function( filter_name ) {
        var found_filter = null;
        $($this.filter_nav).children(':not(picked)').each( function( index, element ){
          if ( $(element).text() == filter_name ) {
            found_filter = element;
          }
        });
        return found_filter;
      };

      // finds the current filter from the checkbox.  the checkbox parent ul item class
      // name is used to determine what group of filters we are dealing with.
      $this.currentFilterFromCheckbox = function( checkbox ) {
        var parentListElement = $(checkbox).parents('ul');
        if ( parentListElement.hasClass( $this.options['tour_lengths_class_name'] ) ) {
          return $this.options['tour_lengths_param_name'];
        } else if ( parentListElement.hasClass( $this.options['tour_types_class_name'] ) ) {
          return $this.options['tour_types_param_name'];
        } else if ( parentListElement.hasClass( $this.options['tour_filters_class_name'] ) ) {
          return $this.options['tour_filters_param_name'];
        }
        return null;
      };

      $this.filterToParams = function() {
        var params = "";

        var tour_lengths_params   = $this.tourLengthsParams();
        var tour_types_params     = $this.tourTypesParams();
        var tour_filters_params    = $this.tourFiltersParams();

        params = params.concat( $this.createFilterParam( $this.options['tour_lengths_param_name'], tour_lengths_params ) );
        params = params.concat( $this.createFilterParam( $this.options['tour_types_param_name'], tour_types_params) );
        params = params.concat( $this.createFilterParam( $this.options['tour_filters_param_name'], tour_filters_params ) );
        params = params.concat( $this.createFilterParam( $this.options['sort_by_param_name'], $this.sort_by) );
        params = params.concat( $this.createFilterParam( $this.options['sort_direction_param_name'], $this.sort_direction) );
        return params;
      };

      $this.createFilterParam = function( sub_param, value )  {
        if ( value.length > 0 ) {
          return $this.options['filter_param_name'].concat("[").concat(sub_param).concat("]=").concat( value ).concat("&");
        }
        return "";
      };

      $this.tourLengthsParams = function() {
        return $this.filterParamsFor( $this.options['tour_lengths_param_name'] );
      };

      $this.tourTypesParams = function() {
        return $this.filterParamsFor( $this.options['tour_types_param_name'] );
      };

      $this.tourFiltersParams = function() {
        return $this.filterParamsFor( $this.options['tour_filters_param_name'] );
      };

      $this.filterParamsFor = function( filter_name ) {
        var params = "";
        var current_filter = $this.filter[filter_name];
        if ( current_filter ) {
          params = params.concat( current_filter.join(",") );
        }
        return params;
      };

      // let's get this party started.
      $this.start();

    });
  };


  $.fn.trip_finder.defaults = {
    debug:                       false,
    tour_lengths_class_name:     'tour_lengths',
    tour_lengths_param_name:     'tour_lengths',  // this is the parameter that gets sent for the tour lengths fitler info
    tour_types_class_name:       'tour_types',
    tour_types_param_name:       'tour_types',    // this is the parameter that gets sent for the tour types filter info
    tour_filters_class_name:     'tour_filters',
    tour_filters_param_name:     'tour_filters',  // this is the parameter that gets sent for tour filters filter info
    filter_param_name:           'filter',        // this is the name of the parameter that gets sent with all the filter info (top level param)
    filter_nav_element:          '.tag_filter ul',
    filter_nav_picked_class_name:   'picked',
    sort_by_param_name:        'sort_by',
    sort_direction_param_name:      'sort_direction',
    default_sort_by:                'name',
    default_sort_direction:         'asc',
    default_filter_text:            "You can narrow your trip results by using the filtering tool on the left."
  };

  $.fn.trip_finder.sort_options = [
    {name: 'Name', sort_by: 'name', sort_direction: 'asc'},
    {name: 'Price: Lowest To Highest', sort_by: 'price', sort_direction: 'asc' },
    {name: 'Price: Highest To Lowest', sort_by: 'price', sort_direction: 'desc' },
    {name: 'Length: Longest To Shortest', sort_by: 'length', sort_direction: 'desc' },
    {name: 'Length: Shortest To Longest', sort_by: 'length', sort_direction: 'asc' }
  ];


  // responsible for updating the trip results header, with the new result count.
  $.fn.trip_finder.updateResultCount = function( count ) {
    $('.content h2').replaceWith("<h2>Trip Results (" + count + ")</h2>");
  };

  $.fn.trip_finder.updateResultsWithContent = function( content ) {
    $('.content .trip-results').html( content );
    window.location.hash='#top';
  };

  // responsible for creating a new result entry.
  $.fn.trip_finder.createResultEntry = function( index, value ) {
    var pathname = window.location.pathname;
    var url = value.tour_url;
    var save_trip_url = url.concat("/add_to_list");
    var send_to_friend_url = url.concat("/send_to_friend");
    var departure_url = "/agents" + url.concat("/departures");
    var tour_departures_url = url.concat("/departures");
    var tour_type = value.tour_type || '';
    var content = "";


    //  rest of world doesn't have a tour type, so not show the table row
    // TODO: refactor... my (robby) JS is rusty
    if (pathname.indexOf("agents") > 0){
      content = "<li class=\"group\"><table class=\"data\"><tr><th>Length:</th><td>" + value.length_in_days + "</td></tr><tr><th>Price From:</th><td>" + value.tour_price + "</td></tr><tr><th>Experience:</th><td>" + tour_type + "</td></tr><tr class=\"last\"><td colspan=\"2\"><ul class=\"subnav\"><li class=\"last\"><a href=\"" + departure_url + "\" class=\"lbOn\">View Departures</a></li></ul></td></tr></table><h3>" + image_link_for_tour( value ) + "</h3><div class=\"info\"><p class=\"desc\"><strong>Covering:</strong> " + value.tour_blurb + "</p></div></li>";
    } else {
      content = "<li class=\"group\">";
      content += "<div class=\"details\">";
      content += "<dl class=\"pattern_tour_detail\">";
      if (value.operational_region == 'Europe') {
        content += "<dt class=\"experience\">Experience<dt><dd class=\"experience\">" + tour_type + "</dd>";
      }
      content += "<dt class=\"length\">Length</dt><dd class=\"length\">" + value.length_in_days + "</dd>";
      var formatted_price = (value.departure_has_extra_cost == true) ? value.total_price + '*' : value.tour_price;
      content += "<dt class=\"price\">Total Price From</dt><dd class=\"price\">" + formatted_price + " <span class=\"per_person\">per person</span></dd></dl>";
      content += "<a href=\"" + tour_departures_url + "\">Check Availability</a>";
      if (value.departure_has_extra_cost == true) {
        content += "<p>*Tour (" + value.tour_price + ") + " + value.departure_extra_cost_type + " (" + value.departure_extra_cost + ")</p>";
      }
      content += "</div>"
      content += "<h3>" + image_link_for_tour( value ) + "</h3>"
      content += "<div class=\"info\"><p class=\"desc\"><strong>Covering:</strong> " + value.tour_blurb + "</p>"
      content += "</div>"
      content += "<ul class=\"actions\">"
      content += "<li><a href=\"" + save_trip_url + "\">Save Trip</a></li>"
      content += "<li><a href=\"" + send_to_friend_url + "\" class=\"lbOn\">Email</a></li>"
      content += "</ul>"
      content += "</li>";
    }
    return content;
  };

  function image_link_for_tour( value ) {
    var pathname = window.location.pathname;
    var url = value.tour_url;

    if (pathname.indexOf("agents") > 0) {
      url = "/agents"  + url;
    }

    var img = value.tour_image;
    var name = value.tour_name;
    var content = "<a href=\"" + url + "\"><img class=\"thumb\" width=\"180\" height=\"82\" src=\"" + img + "\" alt=\"" + name + "\"/></a><a href=\"" + url + "\">" + name + "</a>";
    return content;
  };


  //   displays a debug message in the console, if debug is set to true
  //   in the $.fn.trip_finder.defaults.
  function debug(message) {
    if ( $.fn.trip_finder.defaults.debug ) {
      if( arguments[1] ) {
        message = message.concat(" arguments: [");
        if( arguments[1].constructor.name == "String" ) {
          message = message.concat( arguments[1] );
        } else if( arguments[1].constructor.name == "Object" ) {
          for( var i in arguments[1] ) {
            value = arguments[1][i];
            if ( value.constructor.name == "String" ) {
              message = message.concat( i + ": '" + arguments[1][i] + "', ");
            } else {
              message = message.concat( i + ": " + arguments[1][i] + ", ");
            }
          }
          message = message.substring(0, message.lastIndexOf(',') );
        } else {
          message = message.concat( arguments[1] );
        }
        message = message.concat("]");
      }

      if ( window.console ) {
        window.console.log( message );
      } else {
        alert( message );
      }
    }
  }


})(jQuery);
