var Runnerroot = {
  map_manager : null,  // the map
  geocoder : null,     // the geocoder
  current_root : null, // current Root
  search_results : null, // [{name : <string>, start_lat : <float>, start_lng : <float>, distance : <float>, user_id : <int>, root_id : <int>}, ...]
  is_root_open : false,  // true if a route is currently opened
  units : "english",   // units = {english | metric}
  weight : "150.0",    // in pounds
  pace : "10.0"        // in min/mi
};

function init() {
  // initialize data structures
  Runnerroot.search_results = new Array();
  Runnerroot.current_root = new Root();

  // init saved data
  if (get_cookie("pace")) { Runnerroot.pace = get_cookie("pace"); }
  if (get_cookie("units")) { Runnerroot.units = get_cookie("units"); }
  if (get_cookie("weight")) { Runnerroot.weight = get_cookie("weight"); }
  if (get_cookie("default_address")) { document.address_form.address.value = get_cookie("default_address"); }
  if (Runnerroot.units != "english" && Runnerroot.units != "metric") { Runnerroot.units = "english"; }

  // set default unit for roots
  Root.set_units(Runnerroot.units);

  // turn everything into a dialog that needs to be one
  $("#save_dialog").dialog({autoOpen : false, modal : true, width: 500});
  $("#help_dialog").dialog({autoOpen : false, modal : true, width: 450});
  $("#register_dialog").dialog({autoOpen : false, modal : true, width: 500});
  $("#error_dialog").dialog({autoOpen : false, modal : true, 
                             buttons : {Okay : function() { $("#error_dialog").dialog("close"); }}});
  $("#message_dialog").dialog({autoOpen : false, modal : true,
			       buttons : {Okay : function() { $("#message_dialog").dialog("close"); }}});
  $("#delete_dialog").dialog({autoOpen : false, modal : true});
}

function register_dialog() {
  $("#save_dialog").dialog("close");
  $("#help_dialog").dialog("close");
  $("#register_dialog").dialog("open");
}

function help_dialog() {
  $("#register_dialog").dialog("close");
  $("#save_dialog").dialog("close");
  $("#help_dialog").dialog("open");
}

function save_dialog() {
  if (!Runnerroot.is_root_open) {
    $("#error_dialog").html("Please create a route first!");
    $("#error_dialog").dialog("open");
    return;
  }

  $("#help_dialog").dialog("close");
  $("#register_dialog").dialog("close");
  $("#is_save_error").html("");
  $("#save_dialog").dialog("open");
  $("#save_name")[0].focus();
}

function register() {
  var ajax = RR.get_ajax();
  var params = {username : document.register_form.username.value,
		email : document.register_form.email.value,
		password : document.register_form.password.value,
		password_confirm : document.register_form.password_confirm.value};

  var text_return = ajax.postSyncHttpRequest("/users/register", params);
  var register_info = eval("(" + text_return + ")");
  if (register_info.user_id > 0) {
    var username = document.register_form.username.value; 
    set_global_cookie("session_id", register_info.session_id);
    $("#login_name").html(username);
    $("#login").css("display", "inline");
    $("#user").css("display", "none");
    $("#register_dialog").dialog("close");
  } else {
    $("#is_register_error").html("<p style=\"color: red\">" + register_info.message + "</p>");
  }
}

function show_login() {
  $("#user").css("display", "inline");
  $("#login").css("display", "none");
}

function login() {
  var ajax = RR.get_ajax();
  var params = {username : document.login_form.username.value,
		password : document.login_form.password.value};
  var text_return = ajax.postSyncHttpRequest("/users/login", params);
  var login_info = eval("(" + text_return + ")");
  if (login_info.user_id > 0 && login_info.session_id.length > 0) {
    set_global_cookie("session_id", login_info.session_id);
    $("#login_name").html(login_info.username);
    $("#login").css("display", "inline");
    $("#user").css("display", "none");
  } else {
    $("#error_dialog").html(login_info.message);
    $("#error_dialog").dialog("open");
  }
}

function logout() {
  // throw a log-out request toward the server...
  var ajax = RR.get_ajax();
  ajax.postAsyncHttpRequest("/users/logout");

  // show login and reset session_id
  show_login();
  reset_global_cookie("session_id");
}

function set_global_cookie(name, value) {
  // save everything for one week
  var expires = 7 * 24 * 60 * 60;
  set_cookie(name, value, expires, "/", ".runnerroot.com");
}

function reset_global_cookie(name) {
  // reset global cookie
  set_cookie(name, false, -3600, "/", ".runnerroot.com");
}

function update_variables() {
  var units = "english";
  var pace = Math.round(10 * Runnerroot.pace) / 10 + " min / mi";
  var weight = Math.round(10 * Runnerroot.weight) / 10 + " lbs"

  if (Runnerroot.units == "metric") { 
    units = "metric";
    pace = Math.round(10 * Runnerroot.pace / 0.6213) / 10 + " min / km";
    weight = Math.round(10 * Runnerroot.weight / 2.2046) / 10 + " kgs";
  }

  html  = '<ul class="nobullet noindent">';
  html += '<li>[<a href="javascript: change_units()">Change</a>] Units : <b>' + units + '</b>';
  html += '<li>[<a href="javascript: change_pace()">Change</a>] Pace : <b>' + pace + '</b>';
  html += '<li>[<a href="javascript: change_weight()">Change</a>] Weight : <b>' + weight + '</b>';
  html += '</ul>';

  $("#variables").html(html);
}

function change_units() {
  Runnerroot.units = (Runnerroot.units == "english") ? "metric" : "english";
  Root.set_units(Runnerroot.units);
  set_global_cookie("units", Runnerroot.units);

  if (Runnerroot.is_root_open) { update_root(); }
  update_variables();
}

function change_pace() {
  var pace = (Runnerroot.units == "english") ? Runnerroot.pace : Runnerroot.pace / 0.6213;
  var unit = (Runnerroot.units == "english") ? "miles" : "kilometers";
  pace = Math.round(10 * pace) / 10;
  if (pace = prompt("Enter your pace in minutes / " + unit, pace)) {
    Runnerroot.pace = (Runnerroot.units == "english") ? pace : pace * 0.6213;
  }

  set_global_cookie("pace", Runnerroot.pace);
  update_variables();
  calculate_report();
}

function change_weight() {
  var weight = (Runnerroot.units == "english") ? Runnerroot.weight : Runnerroot.weight / 2.2046;
  var unit = (Runnerroot.units == "english") ? "pounds" : "kilograms";
  weight = Math.round(10 * weight) / 10;
  if (weight = prompt("Enter your weight in " + unit, weight)) {
    Runnerroot.weight = (Runnerroot.units == "english") ? weight : weight * 2.2046;
  }

  set_global_cookie("weight", Runnerroot.weight);
  update_variables();
  calculate_report();
}

function get_time(distance) {
  var minutes = Math.numberFormat(distance * Runnerroot.pace, 1);
  var hours = Math.numberFormat(Math.floor(minutes / 60), 0)
  minutes = Math.round(10 * (minutes % 60)) / 10;

  var display_string = minutes + " minutes";
  if (hours > 0) { display_string = hours + " hr " + Math.round(minutes) + " min"; }
  
  return display_string;
}

// expects distance in MILES to be correct
function get_calories(distance) {
  var coeff = 0.79;
  var weight = Runnerroot.weight;

  var calories = coeff * Runnerroot.weight * distance;  
  return Math.round(calories);
}

function calculate_report() {
  var root = Runnerroot.current_root;
  var distance = root.get_distance();
  var calories = get_calories(root.get_distance("english"));
  var unit = (Runnerroot.units == "english") ? "miles" : "kilometers";

  var information = Math.numberFormat(distance, 2) + " " + unit + "<br>";
  information += get_time(distance) + "<br>";
  information += calories + " calories";

  $("#report").html(information);
}

function calculate_points() {
  var root = Runnerroot.current_root;

  // update points
  if (root.get_points().length > 0) {
    var html = "<table><tr><td>Point</td><td>Distance</td><td>Time</td></tr>";
    var points = root.get_points();
    var last_point = false;
    var distance = 0;
    var unit = (Runnerroot.units == "english") ? "mi" : "km";
    for (var x = 0; x < points.length; x++) {
      if (last_point) {
	distance += Root.calculate_distance(last_point, points[x]);
      }
      html += "<tr><td>" + (x + 1) + "</td>";
      html += "<td>" + Math.numberFormat(distance, 2) + " " + unit + "</td>";
      html += "<td>" + get_time(distance) + "</td></tr>\n";
      last_point = points[x];
    }
    html += "</table>";
    $("#points").html(html);
  } else {
    $("#points").html("Click anywhere on the map to create a route");
  }
}

function update_root() {
  // display it on the map
  Runnerroot.map_manager.display_route(Runnerroot.current_root);

  // update distance/time info
  calculate_report();

  // update points in the sidebar
  calculate_points();
}

function create_root() {
  alert("Click anywhere on the map to begin!");
  this.reset_root();
  Runnerroot.is_root_open = true;
}

function reset_root() {
  // make ourselves a new root
  Runnerroot.current_root = new Root();

  // draw the "new" root (clearing old line markers)
  update_root();
}

function undo_root() {
  if (!Runnerroot.is_root_open) return;

  var point = Runnerroot.current_root.pop_point();  
  update_root();
}

function save_root() {
  var ajax = RR.get_ajax();
  var name = document.save_form.name.value;

  var params = {"points" : Runnerroot.current_root.pack_points(),
		"name" : name,
	        "root_id" : Runnerroot.current_root.id};
  var text_return = ajax.postSyncHttpRequest("/roots/save", params);
  var save_info = eval("(" + text_return + ")");
  if (save_info.root_id <= 0) {
    $("#is_save_error").html("<p style='color: red'>" + save_info.message + "</p>");
    return;
  }

  $("#save_dialog").dialog("close");
  $("#message_dialog").html(save_info.message);
  $("#message_dialog").dialog("open");
}

function get_name_from_results(id) {
  for (var x = 0; x < Runnerroot.search_results.length; ++x)
    if (Runnerroot.search_results[x].id == id)
      return Runnerroot.search_results[x].name;

  return "";
}

function load_root(id) {
  // put our map in a decent state
  reset_root();

  document.save_form.name.value = get_name_from_results(id);

  // load the points
  var ajax = RR.get_ajax();
  var params = {"root_id" : id};
  var points = eval(ajax.postSyncHttpRequest("/roots/load", params));

  // process the root points
  Runnerroot.current_root = new Root();
  Runnerroot.current_root.id = id;
  for (var i = 0; i < points.length; i++) {
    var p = new LatLng(points[i].lat, points[i].lng);
    Runnerroot.current_root.push_point(p);
  }

  // update the root
  Runnerroot.is_root_open = true;
  Runnerroot.map_manager.clear_markers();
  update_root();
}

function delete_root(id, verified) {
  if (verified) {
    var ajax = RR.get_ajax();
    var params = {root_id : id};
    var text_result = ajax.postSyncHttpRequest("/roots/delete", params);
    var delete_result = eval("(" + text_result + ")");
    $("#delete_dialog").dialog("close");
    if (delete_result.success == 0) {
      $("#error_dialog").html(delete_result.message);
      $("#error_dialog").dialog("open");
    } else {
      $("#message_dialog").html(delete_result.message);
      $("#message_dialog").dialog("open");
    }
    search_roots();
  } else {
    var name = get_name_from_results(id);
    var okay_action = function() { delete_root(id, true); }
    var cancel_action = function() { $("#delete_dialog").dialog("close"); }
    $("#delete_dialog").dialog("option", "buttons",
				 {Cancel : cancel_action,
				  Okay : okay_action});
    $("#delete_dialog").html("Are you sure you want to delete '" + name + "'?");
    $("#delete_dialog").dialog("open");
  }
}

function search_roots(was_clicked) {
  // do not search if the map is too far out...
  if (Runnerroot.map_manager.get_zoom() < 12) {
    if (was_clicked) { 
      $("#message_dialog").html("Please zoom in before searching for routes");
      $("#message_dialog").dialog("open");
    }

    $("#results").html("Found 0 routes in 0.000ms (zoom in)");
    return;
  }

  // make nice with a "loading" image
  var start_time = new Date().getTime();
  $("#results").html("Searching...");
  $("#results").css("background", "url(/images/loading.gif) no-repeat 10px 8px");

  // put our map in a decent state...
  reset_root();

  // make request for search
  var d_min = $("#d_min")[0].value;
  var d_max = $("#d_max")[0].value;
  var search_username = $("#search_username")[0].value;
  set_global_cookie("d_min", d_min);
  set_global_cookie("d_max", d_max);

  var ajax = RR.get_ajax();
  var bounds = Runnerroot.map_manager.get_bounds();
  var params = {"southwest" : bounds.getSouthWest().toUrlValue(),
	        "northeast" : bounds.getNorthEast().toUrlValue(),
		"d_min" : d_min, "d_max" : d_max, 
		"units" : Runnerroot.units,
		"search_username" : search_username};
  var results = ajax.getSyncHttpRequest("/roots/search/", params);
  var search_results = eval(results);
  Runnerroot.search_results = search_results;
  
  // display results 
  Runnerroot.is_root_open = false;
  Runnerroot.map_manager.display_search_results(Runnerroot.search_results);

  var end_time = new Date().getTime();
  $("#results").html("Found " + Runnerroot.search_results.length + " routes in " + (end_time - start_time) / 1000 + "ms");
  $("#results").css("background", "");
}

function process_point(overlay, point) {
  // use our own representation of lat/lng
  if (!point) return;
  
  var p = new LatLng(point.lat(), point.lng());
  p.g_latlng = point;

  Runnerroot.current_root.push_point(p);
  Runnerroot.is_root_open = true;
  
  update_root();
}

function search_map() {
  var address = document.address_form.address.value;
  var geocoder = Runnerroot.geocoder;
  var map = Runnerroot.map;

  set_global_cookie("default_address", address);

  var func = function(response) {
    if (response && response.Status.code == 200) {
      var place = response.Placemark[0];
      var latlng = new GLatLng(place.Point.coordinates[1],
			       place.Point.coordinates[0]);
      var zoom = place.AddressDetails.Accuracy + 10;
      if (zoom > 16) zoom = 16;

      // center our map
      Runnerroot.map_manager.set_center(latlng, zoom);

      // do a search
      search_roots();
    }
  }
  geocoder.getLocations(address, func);
}

function rr_load() {
  // init
  init();
 
  // load map
  var themap = new GMap2(document.getElementById("map"),
		  {
		      draggableCursor : "crosshair",
		      draggingCursor : "crosshair"
		  });
  Runnerroot.map_manager = new MapManager(themap);

  // setup the geocoder
  Runnerroot.geocoder = new GClientGeocoder();

  // center and zoom the map to something reasonable
  if (document.address_form.address.value != "") {
    search_map();
  } else {
    if (ip_lat && ip_lng) {
      Runnerroot.map_manager.set_center(new GLatLng(ip_lat, ip_lng), 8);
    } else {
      Runnerroot.map_manager.set_center(new GLatLng(35, -90), 4);
    }
  }

  // add our listeners...
  GEvent.addListener(themap, "click", process_point);
  GEvent.addListener(themap, "dragend", function() { if (!Runnerroot.is_root_open) { search_roots(); }} );
  GEvent.addListener(themap, "zoomend", function() { if (!Runnerroot.is_root_open) { search_roots(); }} );

  // update initial information
  update_variables();
  calculate_points();
  calculate_report();
}

function rr_unload() {
  GUnload();
}
