/*
Certain global variables must be set in order for this to function properly:
eg, for NY2008:
var mymapsKML = "http://maps.google.co.uk/maps/ms?ie=UTF8&hl=en&msa=0&output=nl&msid=106583798356934466139.000452ff8b165a8dff62d"; //google map RSS link
var venuesURI = "./NYrss.xml"; //using local file rather than live feed for venue definition, save google RSS link as, then link to that xml file.
var commutersURI = "http://creator.zoho.com/tangocommute/json/4/callback=showCommuters"; //URI for the zoho commuter JSON feed.
var center = new GLatLng(40.75,-73.96);//could calculate this rather than setting it manually
var zoomLevel = 11;//again, should be made automatic
*/

var map;
var placeMarker;
var bObj; //used for JSONscriptRequest, which parses data from zoho feed.
var commuterMarkers;
var currentlySelectedVenue;
var currentPoly;
var venueArray; //venueArray holds items and is indexed with place title as key
var polygonArray; //polygonArray holds GPolygons and is indexed with place title as key
var lastGoodPoint;
var testIcon;

//used in construction of zoho form
var breakFieldName = "point";
var locationFieldName = "Your_Location";
var dragMessage = "Presiona y desliza este marcador para elegir tu localizacion, el sitio donde queries bailar.";

function initialize() {
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map_canvas"));
    map.enableScrollWheelZoom();
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    map.addMapType(G_PHYSICAL_MAP);
    map.setMapType(G_PHYSICAL_MAP);
    
    makeIconArray();
    
    //this would be too easy... 
    //in order to associate the geographical venue data with place names and other logic
    //in our script, we also need to do extra parsing later 
    var venuesGX = new GGeoXml(mymapsKML); //New York locations from MyMaps
    map.addOverlay(venuesGX);
    
    map.setCenter(center, zoomLevel);
    
    venueArray = new Array();
    polygonArray = new Array();
    GDownloadUrl(venuesURI, function(data, responseCode) {
      var xml = GXml.parse(data);
      var items = xml.documentElement.getElementsByTagName("item");
      for (var i=0; i<items.length; i++) {
        var fitem = items[i].getElementsByTagName("title").item(0);
        var title = getText(fitem);
        var p = parsePolygonFromItem(items[i]);
        if (p){
			polygonArray[title] = p;
			p.title = title;
			venueArray[title] = fitem;
		}
        /* 
        //commented out, as we are only using these polygons internally for knowing
        //what area a region covers; we don't add a listener to them or add them as
        //an overlay since we are using a standard GGeoXml overlay
        GEvent.addListener(p, "click", function(){
          if(currentPoly != this) venueSelection(this.title);
        });
        map.addOverlay(p); 
        */
      }
    });
    
    
    
	bObj = new JSONscriptRequest(commutersURI);
    bObj.buildScriptTag();
    bObj.addScriptTag();
    
  }
}
function createPlaceMarker(center){
    placeMarker = new GMarker(center, {draggable: true});
    map.addOverlay(placeMarker);
    document.getElementById("zoho-point").value = placeMarker.getPoint();
    GEvent.addListener(placeMarker, "click", function(){
      placeMarker.openInfoWindow(dragMessage);
    });
    GEvent.addListener(placeMarker, "dragstart", function(){
      placeMarker.closeInfoWindow();
    });
    GEvent.addListener(placeMarker, "drag", function(){
      if (!currentPoly.contains(placeMarker.getPoint())) placeMarker.setPoint(lastGoodPoint);
      lastGoodPoint = placeMarker.getPoint();
    });
    GEvent.addListener(placeMarker, "dragend", function() {
      document.getElementById("zoho-point").value = placeMarker.getPoint();
    });
}
//This function is called automatically on construction of JSONscriptRequest(commutersURI)
function showCommuters(jsonData){
  var commuterData = jsonData[tableName];
  if (document.getElementById("commuterList")) showCommutersWithList(commuterData);
  else {
	  commuterMarkers = new Array();
	  for (var i in commuterData){
		var commuter = commuterData[i];
		var fmarker = createCommuterMarker(commuter);
		commuterMarkers.push(fmarker);
		map.addOverlay(fmarker);
	  }
	  bObj.removeScriptTag();
  }
}
function showCommutersWithList(commuterData){
  commuterMarkers = new Array();
  var fHTML = "<table>";
  for (var i in commuterData){
    var commuter = commuterData[i];
    var fmarker = createCommuterMarker(commuter);
    var name = commuter.TangoCommuter_A;
    commuterMarkers[i] = fmarker;
    map.addOverlay(fmarker);
    fHTML += "<tr>";
    var iconKey = commuter.Dance_Experience;
    iconKey += commuter.TangoCommuter_B ? "-dot" : "";
    fHTML += (iconKey=="") ? "<td></td>" : "<td><img style='width:16px; height:16px' src='" + dancerIcons[iconKey].image + "' /></td>";
    fHTML += "<td><a href='javascript:highlightMarker(" +i+ ")'>" +name+ "</td>";
    //fHTML += "<td><a href='javascript:commuterMarkers[" + i + "].openInfoWindowHtml();'>" +name+ "</td>";
    fHTML += "</tr>";
  }
  fHTML += "</table>";
  document.getElementById("commuterList").innerHTML = fHTML;
  bObj.removeScriptTag();
  
  //process the list of venues after the real commuters callback stuff has finished
  //to be sure there is a table to insert into etc... most uncouth.
  venueArray = new Array();
  polygonArray = new Array();
  GDownloadUrl(venuesURI, function(data, responseCode) {
    var xml = GXml.parse(data);
    var items = xml.documentElement.getElementsByTagName("item");
    var fHTML;
    var table = document.getElementById("commuterList").childNodes[0];
    for (var i=0; i<items.length; i++) {
      var fitem = items[i].getElementsByTagName("title").item(0);
      var title = getText(fitem);
      var p = parsePolygonFromItem(items[i]);
      if (p){
		  polygonArray[title] = p;
		  p.title = title;
		  venueArray[title] = fitem;
		  var row = table.insertRow(table.rows.length);
		  var cell;
		  cell = row.insertCell(0);
		  cell = row.insertCell(1);
		  var link = document.createElement('a');
		  link.setAttribute("href", "javascript:venueSelection('" +title+ "')");
		  link.innerHTML = title;
		  cell.appendChild(link);
	  }
    }
  });
}

var commuterInfo = new Array();
function createCommuterMarker(commuter){
  var fHTML;
  var glatlng;
  //commuter.point should be in the format "(<lat>, <lng>)" where <lat> and <lng> are numbers 
  //malformed data produces an error.
  //AFAIK, the only way malformed data could be produced is if either
  // a) someone used the original zoho form, which displays the point field, and put something wrong in
  // b) some l33t h4xor went to a little bit of trouble to deliberately substitute something stupid.
  //The chances of either of these eventualities ensuing is considered vanishingly small
  //(although adding validation in zoho would probably have taken less long than writing this comment)
  
  //Strip the brackets...
  var fpoint = commuter.point.substring(1,commuter.point.length-1);
  var fmarker;
  fpoint = fpoint.split(", ");
  glatlng = new GLatLng(fpoint[0], fpoint[1]);
  fHTML = "<em>Leader:</em> " + commuter.TangoCommuter_A + "<br />";
  fHTML += commuter.TangoCommuter_B ? "<em>Follower:</em> " + commuter.TangoCommuter_B + "<br />" : "";
  fHTML += commuter.Dance_Experience + "<br />";
  //add image tag if relevant
  fHTML += commuter.profileimage ? "<img src='" + commuter.profileimage + "' />" : "";
  commuterInfo.push(fHTML);//push into commuterInfo 
  //XXX: note that indices of commuterInfo depend on this function always being called for each commuter in the appropriate order
  
  //make the marker at the appropriate point, ready to display our html when clicked.
  var iconKey = commuter.Dance_Experience;
  iconKey += commuter.TangoCommuter_B ? "-dot" : "";
  var ficon = dancerIcons[iconKey];
  fmarker = new GMarker(glatlng, {icon:ficon});
  GEvent.addListener(fmarker, "click", function(){
    fmarker.openInfoWindowHtml(fHTML);
  });
  return fmarker;
}
function highlightMarker(i){
  var marker = commuterMarkers[i];
  marker.openInfoWindowHtml(commuterInfo[i]);
  map.setCenter(marker.getLatLng(), 17);
  map.setMapType(G_HYBRID_MAP);
}


// === A method for testing if a point is inside a polygon
// === Returns true if poly contains point
// === Algorithm shamelessly stolen from http://alienryderflex.com/polygon/ 
GPolygon.prototype.contains = function(point) {
  var j=0;
  var oddNodes = false;
  var x = point.lng();
  var y = point.lat();
  for (var i=0; i < this.getVertexCount(); i++) {
    j++;
    if (j == this.getVertexCount()) {j = 0;}
    if (((this.getVertex(i).lat() < y) && (this.getVertex(j).lat() >= y))
    || ((this.getVertex(j).lat() < y) && (this.getVertex(i).lat() >= y))) {
      if ( this.getVertex(i).lng() + (y - this.getVertex(i).lat())
      /  (this.getVertex(j).lat()-this.getVertex(i).lat())
      *  (this.getVertex(j).lng() - this.getVertex(i).lng())<x ) {
        oddNodes = !oddNodes
      }
    }
  }
  return oddNodes;
}

//simplest (dirty) workaround for x-browser xml namespace handling?
//currently, this function is just being used for the Polygon elements
//and it works in Opera & IE, but not Safari or Firefox 
//(? not sure what that comment was about... seems to be working :-| )
function getGMLElementsByTagName(tagName, scope){
  var ns = "http://www.opengis.net/gml";
  var prefix = "gml";
  var elementListForReturn = scope.getElementsByTagName(prefix+":"+tagName);
  if(elementListForReturn.length == 0){
    elementListForReturn = scope.getElementsByTagName(tagName);
    if(elementListForReturn.length == 0){
      elementListForReturn = scope.getElementsByTagName(ns+":"+tagName);
      if(elementListForReturn.length == 0 && document.getElementsByTagNameNS){
        elementListForReturn = scope.getElementsByTagNameNS(ns, tagName);
      }
    }
  }     
  
  return elementListForReturn;
}

// cross-browser getText ~~ http://www.webmasterworld.com/javascript/3281616.htm
// This has too many problems.
//Object.prototype.getText = function() {
//    return this.textContent || this.innertext;
//}

// cross-browser getText ~~ http://www.webmasterworld.com/javascript/3281616.htm
function getText(o) {
    // alert("gettext");
    return o.textContent || o.innerText || o.text;
}



//making an array of colorful dancerIcons with "dancer experience" as key.
var GIconDir = "http://maps.google.co.uk/intl/en_uk/mapfiles/ms/micons/"; //green-dot.png etc.
var IconCols = new Array();//["green", "yellow", "red", "purple", "pink", "blue", "ltblue"]; 
var dancerIcons = new Array();

function makeIconArray(){
  //what a load of bloody hassle; why can't we just make a GMarker of specified colour?
  var baseIcon = new GIcon();
  baseIcon.iconSize = new GSize(32,32);
  baseIcon.shadowSize = new GSize(56,32);
  baseIcon.iconAnchor = new GPoint(16,23);
  baseIcon.infoWindowAnchor = new GPoint(16,0);
  
  for (exp in IconCols){
    dancerIcons[exp] = new GIcon(baseIcon, GIconDir + IconCols[exp] + ".png");
    dancerIcons[exp + "-dot"] = new GIcon(baseIcon, GIconDir + IconCols[exp] + "-dot.png");
  }
}


//takes a KML item and returns 1st GPolygon child if present, otherwise null
function parsePolygonFromItem(item){
  var polyEls = getGMLElementsByTagName("Polygon", item);
  if (polyEls.length < 1) return null;
  //split the string of the first Polygon element by whitespace; each item only has one Polygon element.
  var poslist = getText(polyEls.item(0)).split(new RegExp("\\s+"));
  var poslistf = new Array();
  //parse the split 'poslist' for floats and add them to new array.
  for (var n=0; n<poslist.length; n++) {
    var f =  parseFloat(poslist[n]);
    if (!isNaN(f)) poslistf.push(f);
  }
  //finally, make GLatLngs from each pair of floats in the array...
  var latlngs = new Array();
  for (var i=0; i<poslistf.length-1; i+=2){
    latlngs.push(new GLatLng(poslistf[i], poslistf[i+1]));
  }
  var fpoly = new GPolygon(latlngs, "#000099", 2, 0.7, "#0000ff", 0.1);
  return fpoly;
}

//takes venueTitle as a string which is the key for venueArray
function venueSelection(venueTitle){
  map.setMapType(G_HYBRID_MAP);
  var fvenue = currentlySelectedVenue = venueArray[venueTitle];
  currentPoly = polygonArray[venueTitle];
  var fbounds = currentPoly.getBounds();
  var fcenter = fbounds.getCenter(); 
  map.setZoom(map.getBoundsZoomLevel(fbounds));
  map.setCenter(fcenter);
}

//makes a draggable marker at the centre of the currentPoly.  
//Meant to be called directly after venueSelection, otherwise currentPoly may not be set.
function createInteractiveMarker() {
  var fbounds = currentPoly.getBounds();
  var fcenter = fbounds.getCenter(); 
  lastGoodPoint = fcenter; //nb. the center of the bounds may not actually be within the poly...
  //but then, that's not the only part of the code that is not totally robust; 
  //it works with the current data
  if (!placeMarker) createPlaceMarker(fcenter);
  placeMarker.setLatLng(fcenter);
  placeMarker.show();
  placeMarker.openInfoWindow("Presiona y desliza este marcador para elegir tu localizacion, el sitio donde queries bailar.");
}

function writeZohoField(fieldName){
	document.write("<tr id='tr-" + fieldName + "'><td>");
	Zoho.writeLabel(fieldName);
	document.write("</td><td>");
	Zoho.writeInput(fieldName);
	document.write("</td></tr>");
}

function writeFormTop(){
  document.write("<table>");
  for (fieldName in Zoho.inputArr) {
    writeZohoField(fieldName);
    if (fieldName == breakFieldName) break;
  }
  document.write("</table>");
  document.getElementById("tr-"+breakFieldName).style.display = "none";
}

function writeFormBottom(){
  document.write("<table>");
  var startWriting = false; //we start writing after reaching the 'break' field, ie 'point'
  for (fieldName in Zoho.inputArr) {
    if (startWriting) writeZohoField(fieldName);
    if (fieldName == breakFieldName) startWriting = true;
  }
  document.write("</table><br />");
  Zoho.writeSubmit("Submit"); Zoho.writeReset("Reset");
  document.getElementById("zoho-"+ locationFieldName).onchange = function(){
    var vv = document.getElementById("zoho-"+ locationFieldName);
    venueSelection(getText(vv[vv.selectedIndex]));
	createInteractiveMarker();
  };
}