/**
 * @fileoverview Embeddable map logic using v3.0 of the Maps API.
 * @author e.bidelman@google.com (Eric Bidelman)
 */

var DEFAULT_ZOOM = 10;
var MAX_PROXIMITY_SEARCH_MILES = 35;
var MAX_SEARCH_RESULTS = 26;
var QUERY_PREFIX = 'Find a flu vaccine near';
var ADDRESS_INPUT_MSG = 'U.S. city and state or zip';
//var OOSTOCK_MSG = 'Temporarily out of stock';

var ENTER_KEYCODE = 13;

var MARKER_X_OFFSET = 25;
var MARKER_Y_OFFSET = 38;

var FLU_SHOT_TYPE = {
  'seasonal': 0,
  'h1n1': 1,
  'both': 2
};

/* Add custom helpers to the Maps API ======================================= */

google.maps.Map.prototype.openInfoWindow = null;

google.maps.Map.prototype.markers = new Array();

google.maps.Map.prototype.addMarker = function(marker) {
  this.markers[this.markers.length] = marker;
  return this.markers.length - 1;
};

google.maps.Map.prototype.getMarker = function(lat, lng) {
  for (var i = 0, marker; marker = this.markers[i]; ++i) {
    var pos = marker.getPosition();
    if (pos.lat() == lat && pos.lng() == lng) {
      return marker;
    }
  }
  return null;
};

google.maps.Map.prototype.getMarkers = function() {
  return this.markers;
};

google.maps.Map.prototype.clearMarkers = function() {
  if(this.openInfoWindow) {
    this.openInfoWindow.close();
  }
  for (var i = 0, marker; marker = this.markers[i]; ++i) {
    this.markers[i].setMap(null);
  }
  $('#clinic_list').html('').hide();
};

/* ========================================================================== */

// Setup event handlers once DOM is finished loading.
$(document).ready(function() {
  $('#address')
  .val(ADDRESS_INPUT_MSG)
  .focus(function() {
    $(this).val('').addClass('on');
  })
  .blur(function() {
    if (!$(this).val()) {
      $(this).val(ADDRESS_INPUT_MSG);
    }
    $(this).removeClass('on');
  })
  .keyup(function(e) {
    if(e.keyCode == ENTER_KEYCODE) {
      $('#geocode_button').click();
    }
  });
});

function FluSearch() {
  this.map = null;
  this.geocoder = null;
};

FluSearch.prototype.showInfoWindow = function(index) {
  //google.maps.event.trigger(this.map.getMarker(index), 'click');
  google.maps.event.trigger(this.map.getMarkers()[index], 'click');
};

FluSearch.prototype.createMarker = function(obj, infoWin, i) {
  var latlng = new google.maps.LatLng(obj.LAT, obj.LNG);
  var marker;

  if (obj.icon) {
    marker = new google.maps.Marker({
      position: latlng,
      map: this.map,
      title: obj.NAME,
      icon: obj.icon,
      zIndex: i
    });
  } else {
    marker = new google.maps.Marker({
      position: latlng,
      map: this.map,
      title: obj.NAME,
      zIndex: i
    });
  }

  // Setup click handler for marker
  var me = this;
  google.maps.event.addListener(marker, 'click', function() {
    if (me.map.openInfoWindow) {
      me.map.openInfoWindow.close();
    }
    me.map.openInfoWindow = new google.maps.InfoWindow({content: infoWin});
    me.map.openInfoWindow.open(me.map, marker);
  });

  return marker;
};

/**
 * Builds the HTML for a marker's info window.
 * @param {object} An object containing the data about this marker.
 * @return {string} The HTML to fill the info window with.
 */
FluSearch.prototype.constructMarkerInfoWindow = function(result) {
  //var fullAddress = [result.STREET, result.TOWN, result.STATE].join(', ');

  var infoWinHtml = [
      '<div style="overflow-y:auto;height:203px;padding-right:15px;width:320px;">',
      '<h3 style="margin:0;">', result.NAME, '</h3>',
      '<div>', result.ADDRESS, '</div>',
      '<div>', this.formatPhoneString(result.PHONE), '</div>'];

  if (result.WEBSITE) {
    infoWinHtml.push('<div><a href="', result.WEBSITE,
                     '" target="_new" style="color:#289328;">');
    if (result.WEBSITE.length > 100) {
      infoWinHtml.push('More information');
    } else {
      infoWinHtml.push(result.WEBSITE);
    }
    infoWinHtml.push('</a></div>');
  }

  infoWinHtml.push('<div style="margin-top:10px;">');
  if (result.START_DATE) {
    infoWinHtml.push(this.formatDateString(result.START_DATE), ' - ');
    //infoWinHtml.push(result.START_DATE, '-');
  } else {
    infoWinHtml.push('until ');
  }

  infoWinHtml.push(this.formatDateString(result.END_DATE), '</div>');
  //infoWinHtml.push(result.END_DATE, '</div>');

  if (result.DAYS_HOURS) {
    infoWinHtml.push('<div>', result.DAYS_HOURS, '</div>');
  }

  if (result.SEASONAL_SHOTS_STOCK && result.SEASONAL_SHOTS_COST) {
    infoWinHtml.push('<div>Seasonal flu shot charge: ',
                     result.SEASONAL_SHOTS_COST);
    if (result.SEASONAL_SHOTS_CHILDREN) {
      infoWinHtml.push(' (also offered to children)');
    }
    infoWinHtml.push('</div>');
  }

  if (result.SEASONAL_SPRAY_STOCK && result.SEASONAL_SPRAY_COST) {
   infoWinHtml.push('<div>Seasonal spray charge: ',
                    result.SEASONAL_SPRAY_COST);
    if (result.SEASONAL_SPRAY_CHILDREN) {
      infoWinHtml.push(' (also offered to children)');
     }
     infoWinHtml.push('</div>');
  }

  if (result.INSURANCE) {
    infoWinHtml.push('<div>Insurance accepted? ',
      result.INSURANCE ? 'Yes' : 'No', '</div>');
  }

  infoWinHtml.push('<div style="color:#666;margin-top:5px;">',
                   result.NOTES, '</div>');

  infoWinHtml.push('</div>');

  return infoWinHtml.join('');
};

FluSearch.prototype.placeAllMarkers = function(results) {
  this.map.clearMarkers();

  if (!results.length) {
    $('#clinic_list').html(
        '<h3 style="text-align:center;margin-top:1em;">No results</h3>').show();
    return;
  }

  var html = [];
  var yOffset = 0;
  for (var i = 0, result; result = results[i]; ++i) {
    var c = String.fromCharCode("A".charCodeAt(0) + i);
    var img = "http://maps.google.com/mapfiles/marker" + c + ".png";
    result.icon = new google.maps.MarkerImage(img);

    var infoWinHtml = this.constructMarkerInfoWindow(result);

    var markerIndex = this.map.addMarker(
        this.createMarker(result, infoWinHtml, MAX_SEARCH_RESULTS - i));

    // Append result to listing.
    html.push(
        '<li>',
        '<div>',
        '<img src="' + img + '" align="left">',
        '</div>',
        '<div style="margin-left:30px;">',
        '<div class="title"><a href="javascript:flusearch.showInfoWindow(',
        markerIndex, ');">', result.NAME, '</a></div>', '<div>',
        result.ADDRESS, '</div>');

    if (result.PHONE) {
      html.push('<div>', this.formatPhoneString(result.PHONE), '</div>');
    }

    html.push('<div class="hours">');

    // Display starting data for shot if it was returned to us.
    if (result.START_DATE) {
      var dateParts = result.START_DATE.split('-');
      var startDate = new Date();
      startDate.setFullYear(dateParts[0], dateParts[1] - 1, dateParts[2]);
      var today = new Date();
      if (today < startDate) {
        html.push('Starting ', this.formatDateString(result.START_DATE), ' - ');
    	//html.push('Starting ', result.START_DATE, ' - ');
      }
    }

    // Append the days of week and times the shot is offered.
    if (result.DAYS_HOURS) {
      html.push(result.DAYS_HOURS, ' ');
    }

    html.push('</div></div></li>');

    // Adjust the bg y-pos on the sprite to the next letter.
    yOffset += MARKER_Y_OFFSET;
  }

  $('#clinic_list').html('<ul class="data_listing">' + html.join('') + '</ul>').show();
};

FluSearch.prototype.formatPhoneString = function(phoneStr) {
  if (!phoneStr) {
    return '';
  }
  // Formats a string of numbers into a readable phone number: (xxx) xxx-xxx
  return phoneStr.replace(/\(?([0-9]{3})[\)-]?([0-9]{3})-?([0-9]{4})(.*)?/,
                          '($1) $2-$3$4');
};

FluSearch.prototype.formatTimeString = function(timeStr) {
  var time = timeStr.split(':');

  var d = new Date();
  d.setHours(parseInt(time[0], 10), parseInt(time[1], 10));

  var hours = d.getHours();
  var minStr = d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes();
  if (hours > 12) {
    return [hours - 12, ':', minStr, ' PM'].join('');
  } else {
    var amPm = ' AM';
    if (hours == 12) {
      amPm = ' PM';
    }
    return [hours, ':', minStr, amPm].join('');
  }
};

FluSearch.prototype.formatDateString = function(dateStr) {
  if (dateStr == null || dateStr == '') {
    return '';
  }
  var parts = dateStr.split('-');
  return [parts[1], parts[2], parts[0].substring(2)].join('/');
};

/**
 * Util for extracting a lat,lng pair from the URL passed in from the user's
 * onebox query. The lat,lng is passed in the URL as a hash (#lat=x,lng=y).
 * @param {string} The browser's curent URL.
 * @return {object} A JSON ojbect containg the lat,lng pair.
 */
FluSearch.prototype.getLatLngFromUrl = function(url) {
  var parts = url.split('#');
  if (parts.length <= 1) {
    return null;
  }

  var latlng = parts[1].split(',');
  var lat;
  var lng;
  if (latlng[0].indexOf('lat') > -1) {
    lat = latlng[0];
    lng = latlng[1];
  } else {
    lat = latlng[1];
    lng = latlng[0];
  }

  return {
    lat: parseFloat(lat.split('=')[1]),
    lng: parseFloat(lng.split('=')[1])
  };
};

/**
 * Util for extracting an address from the URL passed in from the user's
 * onebox query. The full address is passed in the URL as a hash (#address)
 * and is double url encoded. This method twice escapes that value, and returns
 * the result.
 * @param {string} The browser's current URL.
 * @return {string} The user's query address.
 */
FluSearch.prototype.getAddressQueryFromUrl = function(url) {
  url = decodeURIComponent(url);

  var parts = url.split('?');
  if (parts.length <= 1) {
    return null;
  }

  var addressQuery = decodeURIComponent(parts[1]).split('=')[1];
  if (addressQuery.indexOf(QUERY_PREFIX) > -1) {
    addressQuery = addressQuery.substring(QUERY_PREFIX.length);
  }

  return $.trim(addressQuery);
};

FluSearch.prototype.doSearch = function(locationObj) {
  $('#loading').show();

  var queryParams = {};
  //queryParams['max-results'] = $('#max-results').val() || MAX_SEARCH_RESULTS;
  //queryParams['max-distance'] =
  //    $('#max-distance').val() || MAX_PROXIMITY_SEARCH_MILES;
  //queryParams['address'] = encodeURIComponent(locationObj.address);
  //queryParams['embed'] = 'true';

  if (locationObj.bounds) {
    queryParams['north'] = locationObj.bounds.getNorthEast().lat();
    queryParams['east'] = locationObj.bounds.getNorthEast().lng();
    queryParams['south'] = locationObj.bounds.getSouthWest().lat();
    queryParams['west'] = locationObj.bounds.getSouthWest().lng();
  } else {
    queryParams['LAT'] = locationObj.center.lat();
    queryParams['LNG'] = locationObj.center.lng();
  }

  // Use the flushot-finder map service, via JSONP, if the user is accessing
  // www.google.org.
  var serviceUrl = '/map?json';
  var jsonType = 'json'
  if (location.host == 'www.google.org') {
    serviceUrl = 'http://flushot-finder.appspot.com' + serviceUrl;
    jsonType = 'jsonp';
  }

  var me = this;
  $.ajax({
    url: serviceUrl,
    type: 'GET',
    data: queryParams,
    dataType: jsonType,
    error: function(xhr, textStatus) {
      $('#change_address input').removeAttr('disabled');
      $('#loading').hide();
    },
    success: function(response) {
      me.doSearchSuccess(response, locationObj, me);
    }
  });
};

FluSearch.prototype.doSearchSuccess = function(results, locationObj, me) {
  $('#change_address input').removeAttr('disabled');

  me.placeAllMarkers(results);

  // Create bounding box containing all clinic markers
  var newBounds = new google.maps.LatLngBounds();
  for (var i = 0, result; result = results[i]; ++i) {
    var latlng = new google.maps.LatLng(
        parseFloat(result.LAT), parseFloat(result.LNG));
    newBounds.extend(latlng);
  }

  // Recenter map and zoom to a level where all results are visible
  if (results.length) {
    me.map.fitBounds(newBounds);
  }

  $('#address_info').show();
  $('#address_heading_msg').html('<strong>flu vaccines</strong> near ');
  $('#change_address').html($('#address').val());

  $('#address').blur();
  $('#address').removeAttr('disabled');
  $('#loading').hide();
};

FluSearch.prototype.geoCodeAndSearch = function() {
  var jAddress = $('#address');
  var address = jAddress.val();

  jAddress.val(address).attr('disabled', 'disabled');

  /*$('#view_in_maps_link').get(0).href =
      'http://maps.google.com/maps/mpl?moduleurl=' +
      'http://maps.google.com/mapfiles/mapplets/flushot/flushot.xml' +
      '%23address=' + encodeURIComponent(encodeURIComponent(address));*/

  this.map.clearMarkers();

  $('#loading').show();
  $('#no_results_help').hide();

  var me = this;
  this.geocoder.geocode({'address': jAddress.val()}, function(results, status) {
    // Helper to deal with a failed gecoding.
    var geocodingFailed = function(msg) {
      $('#address_heading_msg').html(msg);
      $('#loading').hide();
      $('#no_results_help').show();
      jAddress.val(ADDRESS_INPUT_MSG).blur().removeAttr('disabled');
    };

    if (status == google.maps.GeocoderStatus.OK) {
      var result = results[0];

      // Proximity search
      me.doSearch({center: result.geometry.location,
                   address: $('#address').val()});

      /*// Bounding box search
      var bounds = new google.maps.LatLngBounds(
          result.geometry.bounds.getSouthWest(),
          result.geometry.bounds.getNorthEast());
      me.doSearch({center: result.geometry.location, bounds: bounds,
                   address: $('#address').val()});*/
    } else {
      geocodingFailed('Could not find address.');
    }
  });
};

