// Copyright (C) 2006 Ashutosh Kulshreshtha (ashu.kuls@gmail.com)
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// renderer.js
//-------------------
// Upload KML files and browse the layers using google maps API

// Common Functions
var gRenderer_; // The renderer application
Event.observe(window, 'load', load, false);

function load() {
  var width, height;
  if( window.innerHeight ) {
    width = window.innerWidth - 300 ;
    height = window.innerHeight - 50 ; 
  } else {
    width = document.documentElement.offsetWidth - 350 ;
    height = document.documentElement.offsetHeight - 90 ; 
  }
  printfire(width);
  printfire(height);
  $('map').style.width = width + "px";
  $('map').style.height = height + "px";
  gRenderer_ = new LayerRenderer();
  attachEvents();
  hide_status();

  // Focus the search box
  Field.focus('q');

  new AutoSuggestControl($('q'), gRenderer_);
}

// With firebug extension
function printfire()
{
  if (document.createEvent)
  {
    printfire.args = arguments;
    var ev = document.createEvent("Events");
    ev.initEvent("printfire", false, true);
    dispatchEvent(ev);
  }
}

function noop() {
}

function clear(event) {
  printfire("clear called");
  var element = Event.element(event);
  gRenderer_.clearMap();
}

function show_poi(event) {
  gRenderer_.showMarker();
}

function fetch_near() {
  gRenderer_.fetchNear();
}

function search(event) {
  gRenderer_.search();
}

function browse(event) {
  // gRenderer_.browse();
}

function add_point(event) {
  var element = Event.element(event);
  var layerid = element.getAttribute("layerid");
  gRenderer_.send_add_point(layerid);
}

function suggest(event) {
  gRenderer_.suggest();
}

function hide_status() {
  printfire("hide status");
  Element.hide('status');
}

function set_status(str) {
  printfire("set status " + str);
  if (str) {
    Element.update('status', str);
  }
  Element.show('status');
}

function result_clicked(event) {
  var element = Event.element(event);
  var rid = element.getAttribute("rid");
  printfire("result " + rid + " clicked");
  gRenderer_.showInfoWindow(rid);
}

function attachEvents() {
  Event.observe(window, 'unload', GUnload, false);
  // Event.observe($('form'), 'submit', noop, false);
  Event.observe($('button_clear'), 'click', clear , false);
  Event.observe($('button_poi'), 'click', show_poi , false);
  Event.observe($('button_fetch'), 'click', fetch_near , false);
  // Event.observe($('button_browse'), 'click', browse , false);
  Event.observe($('searchform'), 'submit', search, false);

  var array = $A(document.getElementsByClassName("add_point"));
  array.each ( function(elem) {
      Event.observe(elem, 'click', add_point, false);
      });
}

function button_click(event) {
  var element = Event.element(event);
  var layer = element.getAttribute("value");
  var region_select = $("select_"+layer);
  var region = region_select.options[region_select.selectedIndex].value;
  gRenderer_.fetchRegion(layer, region);
}

// LayerRenderer class
var LayerRenderer = Class.create();

LayerRenderer.prototype.initialize = function() {
  this.map = undefined;
  this.marker = undefined;
  this.add_point_marker = undefined;
  if (GBrowserIsCompatible()) {
    this.map = new GMap2(document.getElementById("map"));
    this.map.addControl(new GLargeMapControl());
    this.map.addControl(new GScaleControl());
    this.map.addControl(new GMapTypeControl());
    this.map.setCenter(new GLatLng(12.98,77.59), 12);
    this.map.setMapType(G_SATELLITE_MAP);
    new GKeyboardHandler(this.map);
  } else {
    alert("Google maps API is not supported on your browser.");
  }
  this.layer_hash = $H();
  this.marker_hash = $H();
  this.result_index = 1;

  this.default_icon = new GIcon();
  this.default_icon.image = "markers/0.png";
  this.default_icon.shadow = "markers/shadow.png";
  this.default_icon.iconSize = new GSize(12, 20);
  this.default_icon.shadowSize = new GSize(22, 20);
  this.default_icon.iconAnchor = new GPoint(6, 20);
  this.default_icon.infoWindowAnchor = new GPoint(5, 1); 

  this.tilelayer = undefined;
  // this.browse();
}

LayerRenderer.prototype.setLayers = function(layers) {
  this.layer_hash = $H();
  for (var i = 0; i < layers.length; ++i) {
    if (layers[i].icon) {
      var icon = new GIcon(this.default_icon, layers[i].icon);
      layers[i].icon = icon;
    } else {
      layers[i].icon = this.default_icon;
    }
    this.layer_hash[layers[i].id] = layers[i];
  }
}

LayerRenderer.prototype.clearMap = function() {
  this.map.clearOverlays();
  this.marker = undefined;
  this.layer_hash = $H();
  this.marker_hash = $H();
  this.result_index = 1;
  Element.update('results', "");
}

LayerRenderer.prototype.showMarker = function() {
  var center = this.map.getCenter();
  printfire(center);
  if (this.marker) {
    this.map.removeOverlay(this.marker);
    delete this.marker;
  }
  this.marker = new GMarker(center, {draggable: true});

  GEvent.addListener(this.marker, "dragstart", function() {
      gRenderer_.map.getInfoWindow().hide();
      });

  GEvent.addListener(this.marker, "dragend", function() {
      gRenderer_.marker.openInfoWindowHtml(
	"Click 'Get Data' <br> or drag further");
      });

  this.cancelNewPoint();

  this.map.addOverlay(this.marker);
  this.marker.openInfoWindowHtml("Drag the marker to the point of interest");
  printfire("marker added ");
}

LayerRenderer.prototype.showInfoWindow = function(rid) {
  this.cancelNewPoint();
  var marker = this.marker_hash[rid];
  if (marker) {
    printfire(marker);
    GEvent.trigger(marker, "click");
  }
}

LayerRenderer.prototype.drawPointPlacemark = function(region) {
  var point = region.coordinates[0];
  printfire(region);
  var center_point = new GLatLng(point[1], point[0]);
  var marker = new GMarker(center_point,
      {icon:this.layer_hash[region.layerid].icon } );
  this.map.addOverlay(marker);

  var rid = region.id;
  var info = "<b>" + region.name + "</b><br>" +
    (region.info?region.info:"") +
    "<br><a href=editregion.php?regionid=" + rid + ">edit</a>";

  this.marker_hash[rid] = marker;

  GEvent.addListener(marker, "click", function() {
      marker.openInfoWindowHtml(info);
      });
}

LayerRenderer.prototype.addToResult = function(region) {
  var rid = region.id;
  var layer = this.layer_hash[region.layerid];
  var res = "<br>" + this.result_index + " [" + layer.name + "] <span class='result' id='result' rid='" +rid + "'>"
    + this.regionString(region) + "</span>";
  new Insertion.Bottom('results', res);
  this.result_index++;
  printfire(res);
}

LayerRenderer.prototype.drawPolygonPlacemark = function(region) {
  printfire("polygon size " + region.coordinates.length);
  var point_array = new Array();
  for (var i = 0; i < region.coordinates.length; ++i) {
    var point = region.coordinates[i];
    // printfire(point);
    point_array.push(new GLatLng(point[1], point[0]));
  }
  var color = this.layer_hash[region.layerid].color;

  // printfire(point_array);
  // Draw the polygon on the map
  this.map.addOverlay(new GPolyline(point_array, color, 3, 1));
}

LayerRenderer.prototype.drawSingleRegion = function(region) {
  if (region.geometry == "point") {
    this.drawPointPlacemark(region);
    this.addToResult(region);
  } else if (region.geometry == "polygon") {
    this.drawPolygonPlacemark(region);
  } else {
    printfire("bad region " . region);
  }
}

LayerRenderer.prototype.regionString = function(region) {
  return region.name;
}

LayerRenderer.prototype.drawResponse = function(resp, json) {
  // printfire(resp);
  set_status('Rendering data');
  if (!json) {
    json = eval('('+resp.responseText+')');
  }
  if (json.layers) {
    this.setLayers(json.layers);
  }

  // printfire(json);
  var num_regions = 0;
  var shown_results = 0;
  if (json.regions && json.regions.length) {
    num_regions = json.regions.length;
    shown_results = num_regions;
  }
  this.result_index = 1;
  var rid_array = new Array();
  printfire("num regions " + num_regions);
  Element.update('results', "<p><div class=subtitle> Results ");
  // + shown_results + " of " + num_regions + "</div>");
  for (var i = 0; i < num_regions; ++i) {
    this.drawSingleRegion(json.regions[i], i+1);
    if (json.regions[i].geometry == "point") {
      rid_array.push(json.regions[i].id);
    }
  }
  // printfire(this.marker_hash);
  printfire("done");
  var array = $A(document.getElementsByClassName("result", "results"));
  array.each ( function(elem) {
      Event.observe(elem, 'click', result_clicked, false);
      });

  // Open the info windwow if there is only one result
  if (rid_array.length == 1) {
    printfire("single result");
    printfire(rid_array);
    this.showInfoWindow(rid_array[0]);
  }

  // Pan to the marker
  if (this.marker) {
    this.map.panTo(this.marker.getPoint());
  }

  if (num_regions == 0) {
    set_status("No matching results");
  } else {
    hide_status();
  }
}

LayerRenderer.prototype.reportError = function(request) {
  printfire('server error during fetch');
}

LayerRenderer.prototype.fetchNear = function(event) {
  var myComplete = (function(resp, json) {
      gRenderer_.drawResponse(resp, json);
      }).bind(this)

  if (this.ajax_request) {
    delete this.ajax_request;
  }

  var lobjs = document.getElementsByName('checkbox_region');
  var layers = "";
  for (var i=0; i<lobjs.length; ++i) {
    if (lobjs[i].checked) {
      layers = layers + "," + lobjs[i].value;
    }
  }
  // remove first comma
  if (layers != "") {
    layers = layers.substring(1);
  } else {
    alert("Select at least one layer to browse, or search");
    return;
  }

  var bound = this.map.getBounds();
  if (this.marker) {
    ll = this.marker.getPoint().toUrlValue() + ",0,0";
  } else {
    ll =  bound.getCenter().toUrlValue() + "," + bound.toSpan().toUrlValue();
  }
  var url = 'query.php'
  var pars = 't=fetch&ll=' + ll + "&layers=" + layers;
  this.ajax_request = new Ajax.Request(
      url, 
      { method: 'get',
	parameters: pars,
	onComplete: myComplete,
	onError: gRenderer_.reportError }
      ); 
  set_status('Fetching ... ');
  printfire("fetchNear " + pars);
  if (event)
    Event.stop(event); 
}

LayerRenderer.prototype.browse = function() {
  printfire("Browsing...");
  this.tilelayer = new GTileLayer(new GCopyrightCollection(), 0, 17);
  this.tilelayer.getTileUrl = (function(a, b) {
    // b = gRenderer_.map.maxResolution() - b;
    zoom = 17 - b;
    var path = "http://maps.google.com/mapsdt?id="
      + "http://www.vansham.com/janaagraha/blr_roads.kml&x="
      + a.x + "&y=" + a.y + "&zoom=" + zoom;
    return path;
  });
  this.tilelayer.isPng = ( function() { return true; });
  this.map.addOverlay(new GTileLayerOverlay(this.tilelayer));
}

LayerRenderer.prototype.search = function(event) {
  var myComplete = (function(resp, json) {
      gRenderer_.drawResponse(resp, json);
      }).bind(this)

  if (this.ajax_request) {
    delete this.ajax_request;
  }

  var q = $('q').value;
  var bound = this.map.getBounds();
  if (this.marker) {
    ll = this.marker.getPoint().toUrlValue() + ",0,0";
  } else {
    ll =  bound.getCenter().toUrlValue() + "," + bound.toSpan().toUrlValue();
  }
  var url = 'query.php'
  var pars = 't=search&q=' + q + '&ll=' + ll;
  this.ajax_request = new Ajax.Request(
      url, 
      { method: 'get',
	parameters: pars,
	onComplete: myComplete,
	onError: gRenderer_.reportError }
      ); 
  set_status('Searching ...');
  printfire("search " + pars);
  if (event)
    Event.stop(event); 
}

LayerRenderer.prototype.suggest = function(userText, callback) {
  if (this.ajax_request) {
    delete this.ajax_request;
  }

  var url = 'query.php'
  var pars = 'q=' + userText + '&t=suggest';
  this.ajax_request = new Ajax.Request(
      url, 
      { method: 'get',
	parameters: pars,
	onComplete: callback,
	onError: gRenderer_.reportError }
      ); 
  printfire("search " + pars);
}

LayerRenderer.prototype.send_add_point = function(layerid, callback) {
  if (this.ajax_request) {
    delete this.ajax_request;
  }

  var myComplete = (function(resp, json) {
      gRenderer_.DisplayAddPoint(resp, json);
      });

  var url = 'editlayer.php'
  var pars = 'layerid=' + layerid + '&submit=AddPoint';
  printfire("addpoint " + pars);
  this.ajax_request = new Ajax.Request(
      url, 
      { method: 'get',
	parameters: pars,
	onComplete: myComplete,
	onError: gRenderer_.reportError }
      ); 
}


LayerRenderer.prototype.DisplayAddPoint = function(resp, json) {
  printfire("Displaty add point");
  printfire(resp);
  Element.update('add_point_div', resp.responseText);

  var submit_new_point = (function(event) {
      printfire("submitting form");
      gRenderer_.submitNewPoint()
      if (event) Event.stop(event); 
      });
  var reset_new_point = (function(event) {
      gRenderer_.cancelNewPoint()
      if (event) Event.stop(event); 
      });

  Event.observe($('add_point_form'), 'submit', submit_new_point, false);
  Event.observe($('add_point_form'), 'reset', reset_new_point, false);
  this.addPointMarker();
}

LayerRenderer.prototype.submitNewPoint = function() {
  if (this.ajax_request) {
    delete this.ajax_request;
  }
  var ll = this.add_point_marker.getPoint().toUrlValue();
  var myComplete = (function(resp, json) {
      gRenderer_.newPointComplete(resp, json);
      });

  var url = 'editregion.php';
  var pars = 'll=' + ll + "&submit=AddPoint&" +
    Form.Element.serialize("add_point_layerid") + "&" +
    Form.Element.serialize("add_point_name") + "&" +
    Form.Element.serialize("add_point_info");

  printfire("submit point  " + pars);
  this.ajax_request = new Ajax.Request(
      url, 
      { method: 'get',
	parameters: pars,
	onComplete: myComplete,
	onError: gRenderer_.reportError }
      ); 
}

LayerRenderer.prototype.newPointComplete = function(resp, json) {
  printfire("New point added");
  var q = Form.Element.getValue("add_point_name");
  this.cancelNewPoint();
  $('q').value = q;
  this.search();
}

LayerRenderer.prototype.cancelNewPoint = function() {
  printfire("cancel new point");
  Element.update('add_point_div', "");
  if (this.add_point_marker) {
    this.map.removeOverlay(this.add_point_marker);
    this.map.getInfoWindow().hide();
    delete this.add_point_marker;
  }
}

LayerRenderer.prototype.cancelMarker = function() {
  if (this.marker) {
    this.map.removeOverlay(this.marker);
    this.map.getInfoWindow().hide();
    delete this.marker;
  }
}

LayerRenderer.prototype.addPointMarker = function() {
  var center = this.map.getCenter();
  printfire(center);
  if (this.add_point_marker) {
    delete this.add_point_marker;
  }
  this.add_point_marker = new GMarker(center, {draggable: true});

  GEvent.addListener(this.add_point_marker, "dragstart", function() {
      gRenderer_.map.getInfoWindow().hide();
      });

  GEvent.addListener(this.add_point_marker, "dragend", function() {
      printfire("drag ended");
      gRenderer_.add_point_marker.openInfoWindow($('add_point_form'));
      printfire("drag ended 2");
      });

  this.cancelMarker();
  this.map.addOverlay(this.add_point_marker);
  this.add_point_marker.openInfoWindow($('add_point_form'));
  printfire("marker added ");
}

