/*
 * Filename: GImageOverlay.js
 * Description: Contains a class for positioning an image in Google Maps.
 * Last Modified: 2008-04-29 14:58 PST
 * Author: Paul Reuter
 * Version: 1.2
 *
 * (C) 2008 Regents of the University of California
 *                All Rights Reserved
 *
 * Branch of v1.1.
 */


/*
 * Motivation:
 * Ever want to overlay an image strictly as an image,
 * not as a GGroundOverlay?  Well, this allows you to do so,
 * and also provides an API for querying bounds once you've
 * established position.
 */


function GImageOverlay(imgUrl, bounds, opacity) { 
  this.bounds_ = bounds;
  this.imgUrl_ = imgUrl;
  this.opacity_ = opacity || 0.75;
  this.img_ = null;
  this.map_ = null;
  this.div_ = null;
  this.markers = [ [null,null,null],[null,null,null],[null,null,null] ];

  this.width  = null;  // Actual width of image
  this.height = null;  // Actual height of image

  this.bShowResize = false; // Show the resize markers
  this.bShowMove   = false; // Show the draw/move marker
}
GImageOverlay.prototype = new GOverlay();


GImageOverlay.prototype.initialize = function(map) { 
  this.map_ = map;

  var gio = this;
  var div = document.createElement("div");
  div.style.position = "absolute";

  var img = document.createElement("img");
  img.setAttribute("src",this.imgUrl_);
  img.setAttribute("border",0);
  img.style.zIndex = "2";
  img.onload = function() { 
    gio.width  = this.width;
    gio.height = this.height;
    GEvent.trigger(gio,'loaded',img);
    img.setAttribute("width","100%");
    img.setAttribute("height","100%");
  };

  div.style.opacity = this.opacity_;
  div.style.filter = "alpha(opacity="+(this.opacity_*100)+")";

  div.appendChild(img);
  map.getPane(G_MAP_MAP_PANE).appendChild(div);

  this.img_ = img;
  this.div_ = div;


  // -----------------------
  // Add control markers
  // -----------------------

  var bb = this.getBounds();
  var ct = this.getImageCenter();
  var sw = bb.getSouthWest();
  var ne = bb.getNorthEast();
  var se = new GLatLng(sw.lat(),ne.lng());
  var nw = new GLatLng(ne.lat(),sw.lng());

  var ic = new GIcon();
    ic.shadow      = null;
    ic.shadowSize  = null;
    ic.printImage  = null;
    ic.printShadow = null;
    ic.transparent = null;
    ic.imageMap    = null;
    ic.maxHeight   = 0; // marker will rise this number of pixels on drag
    ic.mozPrintImage    = null;
    ic.dragCrossImage   = null;
    ic.infoWindowAnchor = null;

  var opts = {
    draggable:true,dragCrossMove:false,bouncy:false,
    autoPan:true,clickable:false,title:"Move Image"
  };

  // Center marker: Pan/move
  opts["icon"] = new GIcon(ic,'img/ic/mm.png');
  opts["icon"].iconSize = new GSize(40,36);
  opts["icon"].iconAnchor = new GPoint(20,18);

  gio.markers[1][1] = new GMarker(this.getImageCenter(),opts);
  GEvent.addListener(gio.markers[1][1],'drag',function() {
    // alert("drag: "+gio.markers[1][1].getLatLng().lat());
    gio.setImageCenter(gio.markers[1][1].getLatLng());
  });
  GEvent.addListener(gio.markers[1][1],'dragstart',function() { 
    // alert("start: "+gio.markers[1][1].getLatLng().lat());
  });
  GEvent.addListener(gio.markers[1][1],'dragend',function() { 
    // alert("end: "+gio.markers[1][1].getLatLng().lat());
    GEvent.trigger(gio.markers[1][1],'drag');
  });
  map.addOverlay(gio.markers[1][1]);
  // END: Center marker


  // -----------------------
  // Corner markers
  // -----------------------

  opts["title"] = "Resize Image";

  // Top-Left Corner
  opts["icon"] = new GIcon(ic,'img/ic/tl.png');
  opts["icon"].iconSize = new GSize(6,6);
  opts["icon"].iconAnchor = new GPoint(0,0);

  gio.markers[0][0] = new GMarker(nw,opts);
  GEvent.addListener(gio.markers[0][0],'drag',function() {
    var sw = gio.bounds_.getSouthWest();
    var ne = gio.bounds_.getNorthEast();
    var tl = gio.markers[0][0].getLatLng();
    gio.setBounds(tl.lat(),ne.lng(),sw.lat(),tl.lng());
  });
  map.addOverlay(gio.markers[0][0]);

  // Top-Right Corner
  opts["icon"] = new GIcon(ic,'img/ic/tr.png');
  opts["icon"].iconSize = new GSize(6,6);
  opts["icon"].iconAnchor = new GPoint(5,0);

  gio.markers[0][2] = new GMarker(ne,opts);
  GEvent.addListener(gio.markers[0][2],'drag',function() {
    gio.setBounds(gio.bounds_.getSouthWest(),gio.markers[0][2].getLatLng());
  });
  map.addOverlay(gio.markers[0][2]);

  // Bottom-Left Corner
  opts["icon"] = new GIcon(ic,'img/ic/bl.png');
  opts["icon"].iconSize = new GSize(6,6);
  opts["icon"].iconAnchor = new GPoint(0,5);

  gio.markers[2][0] = new GMarker(sw,opts);
  GEvent.addListener(gio.markers[2][0],'drag',function() {
    gio.setBounds(gio.markers[2][0].getLatLng(),gio.bounds_.getNorthEast());
  });
  map.addOverlay(gio.markers[2][0]);

  // Bottom-Right Corner
  opts["icon"] = new GIcon(ic,'img/ic/br.png');
  opts["icon"].iconSize = new GSize(6,6);
  opts["icon"].iconAnchor = new GPoint(5,5);

  gio.markers[2][2] = new GMarker(se,opts);
  GEvent.addListener(gio.markers[2][2],'drag',function() {
    var sw = gio.bounds_.getSouthWest();
    var ne = gio.bounds_.getNorthEast();
    var br = gio.markers[2][2].getLatLng();
    gio.setBounds(ne.lat(),br.lng(),br.lat(),sw.lng());
  });
  map.addOverlay(gio.markers[2][2]);


  // -----------------------
  // Edge markers
  // -----------------------

  // Top edge
  opts["icon"] = new GIcon(ic,'img/ic/tm.png');
  opts["icon"].iconSize = new GSize(8,5);
  opts["icon"].iconAnchor = new GPoint(4,0);

  var pt = new GLatLng(ne.lat(),ct.lng());
  gio.markers[0][1] = new GMarker(pt,opts);
  GEvent.addListener(gio.markers[0][1],'drag',function() {
    var ct = gio.getImageCenter();
    var pt = gio.markers[0][1].getLatLng();
    gio.markers[0][1].setLatLng(new GLatLng(pt.lat(),ct.lng()));
    gio.setNorth(pt.lat());
  });
  map.addOverlay(gio.markers[0][1]);

  // Bottom edge
  opts["icon"] = new GIcon(ic,'img/ic/bm.png');
  opts["icon"].iconSize = new GSize(8,5);
  opts["icon"].iconAnchor = new GPoint(4,4);

  var pt = new GLatLng(sw.lat(),ct.lng());
  gio.markers[2][1] = new GMarker(pt,opts);
  GEvent.addListener(gio.markers[2][1],'drag',function() {
    var ct = gio.getImageCenter();
    var pt = gio.markers[2][1].getLatLng();
    gio.markers[2][1].setLatLng(new GLatLng(pt.lat(),ct.lng()));
    gio.setSouth(pt.lat());
  });
  map.addOverlay(gio.markers[2][1]);


  // Left edge
  opts["icon"] = new GIcon(ic,'img/ic/ml.png');
  opts["icon"].iconSize = new GSize(5,8);
  opts["icon"].iconAnchor = new GPoint(0,4);

  var pt = new GLatLng(ct.lat(),sw.lng());
  gio.markers[1][0] = new GMarker(pt,opts);
  GEvent.addListener(gio.markers[1][0],'drag',function() {
    var ct = gio.getImageCenter();
    var pt = gio.markers[1][0].getLatLng();
    gio.markers[1][0].setLatLng(new GLatLng(ct.lat(),pt.lng()));
    gio.setWest(pt.lng());
  });
  map.addOverlay(gio.markers[1][0]);

  // Right edge
  opts["icon"] = new GIcon(ic,'img/ic/mr.png');
  opts["icon"].iconSize = new GSize(5,8);
  opts["icon"].iconAnchor = new GPoint(5,4);

  var pt = new GLatLng(ct.lat(),ne.lng());
  gio.markers[1][2] = new GMarker(pt,opts);
  GEvent.addListener(gio.markers[1][2],'drag',function() {
    var ct = gio.getImageCenter();
    var pt = gio.markers[1][2].getLatLng();
    gio.markers[1][2].setLatLng(new GLatLng(ct.lat(),pt.lng()));
    gio.setEast(pt.lng());
  });
  map.addOverlay(gio.markers[1][2]);

  if( !this.bShowMove ) { 
    gio.markers[1][1].hide();
  }
  if( !this.bShowResize ) { 
    gio.markers[0][0].hide();
    gio.markers[0][1].hide();
    gio.markers[0][2].hide();
    gio.markers[1][0].hide();
    gio.markers[1][2].hide();
    gio.markers[2][0].hide();
    gio.markers[2][1].hide();
    gio.markers[2][2].hide();
  }
}

GImageOverlay.prototype.remove = function() { 
  if( !this.div_ ) { 
    return;
  }
  // TODO: recursive removeChild
  this.div_.removeChild(this.img_);
  this.div_.parentNode.removeChild(this.div_);
}

GImageOverlay.prototype.copy = function() { 
  return new GImageOverlay(this.imgUrl_,this.bounds_);
}


GImageOverlay.prototype.redraw = function(force) { 
  if( !force || !this.map_ ) {
    return;
  }

  var bb = this.getBounds();
  var ct = this.getImageCenter();
  var sw = bb.getSouthWest();
  var ne = bb.getNorthEast();
  var se = new GLatLng(sw.lat(),ne.lng());
  var nw = new GLatLng(ne.lat(),sw.lng());

  var c1 = this.map_.fromLatLngToDivPixel(sw);
  var c2 = this.map_.fromLatLngToDivPixel(ne);

  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.width  = Math.abs(c2.x - c1.x) + "px";
  this.div_.style.height = Math.abs(c2.y - c1.y) + "px";
  this.img_.style.width  = Math.abs(c2.x - c1.x) + "px";
  this.img_.style.height = Math.abs(c2.y - c1.y) + "px";
  this.div_.style.left   = Math.min(c2.x, c1.x) + "px";
  this.div_.style.top    = Math.min(c2.y, c1.y) + "px";

  this.markers[0][0].setLatLng(nw);
  this.markers[0][1].setLatLng(new GLatLng(ne.lat(),ct.lng()));
  this.markers[0][2].setLatLng(ne);
  this.markers[2][0].setLatLng(sw);
  this.markers[2][1].setLatLng(new GLatLng(sw.lat(),ct.lng()));
  this.markers[2][2].setLatLng(se);
  this.markers[1][0].setLatLng(new GLatLng(ct.lat(),sw.lng()));
  this.markers[1][1].setLatLng(ct);
  this.markers[1][2].setLatLng(new GLatLng(ct.lat(),ne.lng()));
}



GImageOverlay.prototype.getImageUrl = function() { 
  return this.imgUrl_;
}

GImageOverlay.prototype.setImageUrl = function(imgUrl) { 
  this.img_.removeAttribute("width");
  this.img_.removeAttribute("height");
  this.imgUrl_ = imgUrl;
  this.img_.setAttribute("src",imgUrl);
}

GImageOverlay.prototype.getOpacity = function() { 
  return this.opacity_;
}

GImageOverlay.prototype.setOpacity = function(opacity) { 
  this.opacity_ = (opacity>1) ? opacity/100 : (opacity<0) ? 0 : opacity;
  this.div_.style.opacity = this.opacity_;
  this.div_.style.filter = "alpha(opacity="+opacity+")";
}

GImageOverlay.prototype.getCenter = function() { 
  return this.bounds_.getCenter();
}

GImageOverlay.prototype.getImageCenter = function() { 
  var bb = this.getBounds();

  var c1 = this.map_.fromLatLngToDivPixel(bb.getSouthWest());
  var c2 = this.map_.fromLatLngToDivPixel(bb.getNorthEast());
  var sx = Math.abs(c2.x-c1.x);
  var sy = Math.abs(c1.y-c2.y);

  // new center point: [ w+sx/2 , s+sy/2 ]
  var nc = new GPoint(c1.x+(sx/2),c1.y-(sy/2));
  return this.map_.fromDivPixelToLatLng(nc);
}

/*
 * setCenter: assigns latlng as the center of the bounds... 
 * Not to be confused with setImageCenter, which assigns the
 *   center pixel to the latlng.
 */
GImageOverlay.prototype.setCenter = function(latlng) { 
  var bb = this.getBounds();
  var db = bb.toSpan();
  var ht = db.lat()/2; // half lat
  var hg = db.lng()/2; // half lng
  var sw = new GLatLng(latlng.lat()-ht, latlng.lng()-hg);
  var ne = new GLatLng(latlng.lat()+ht, latlng.lng()+hg);
  this.setBounds(sw,ne);
  return true;
}

GImageOverlay.prototype.setImageCenter = function(latlng) { 
  var old = this.getImageCenter();
  var bb = this.getBounds();

  var c0 = this.map_.fromLatLngToDivPixel(latlng);
  var c1 = this.map_.fromLatLngToDivPixel(bb.getSouthWest());
  var c2 = this.map_.fromLatLngToDivPixel(bb.getNorthEast());

  var sx = Math.abs(c2.x-c1.x);
  var sy = Math.abs(c1.y-c2.y);

  var d1 = new GPoint(c0.x-(sx/2),c0.y+(sy/2));
  var d2 = new GPoint(d1.x+sx,d1.y-sy);

  var sw = this.map_.fromDivPixelToLatLng(d1);
  var ne = this.map_.fromDivPixelToLatLng(d2);
  this.setBounds(sw,ne);
  GEvent.trigger(this,'move',latlng,old);
  return true;
}


GImageOverlay.prototype.setImageSize = function(w,h) { 
  if( typeof(w) == "number" && typeof(h) == "number" ) { 
    this.width = w;
    this.height = h;
    return true;
  }
  if( typeof(w) != "object" ) { 
    return false;
  }
  this.width = w.width;
  this.height = w.height;
  return true;
}

GImageOverlay.prototype.getImageSize = function() { 
  return new GSize(this.width,this.height);
}


GImageOverlay.prototype.getOverlaySize = function() { 
  var bb = this.getBounds();
  var c1 = this.map_.fromLatLngToDivPixel(bb.getSouthWest());
  var c2 = this.map_.fromLatLngToDivPixel(bb.getNorthEast());
  var sx = Math.abs(c2.x-c1.x);
  var sy = Math.abs(c1.y-c2.y);
  return new GSize(sx,sy);
}

GImageOverlay.prototype.setOverlaySize = function(size,height) { 
  if( typeof(size) == "number" && typeof(height) == "number" ) { 
    size = new GSize(size,height);
  }
  if( typeof(size) != "object" ) { 
    return false;
  }
  var oldSize   = this.getOverlaySize();
  var oldBounds = this.getBounds();

  var sx = size.width;
  var sy = size.height;
  var bb = this.getBounds();

  // pixel coord of old ctr
  var c = this.map_.fromLatLngToDivPixel(this.getImageCenter());
  var d1 = new GPoint(c.x-sx/2,c.y+sy/2);
  var d2 = new GPoint(d1.x+sx,d1.y-sy);
  var sw = this.map_.fromDivPixelToLatLng(d1);
  var ne = this.map_.fromDivPixelToLatLng(d2);
  this.setBounds(sw,ne);
  GEvent.trigger(this,'resize',size,this.getBounds(),oldSize,oldBounds);
  return true;
}

GImageOverlay.prototype.getBounds = function() { 
  return this.bounds_;
}

GImageOverlay.prototype.setBounds = function(n,e,s,w) { 
  var old = this.bounds_;
  if( !s && !w ) { 
    if( !e ) {
      // User provided GLatLngBounds
      // ie: n -> bounds
      this.bounds_ = n;
    } else { 
      // User provided (sw, ne)
      // ie: n -> sw, e -> ne
      this.bounds_ = new GLatLngBounds(n,e);
    }
  } else {
    var sw = new GLatLng(s,w);
    var ne = new GLatLng(n,e);
    this.bounds_ = new GLatLngBounds(sw,ne);
  }
  this.redraw(1);
  GEvent.trigger(this,'bounds',this.bounds_,old);
  return true;
}
GImageOverlay.prototype.setNorth = function(n) { 
  var sw = this.bounds_.getSouthWest();
  var ne = this.bounds_.getNorthEast();
  ne = new GLatLng(n, ne.lng());
  this.setBounds(sw,ne);
}
GImageOverlay.prototype.setSouth = function(s) { 
  var sw = this.bounds_.getSouthWest();
  var ne = this.bounds_.getNorthEast();
  sw = new GLatLng(s, sw.lng());
  this.setBounds(sw,ne);
}
GImageOverlay.prototype.setEast = function(e) { 
  var sw = this.bounds_.getSouthWest();
  var ne = this.bounds_.getNorthEast();
  ne = new GLatLng(ne.lat(),e);
  this.setBounds(sw,ne);
}
GImageOverlay.prototype.setWest = function(w) { 
  var sw = this.bounds_.getSouthWest();
  var ne = this.bounds_.getNorthEast();
  sw = new GLatLng(sw.lat(),w);
  this.setBounds(sw,ne);
}

GImageOverlay.prototype.resizable = function(b) { 
  this.bShowResize = (typeof(b) == "undefined" || b) ? true : false;
}
GImageOverlay.prototype.movable = function(b) { 
  this.bShowMove = (typeof(b) == "undefined" || b) ? true : false;
}

// TODO: API for resize, move.
// TODO: resizeTo(GSize), moveToPoint(GPoint), moveToLatLng(GLatLng)
