var defaultToValue = "eg: Target in Boston, or 1229 Barranca St, San Diego"

// Our global state
var gLocalSearch;
//var gDirectionSearch;
var gLocalFromSearch;
var gDirections;
var gMap;
var gSelectedResults = [];
var gCurrentResults = [];
var gCurrentFromResults = [];
var gSearchForm;
var gAllTrips = [];
var currentTripResults = [];
var toSearcher;
var cancelSearch;
var cancelFromSearch;
var gCurrentFrom = {};
var gSelectedResult = false;
var gShowFirstTrips; // Set this to true to automatically show a list of the first trips returned from the ajax request
var from;  // .address .lat .lng
var to;
var datechooser;
var wherefrom;
var whereto;
if (typeof clusters == "undefined") clusters = {}
if (typeof trips == "undefined") trips = {}
var cachedTrips = {}
var cachedDestinations = {}
// Set up the map and the local searcher.
function OnLoad() {
  if (!gCurrentFrom.lat) {
    gCurrentFrom.lat = 42
    gCurrentFrom.lng = -91
	gCurrentFrom.address = ""
  }
  // Initialize the local searcher for the to address
  gDirections = new GDirections(gMap);
//  GEvent.addListener(gDirections, "error", handleErrors);
//  GEvent.addListener(gDirections, "load", yay);

  gLocalSearch = new GlocalSearch();
  //gDirectionSearch = new GDirections(gMap)
  //gLocalSearch.setCenterPoint(gMap);
  gLocalSearch.setCenterPoint(gMap.getCenter());
  gLocalSearch.setSearchCompleteCallback(null, OnLocalSearch);

  gLocalFromSearch = new GlocalSearch();
  gLocalFromSearch.setCenterPoint(gMap);
  gLocalFromSearch.setSearchCompleteCallback(null, OnFromSearch);

//  showTripsFor("default")

  datechooser=$('datechooser')
  whereto = $('whereto');
  wherefrom = $('wherefrom');
  tripresultsdiv = $("tripresults");

  // Set up default text for to field
  whereto.style.color = "#aaa"
  whereto.value = defaultToValue
  whereto.observe('focus', focusTo)
  whereto.observe('click', focusTo)

}

function focusTo(event) {
    // hide the default to text
	if (whereto.value == defaultToValue) {
		whereto.value = ""
		whereto.style.color = "#000"
	}
}

function blurWhereFrom(what) {
	//console.log('blurred')
	var from = $('wherefrom').value
//	if (from.length && from != gCurrentFrom.address)
//		startFromSearch();
}

function startFromSearch() {
	cancelFromSearch = false;
	gLocalFromSearch.execute($('wherefrom').value);
	all_froms = [];
	tripresultsdiv.innerHTML="Let's see if we can find you!";
}

function OnFromSearch() {
  if (cancelFromSearch) {
	cancelFromSearch = false
	return;
  }
  if (!gLocalFromSearch.results.length)  {
	tripresultsdiv.innerHTML="Sorry, we couldn't find your From location, can you be more specific?";
	
	return;
  }

  // Clear the map of old from markers, and me marker
  for (var i = 0; i < gCurrentFromResults.length; i++) {
  	gMap.removeOverlay(gCurrentFromResults[i].marker());
  }
  if (memarker)
	gMap.removeOverlay(memarker);	


  //make localresults for our from location
  gCurrentFromResults = [];
  for (var i = 0; i < gLocalFromSearch.results.length; i++) {
    gCurrentFromResults.push(new LocalResult(gLocalFromSearch.results[i], true) );
  }

  
  // if there is only one result, select it as the from address
  if (gCurrentFromResults.length == 1) {
	var from = gCurrentFromResults[0]
	changeFrom(from.result_.lat, from.result_.lng, from.address() )
  } else {
      tripresultsdiv.innerHTML="<br/>We've found a couple places you might be.  Choose the red star that is closest to you.";
  }
  resetLocalSearchResults();
  rezoom();
  var attribution = gLocalSearch.getAttribution();
  if (attribution) {
    document.getElementById("searchwell").appendChild(attribution);
  }

}


function blurSearcher(what) {
	//console.log('blurred')
	var from = $('wherefrom').value
	if (from.length && from != gCurrentFrom.address)
		startFromSearch();
	else
		googleLocalSearch();
}

function removeOverlays(overlays) {
  for (var i = 0; i < overlays.length; i++) {
	overlays[i].remove_markers();
  }
}
function resetLocalSearchResults() {
  var searchWell = document.getElementById("searchwell");
  // Clear the map and the old search well
  searchWell.innerHTML = "Searching for trips...";
  (tripresultsdiv || $("tripresults")).innerHTML = "";
  removeOverlays(gCurrentResults);
  removeOverlays(currentTripResults);
  gDirections.clear()
  gCurrentResults = [];
  gSelectedResult = false;
}

// When we get a list of local results from google, put them on the map, and run a goloco search
function OnLocalSearch() {
  if (cancelSearch) {
	cancelSearch = false
	return;
  }
  if (!gLocalSearch.results.length) {
	document.getElementById("searchwell").innerHTML="Sorry, we didn't understand your destination.  Can you be more specific?";
	return;
  } 
  document.getElementById("searchwell").innerHTML="";

  // Initialize LocalResult Objects for our results
  for (var i = 0; i < gLocalSearch.results.length; i++) {
    var dest = new LocalResult(gLocalSearch.results[i], false) 
    gCurrentResults.push(dest);
    fetchDestinationTrips(dest);
    cachedDestinations[dest.slug()] = dest
  }
  
  // if there is only one result, select it
  if (gLocalSearch.results.length == 1) {
    setCurrentCluster(gCurrentResults[0])
  }
  rezoom()

  var attribution = gLocalSearch.getAttribution();
  if (attribution) {
    document.getElementById("searchwell").appendChild(attribution);
  }

}

function setCurrentCluster(cluster){
  gSelectedResult = cluster
  whereto.value = gSelectedResult.address()
}

function loadTripsFor(cluster, trips, html) {
    clusters[cluster]  = {}
    clusters[cluster].trips = trips
    clusters[cluster].html = html
    if (typeof cachedDestinations[cluster] != "undefined") {
        cachedDestinations[cluster].setTrips(trips)
    }
    if (gSelectedResult == cachedDestinations[cluster] ) {
        gSelectedResult.showMyTrips()
    } else if ( gSelectedResult == false && cluster == "default") {
        showTripsFor("default")
    }
}



function get_dates() { 
    var selected_date_tags = '';

	if ($('repeats').checked) {
		// repeating date
		for (var i = 0; i < 7; i++) {
			var day = 'day' + i
			if ($(day).checked) {
				selected_date_tags += "<input id='hidden_" + $(day).value +"' name='trip_dates[]' type='hidden' class='trip_date_hidden' value='" + $(day).value +"'/>";
			}
		}
	} else if (mydate){
		// datechooser has set a date (hopefully)
		selected_date_tags += "<input name='trip_dates[]' type='hidden' class='trip_date_hidden' value='" + mydate.getFullYear() + "-" + (mydate.getMonth()+1) + "-" +mydate.getDate() +"'/>";
	}
	$('selected_date_hidden_fields').innerHTML = selected_date_tags
}
var mydate = false;
function pick_date(objDate) {
	mydate = objDate;
	return true;
}

function fetchDestinationTrips(destination) {
	params = {dest_address: destination.address(), 
	          dest_lat: destination.lat, 
	          dest_lng: destination.lng, 
	          cluster: destination.slug()
	          }
	genericTripSearch(params)
}
function genericTripSearch(params) {
    // Start the ajax call for this destination
    // When it returns, we will set the trips on that object.
    default_params = $H({from_address: gCurrentFrom.address, 
	          from_lat: gCurrentFrom.lat, 
	          from_lng: gCurrentFrom.lng,
	          cluster: "default"
	          }).merge (serializer.serialize("trip_search", trip_search))
	
    new Ajax.Request('/map/search', {method: 'get', 
			onSuccess: function(transport) {
				eval(transport.responseText)
			},
			parameters: default_params.merge(params),
			evalJS: "force"
	})
    
}

// When the from is changed, we redo the current search, whatever it is.
function changeFrom(lat, lng, addr) {
	gCurrentFrom.lat = lat
	gCurrentFrom.lng = lng
	gCurrentFrom.address = addr
	$("wherefrom").value = gCurrentFrom.address
	place_memarker();

	googleLocalSearch();
}
function initializeme() {
  if (GBrowserIsCompatible()) {
    gMap = new GMap2(document.getElementById("map_canvas"));
	map = gMap
    map.setCenter(new GLatLng(cu.latitude,cu.longitude), 10);
  	map.addControl(new GSmallMapControl());

	OnLoad()

	// Put me at home
	gCurrentFrom.lat = cu.latitude
	gCurrentFrom.lng = cu.longitude
	gCurrentFrom.address = cu.address
	if (cu.latitude == 0)
		startFromSearch();
	else
		wherefrom.value = cu.address

	place_memarker()
  }
}

function place_memarker() {
	if (memarker){
		gMap.removeOverlay(memarker)
	}
	for (var i = 0; i < gCurrentFromResults.length; i++) {
    	gMap.removeOverlay(gCurrentFromResults[i].marker());
    }
	opts = {"labelText": "", "icon": memarker_icon, zIndexProcess:meZIndex}
	memarker = new GMarker(new GLatLng(gCurrentFrom.lat,gCurrentFrom.lng), opts)
	map.addOverlay(memarker)
}
function meZIndex() {return (GOverlay.getZIndex(gCurrentFrom.lat) - 5000)}

function showTripOnMap(tripSlug) {
    cachedTrips[tripSlug].find_marker()
}

// Called when Trip Search results are returned, we clear the old
// results and load the new ones.
var tripresultsdiv;

function showTripsFor(clusterName, newTripsDiv) {
    if (!gMap)
        return
        
    if (!tripresultsdiv) tripresultsdiv = $('tripresults');
        tripresultsdiv.innerHTML = "";
    
    cluster = clusters[clusterName]
    // remove current trips from map
    removeOverlays(currentTripResults)
    currentTripResults = [];
    
    use_origin = (trip_search.group_id) ? true : false
  	
    cluster.trips.each(function(tripSlug) {
        cachedTrips[tripSlug] = new TripResult(trips[tripSlug], use_origin)
        currentTripResults.push(cachedTrips[tripSlug])
    });
    
  	// Draw lines from origin to destination
  	if (drawLines && currentTripResults.length < 60) {
  	   for (var i = 0; i < currentTripResults.length; i++) {
  	    currentTripResults[i].showLine(true);
  	  }
  	}
    rezoom();
    
    // put trip list html in the tripresultsdiv 
    if (newTripsDiv) {
  	    tripresultsdiv = newTripsDiv
    }else {
        tripresultsdiv = $('tripresults');
      	// we have searched for anywhere, so hide local search results
      	document.getElementById("searchwell").innerHTML="";
    }
    tripresultsdiv.innerHTML = cluster.html;
}


function googleLocalSearch() {
	focusTo()
	cancelSearch = false;
	all_trips = [];
	gSelectedResult = false;
	tripresultsdiv.innerHTML="";
	resetLocalSearchResults();
	gLocalSearch.setCenterPoint(new GLatLng(gCurrentFrom.lat, gCurrentFrom.lng));
	var to = $('whereto').value
	// DEBUG TODO: Remove
	if (/^[1-9]+(\.?[1-9]+)?$/.test(to)) {
	  distRatio = parseFloat(to)
	  to =""
	}
	if (to.length == 0 ) {
		genericTripSearch()
	}
	else {
		gLocalSearch.execute(to);
	}
}
//Event.observe(window,'load', initializeme)


var serializer = {
 
  serialize : function(object) {
    var values = []; 
    var prefix = '';
    
    values = this.recursive_serialize(object, values, prefix);
    
    param_string = values.join('&');
    return param_string;
  },
  
  recursive_serialize : function(object, values, prefix) {
    var value;
    var prefixed_key;
    var child_prefix = '';
    for (var key in object) {
      if (typeof object[key] == 'object' || typeof object[key] == 'array') {
        
        if (prefix.length > 0) {
          child_prefix = prefix + '['+key+']';         
        } else {
          child_prefix = key;
        }
        
        values = this.recursive_serialize(object[key], values, child_prefix);
                
	  } else if (typeof object[key] != 'function' && typeof object[key] != 'undefined') {
        value = encodeURIComponent(object[key]);
        if (prefix.length > 0) {
          prefixed_key = prefix+'['+key+']'          
        } else {
          prefixed_key = key
        }
        prefixed_key = encodeURIComponent(prefixed_key);
        if (value) values.push(prefixed_key + '=' + value);
      }
    }
    return values;
  }
}

var lastitem;
function revealListItem(item) {
	if (lastitem) {
		lastitem.removeClassName("selectedItem")
	}
	if (item) {
		item.addClassName("selectedItem")
		lastitem = item;
	}
}
function withinStdDev(mean, deviation, value) {
  return Math.abs(mean - value) < 2 * deviation
}
function dist2(a, b) {
  return Math.pow(a.lat() - b.lat(), 2) + Math.pow(a.lng()-b.lng(),2)
}
var distRatio = 1.5
function rezoom() {
	var from = new GLatLng(gCurrentFrom.lat, gCurrentFrom.lng);


	var bounds = new GLatLngBounds();
	var minbounds = new GLatLngBounds();
	bounds.extend(from);
	minbounds.extend(from);
	if (currentTripResults) {
	  var allLats = []
	  var allLngs = []
	  var distances = []
	  var avgdistance = 0
		for (var i=0; i<currentTripResults.length; i++) {
		  p = currentTripResults[i].marker().getPoint()
		  allLats.push(p.lat());
		  allLngs.push(p.lng());
		  distances.push(dist2(p,from));
		}
		avgdistance = distances.median()

		var latdev = allLats.standardDeviation()
		var lngdev = allLngs.standardDeviation()
		var latavg = allLats.mean()
		var lngavg = allLngs.mean()
		for (var i=0; i<currentTripResults.length; i++) {
		  //reject trips that are more than twice the median distance from home.
		  if (distances[i] < distRatio * avgdistance)
		    bounds.extend(currentTripResults[i].marker().getPoint());
		}
	}
	if (gCurrentResults) {
		for (var i=0; i<gCurrentResults.length; i++) {
		  bounds.extend(gCurrentResults[i].marker().getPoint());
		  minbounds.extend(gCurrentResults[i].marker().getPoint());
		}
	}
	if (gCurrentFromResults) {
		for (var i=0; i<gCurrentFromResults.length; i++) {
		  bounds.extend(gCurrentFromResults[i].marker().getPoint());
		  minbounds.extend(gCurrentFromResults[i].marker().getPoint());
		}
	}
	z = map.getBoundsZoomLevel(bounds)
	minz = map.getBoundsZoomLevel(minbounds)
	//alert ("z: " + z + "min z:" + minz)
	// if (z -minz < 2) {
	// 	// our results are too big, only show from and to results (not all trips)
	// 	z = minz
	// 	bounds = minbounds
	// }
	if (z>14) z = 14; // don't zoom in too far!

	map.setCenter(bounds.getCenter(), z);
	
}

var serializer = {
  serialize : function(name, object) {
      hash = {}
      for (var key in object) {
          if(typeof object[key] != 'function')
            hash[name+"["+key+"]"] = object[key]
      }
      return hash
  }
}

function show_tab(tab) {
  tab = tab + "_tab"
  all_tabs=$$("div.tab");
  all_tabs.each(function(tab_div) {
    this_tab = tab_div.id
    if (this_tab != tab) {
      t = $(this_tab+"_list")
      if (t) t.hide()
      tab_div.removeClassName("selectedtab")
    }
  });
  $(tab+"_list").show()
  $(tab).addClassName("selectedtab")
  return false 
}