/* Copyright 2009 WeatherBill Inc. */
if (!wb) throw new Error("required module wb not loaded!");
wb.quotelet = wb.quotelet || {};

(function($){
  var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

  function trimTrailingPound(untrimmed){
    var s = jQuery.trim(untrimmed);
    if (s.charAt(s.length - 1) == "#") {
      return s.substring(0, s.length -1);
    }
      else {
        return s;
      }
  }

  function getMonthName(monthNumber){
    return monthNames[monthNumber];
  }

  function plot_locations_around_center(map, markerManager, markerOnClick, markerIcon, getLocationsFunction, minZoom){
    minZoom = minZoom || 8;
    markerIcon = markerIcon || G_DEFAULT_ICON;
    var center = map.getCenter();

    getLocationsFunction(center,
      function(locations){
        var markers = [];
        for (var i = 0; i < locations.length; i++){
          // close over this scope to preserve the location
          // (for loop doesn't close scope!)
          (function(loc){
             // instantiation actually makes this appear on the map
             var marker = new GMarker(locations[i].latLng, {icon: markerIcon});
             markers.push(marker);

             GEvent.addListener(marker, 'click',
               function() {
                 markerOnClick(marker, loc);
               }
             );
           })(locations[i]);
        }
        markerManager.clearMarkers();
        markerManager.addMarkers(markers, minZoom);
        markerManager.refresh();
      }
    );
  }

  function get_default_icon(){
    var icon = new GIcon(G_DEFAULT_ICON);
    icon.iconSize = new GSize(32, 32);
    icon.image = "http://maps.google.com/mapfiles/ms/micons/red-dot.png";
    return icon;
  }
  function set_up_location_markers(map, addressInputSelector,
                                   getLocationsFunction,
                                   minZoomForMarkers,
                                   markerIcon, selectedMarkerIconImage){
    markerIcon = markerIcon || get_default_icon();
    selectedMarkerIconImage = selectedMarkerIconImage ||
      "http://maps.google.com/mapfiles/ms/micons/blue-dot.png";

    var markerManager = new MarkerManager(map);

    function markerOnClick(marker, loc){
      reset_last_marker(marker);
      if (loc.city && loc.state){
        $(addressInputSelector).val(loc.city + ", " + loc.state);
      }
      $("#pricingId").val(loc.pricingId);
      $("#locationSelected").text(loc.name);
      $("#citySelected").text(loc.city);
      $("#stateSelected").text(loc.state);
      map.panTo(marker.getLatLng());
      marker.setImage(selectedMarkerIconImage);
    }
    var lastMarker;
    var lastMarkerImage;
    function reset_last_marker(marker){
      try {
        if (lastMarker){
          lastMarker.setImage(lastMarkerImage);
        }
      } catch (e){
        // sometimes the above fails in strange ways. that's ok, just eat the
        // error.
        if (window.console) window.console.log(e);
      }
      lastMarker = marker;
      lastMarkerImage = marker.getIcon().image;
    }

    // Plot the initial locations
    plot_locations_around_center(map, markerManager,  markerOnClick, markerIcon,
                                 getLocationsFunction, minZoomForMarkers);

  }

  function get_client_latlng(){
    try {
      // return the client's location if we can figure it out
      return new GLatLng(google.loader.ClientLocation.latitude,
                         google.loader.ClientLocation.longitude);
    } catch (e){
      // otherwise return the geographic center of the US
      return new GLatLng(39.5, -98.35);
    }
  }

  function set_up_location_picker(addressInputSelector, addressSubmitSelector,
                                  getLocationsFunction, minZoomForMarkers, markerIcon,
                                  customizeMapFunction, initialZoom){
    customizeMapFunction = customizeMapFunction || function(){};
    initialZoom = initialZoom || 10;

    var map = new GMap2(document.getElementById("locationPickerMap"));
    map.setCenter(get_client_latlng());
    map.setZoom(initialZoom);
    map.setMapType(G_NORMAL_MAP);
    map.setUIToDefault();

    set_up_location_markers(map, addressInputSelector, getLocationsFunction, minZoomForMarkers, markerIcon);

    // Perform any map customizations
    customizeMapFunction(map);

    var geocoder = new GClientGeocoder();
    // on click, first geocode, then call getLocationsCallback with the result.
    // pass a callback to getLocationsCallback to deal with the locations
    // it will get.
    $(addressSubmitSelector).click(function(){
      geocoder.getLatLng($(addressInputSelector).val(),
        function(center) {
          if (!!center) {
            map.setCenter(center);
            map.setZoom(initialZoom);
          } else {
            alert("Geocode was unsuccessful due to: " + status);
          }
        });
      }
    );

    $(addressInputSelector).keypress(
      function(e){
        // if keypress is "return"
        if (e.which == 13){
          $(addressSubmitSelector).click();
          return false;
        }
      }
    );
  }

  /*
   * Get early freeze indexes for a location between two dates.
   */
  function get_freeze_indexes(pricingId, startDate, endDate, threshold, callback){
    var indexes = [];
    var outstandingRequests = 0;
    function get_freeze_indexes_for_year(year){
      startDate.setFullYear(year);
      endDate.setFullYear(year);
      outstandingRequests++;
      function checkOutstanding(){
        outstandingRequests--;
        if (outstandingRequests <= 0) callback(indexes);
      }
      wb.data.getHistorical(pricingId, startDate, endDate, [wb.MIN_TEMP],
                            function(observationSet){
                              indexes.push({year: year, date: calculate_freeze_index(observationSet, threshold)});
                              checkOutstanding();
                            },
                            checkOutstanding);
    }
    for (var y = new Date().getFullYear() - 30; y < new Date().getFullYear(); y++){
      get_freeze_indexes_for_year(y);
    }
  }

  function calculate_freeze_index(observationSet, threshold){
    var values = observationSet.valuesByMeasurement[wb.MIN_TEMP];
    if (values){
      for (var i = 0; i < values.length; i++){
        if (values[i] <= threshold) {
          var d = wb.parseDate(observationSet.time);
          d.setDate(d.getDate() + i);
          return d;
        }
      }
    }
  }

  function format_payout_structure(payoutStructure, payoutScaler){
    payoutScaler = payoutScaler || 1;
    // this is nasty...
    var formattedStructure = [];
    var i = 0;
    var initialPayout = payoutStructure[i].payout;
    var firstDate = payoutStructure[i].date;
    while(payoutStructure[i].payout == initialPayout) {i++;}
    formattedStructure.push(
      {date: $.datepicker.formatDate("M d - ", firstDate) +
             $.datepicker.formatDate("M d", payoutStructure[i-1].date),
       payout: wb.f$((initialPayout * payoutScaler).toFixed(2))});
    for (; i < payoutStructure.length; i++){
      formattedStructure.push(
        {date: $.datepicker.formatDate("M d", payoutStructure[i].date),
         payout: wb.f$((payoutStructure[i].payout * payoutScaler).toFixed(2))});
    }
    return formattedStructure;
  }

  function calculate_declining_freeze_payout_structure(startDate, declineStart,
                                                       declineEnd, endDate,
                                                       initialPayout, endPayout){
    var payoutStructure = [];
    for (var d  = startDate; d <= declineStart; d.setDate(d.getDate() + 1)){
      payoutStructure.push({date: new Date(d), payout: initialPayout});
    }
    var payoutDeclineInterval =
      (initialPayout - endPayout) / number_of_days_between(declineStart, declineEnd);
    var payout = initialPayout;
    for (; d < declineEnd; d.setDate(d.getDate() + 1)){
      payout -= payoutDeclineInterval;
      payoutStructure.push({date: new Date(d), payout: payout});
    }
    for (; d <= endDate; d.setDate(d.getDate() + 1)){
      payoutStructure.push({date: new Date(d), payout: endPayout});
    }
    return payoutStructure;
  }

  function number_of_days_between(d1, d2){
    return Math.abs((d1 - d2) / (1000 * 60 * 60 * 24));
  }


  function set_up_pricing_form(formSelector, options){
    options = options || {};
    $('#pricingId').val(""); // clear out rmsid field on load
    // save a clone of the original pricing div
    var originalOutputDiv = $('#quoteOutput').clone();
    var validator;
    $(formSelector).submit(function(){
      validator = validator || $(formSelector).validate({
        onclick: false,
        onkeyup: false,
        onfocus: false,
        onfocusout: false
      });
      if(validator.form()){
        var resultDiv = originalOutputDiv.clone();
        $(this).ajaxSubmit({
          beforeSubmit: function(data, form, options){
            form.trigger("price", [data, form, resultDiv]);
            return true;
          },
          dataType: 'json',
          success: function(response){
            if (response.price) {
              $(formSelector).trigger("priceSuccess", [response, resultDiv]);
              $(formSelector).trigger("renderPrice", [response, resultDiv]);
            } else {
              $(formSelector).trigger("priceFailure", [response, resultDiv]);
            }
          },
          error: function (XMLHttpRequest, textStatus, errorThrown) {
            $(formSelector).trigger("priceFailure", [{msg: textStatus}, resultDiv]);
          }

        });
      }
      return false; // kill regular form submission
    });

    set_up_quote_output(formSelector);
  };


  function set_up_quote_output(formSelector){
    $(formSelector).bind("price",
      function(){
        $("#quoteHelp").hide();
        $("#quoteOutput").hide();
        $("#quoteLoading").show();
      });
    $(formSelector).bind("priceFailure",
      function(e, response){
        $('#quoteOutput').html(
          '<h1 class="err">' + response.msg || "Unknown Error Pricing" + '</h1>'
        );
        $("#quoteLoading").hide();
        $('#quoteOutput').show();
      });
    $(formSelector).bind("renderPrice",
      function(e, response, resultDiv){
        // swap in a fresh pricing div and use pure to render result
        $(resultDiv).replaceAll("#quoteOutput").
          autoRender(response,
                     {"tr.histPayouts1[class]": wb.pure.zebraAndLead,
                      "tr.histPayouts2[class]": wb.pure.zebra});
        $("#quoteLoading").hide();
        $('#quoteOutput').fadeIn("slow");
        location = "#quoteOutput";
      });
  }

  function set_up_help_dialog(helpIconId, helpId, helpCloseId){
    $(helpIconId).click(function(){$(helpId).show();});
    $(helpCloseId).click(function(){$(helpId).hide();});
  }

  function set_up_help_dialogs(helpIds){
    for (var i = 0; i < helpIds.length; i++){
      set_up_help_dialog.apply(this, helpIds[i]);
    }
  }

  $.extend(wb.quotelet, {
    getFreezeIndexes: get_freeze_indexes,
    setUpStartDatepicker: function(form){
      $("#startDate").datepicker({
        minDate: 4,
        onSelect: function(dateText, datepicker){
          form.s_dy.value = datepicker.currentDay;
          form.s_mo.value = getMonthName(datepicker.currentMonth);
          form.s_yr.value = datepicker.currentYear;
          $(this).trigger('dateSelected');
        }
      });
    },

    setUpEndDatepicker: function(form){
      $("#endDate").datepicker({
        minDate: 4,
        onSelect: function(dateText, datepicker){
          form.e_dy.value = datepicker.currentDay;
          form.e_mo.value = getMonthName(datepicker.currentMonth);
          form.e_yr.value = datepicker.currentYear;
          $(this).trigger('dateSelected');
        },
        beforeShow: function(input, instance){
          var min = $("#startDate").datepicker("getDate");
          if (min){
            min.setDate(min.getDate() + 1);
            return {minDate: min};
          }
        }
      });
    },

    parseHistoricalPayouts: function(historicPayouts, payoutScaler){
      payoutScaler = payoutScaler || 1;
      var hp = trimTrailingPound(historicPayouts).split("#");
      var payouts = [];
      for (var i = 0; i < hp.length; i++){
        var x = hp[i].split("=");
        var payout = wb.priceToFloat(x[1]) * payoutScaler;
        if (payout > 0){
          payouts.push({"year": x[0],
                        "payout": wb.f$(payout.toFixed(0))});
        }
      }
      payouts.reverse();
      return payouts;
    },

    setUpPricingForm: set_up_pricing_form,

    setUpLocationPicker: set_up_location_picker,

    setUpStandardQuotelet: function(quoteFormSelector,
                                    datepickerOptions,
                                    pricingFormOptions){
      var form = $(quoteFormSelector);
      var formEl = form[0];
      wb.quotelet.setUpStartDatepicker(formEl, datepickerOptions);
      wb.quotelet.setUpEndDatepicker(formEl, datepickerOptions);
      wb.quotelet.setUpPricingForm(quoteFormSelector, pricingFormOptions);
      return form;
    },

    setUpLocationAnalytics: function(category, locationButtonSelector,
                                     locationInputSelector){
      $(locationButtonSelector).click(function(){
        pageTracker._trackEvent(category, "Locate",
                                $(locationInputSelector).val());
      });
    },

    setUpPricingAnalytics: function(category, priceButtonSelector,
                                    pricingFormSelector){
      $(priceButtonSelector).click(function(){
        pageTracker._trackEvent(category, "Price",
                                $(pricingFormSelector).formSerialize());
      });
    },

    setUpPrintAnalytics: function(category, printButtonSelector){
      $(printButtonSelector).live("click", function(){
        pageTracker._trackEvent(category, "Print");
      });
    },

    setUpStandardQuoteletAnalytics: function(category,
                                             priceButtonSelector,
                                             pricingFormSelector,
                                             locationButtonSelector,
                                             locationInputSelector){
      wb.quotelet.setUpLocationAnalytics(category, locationButtonSelector,
                                         locationInputSelector);
      wb.quotelet.setUpPricingAnalytics(category, priceButtonSelector,
                                        pricingFormSelector);
    },

    formatPayoutStructure: format_payout_structure,
    calculateDecliningFreezePayoutStructure: calculate_declining_freeze_payout_structure,
    setUpHelpDialogs: set_up_help_dialogs
  });
})(jQuery);

/**
 * Set up jQuery plugins for syntactic sugar.
 */
jQuery.fn.standardQuotelet = function(datepickerOptions, pricingFormOptions){
  return wb.quotelet.setUpStandardQuotelet(this, datepickerOptions, pricingFormOptions);
};
jQuery.fn.locationPicker = function(addressSubmitSelector, getLocationsFunction,
                                    minZoomForMarkers, markerIcon, customizeMapFunction, initialZoom){

  return wb.quotelet.setUpLocationPicker(this, addressSubmitSelector, getLocationsFunction,
                                         minZoomForMarkers, markerIcon, customizeMapFunction, initialZoom);
};
