
/* Automatically add data to a google map from a text 
 * file in the format: 
 *          lat lon html img_url
 *
 * html: the text/html of the message to be displayed
 * when the icon is clicked
 *
 * img_url: the URL of the image to use for the icon. if empty
 * the default google red balloon will be used.
 * 
 * report bugs/questions/problems to brent:
 * bpederse@nature.berkeley.edu
 *
 * BSD license
 *
*/


/*
  USAGE:
  // make your google map
  var gmap = new GMap(document.getElementById("map"));
  gmap.addControl(new GSmallMapControl());
  gmap.centerAndZoom(new GPoint(-123.83, 40.13), 4);

  //add the overlays with the name of your file, the separator
  gmap.dataOverlay('myfile.txt',"\t");
*/

/*
   NOTE: 'myfile.txt' must be in the same directory and with 
   the correct permissions: 
      chown your_username:apache myfile.txt
*/


/* STYLE: the style of text displayed in the marker can be 
   modified within an html style sheet using 'gm'. for
   example to make the text blue:
<style>
gm {
 color: blue;
 white-space: nowrap;
}
</style>
   the 'white-space: nowrap;' line should always be included;

*/

GMap.prototype.dataOverlay = function(file,field_sep,row_sep){
   this.dataOpts.fsep = (field_sep)? field_sep: this.dataOpts.fsep;
   this.dataOpts.rsep = (row_sep)? row_sep: this.dataOpts.rsep;
   this.dataOpts.file = (file)? file: this.dataOpts.file;
   jfetch(file,this.dataOverlayHandleReturn,this);
   GEvent.addListener(this, "moveend", this.maybeRedrawMarkers);
};



/* [maxMarkers] 
   set the max number of markers so the browser doesn't 
   choke even if given a huge number of markers. values greater than 
   900 are pushing it.  400 max with shadows
*/
GMap.prototype.maxMarkers = 600;




/* [forceRedraw] 
   it's often best (and default) not to redraw after a zoom.
   google code handles (or gracefully doesn't handle--i did not
   check) the markers fine so there's usually no need to redraw;
   HOWEVER, if you have a lot of markers each with a lot of
   associated HTML, set this to 1: 'gmap.forceRedraw = 1;'
*/
GMap.prototype.forceRedraw = 0;


/*************** advanced **********************/
/* draw a shadow for the marker (dont use if you have a large
   number of markers) */
GMap.prototype.useMarkerShadow = 0;

/* url of hte image to use for the shadow it the above 
   useMarkerShadow = 1; */
GMap.prototype.markerShadowURL = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'



/***************** internal ****************************/
/*******************************************************/
/*******************************************************/
/*******************************************************/
GMap.prototype.dataOpts = { rsep: '\n' , fsep: '\t', file: 'data.txt', lastBounds: {minX:0,minY:0,maxX:0,maxY:0}}

GMap.prototype.maybeRedrawMarkers = function(){
  // only redraw if current bounds 
  // arent containd in expanded bounds

  if(this.forceRedraw){ this.redrawMarkers(); return; }
  // yes, these could be combined...
  
  var lastBounds = this.dataOpts.lastBounds;
  if(lastBounds.containsBounds(this.getBoundsLatLng())){ return; }

  this.redrawMarkers();
}

GMap.prototype.redrawMarkers = function(){
  this.clearOverlays();
  jfetch(this.dataOpts.file,this.dataOverlayHandleReturn,this);

}

GMap.prototype.resetExpandedBounds = function(){
  this.dataOpts.lastBounds = this.getExpandedBounds();
};

GMap.prototype.dataOverlayHandleReturn = function(){

   var result = arguments[0];
   var opts = this.dataOpts;

   this.resetExpandedBounds();

   var arr = result.split(opts.rsep);
   if(arr.length > this.maxMarkers){ arr=arr.slice(0,this.maxMarkers) }

   var row;

   while(row=arr.shift()){
      if(row.indexOf('#')== 0){continue;}
      if(row.match(/^\s+$/)){continue;}
      row = row.split(opts.fsep);
      if(this.inExpandedBounds({lon: parseFloat(row[1]),lat: parseFloat(row[0])} ,this.dataOpts.lastBounds)) {
        var pt = new GPoint(parseFloat(row[1]),parseFloat(row[0]));
        var info = '<gm>' + row[2] + '</gm>';
        var img = (row[3])?row[3]:'';
        var marker = this._createMarker(pt,info,img);
        this.addOverlay(marker);
        
      }
   }
};  

GMap.prototype.inExpandedBounds = function(LngLat,bounds){
   lat = LngLat.lat;
   lon = LngLat.lon;
   if(   lat > bounds.minY && lat < bounds.maxY && lon > bounds.minX
   && lon < bounds.maxX){ return true;}
   return false;
};

GMap.prototype.getExpandedBounds = function(){
  var bounds = this.getBoundsLatLng();
  var extent = (bounds.maxX - bounds.minX)/3;
  bounds.minX -= extent;
  bounds.maxX += extent;
  bounds.minY -= extent;
  bounds.maxY += extent;
  return bounds;
};
  
GMap.prototype._createMarker = function(point, html,img) {
  var icon;
  var arr = [];  
  if(img){
    icon = new GIcon();
    icon.image = img;
    var ii = document.createElement('img');
    ii.src = img;
    arr[0]=ii;
    var w = ii.width;
    var h = ii.height;
    icon.iconSize=new GSize(w,h);

    if(this.useMarkerShadow){
      icon.shadow= this.markerShadowURL;
      icon.shadowSize = new GSize(w,20);
    }

    icon.iconAnchor = new GPoint(w/2, h);
    icon.infoWindowAnchor = new GPoint(w/2, 0);
  }

  var marker;
  if(icon){ marker = new GMarker(point,icon);}
  else {    marker = new GMarker(point); } 

  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml(html);
  });
  return marker;
};


/* it's AJAX yo

USAGE:
to return the result to an html element:
onclick=jfetch('script.pl?var=something','elem_id');
to return the result to a javascript fuction:
onblur=jfetch('script.php?n=1234',jsFunc);
*/

function jfetch(url,target,context) {
  var req = (typeof XMLHttpRequest!= 'undefined' )?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");
  req.open("GET",url,true);
  req.onreadystatechange = function() {
    if(req.readyState == 4){
      var rsp = req.responseText;
      if(target.constructor == Function){
        target.call(context,rsp);
      }else{
        var t = document.getElementById(target);
        if(t.value==undefined){t.innerHTML=rsp;}else{t.value=rsp;}
      }
    }
  };
  req.send(null);
}

