/*
Copyright (c) 2005-2006, Andre Lewis, andre@earthcode.com
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided 
that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of "Andre Lewis" nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
GZoom custom map control

To use:
  oMap = new GMap2($id("large-google-map"));	
  oMap.addControl(new GMapTypeControl());

Or with options:
  oMap.addControl(new GZoomControl({sColor:'#000',nOpacity:.3,sBorder:'1px solid yellow'}), new GControlPosition(G_ANCHOR_TOP_RIGHT,new GSize(10,10)));

More info at http://earthcode.com
*/

// base definition and inheritance
function GZoomControl(oOptions) {
  GZoomControl.G.style = {
    nOpacity:.2,
    sColor:"#000",
    sBorder:"2px solid blue"
  };
  var style=GZoomControl.G.style;
  for (var s in oOptions) {style[s]=oOptions[s]};
  var aStyle=style.sBorder.split(' ');
  style.nOutlineWidth=parseInt(aStyle[0].replace(/\D/g,''));
  style.sOutlineColor=aStyle[2];
  style.sIEAlpha='alpha(opacity='+(style.nOpacity*100)+')';
}

GZoomControl.prototype = new GControl();

//class globals
GZoomControl.G={
  bDragging:false,
  mct:null,
  mcr:null,
  mcb:null,
  mcl:null,
	oMapPos:null,
	oOutline:null,
	nMapWidth:0,
	nMapHeight:0,
	nMapRatio:0,
	nStartX:0,
	nStartY:0,
	nBorderCorrect:0
};


// ******************************************************************************************
// Methods required by Google maps -- initialize and getDefaultPosition
// ******************************************************************************************
GZoomControl.prototype.initialize = function(oMap) {
  //DOM:button
	var oMC=oMap.getContainer();
	var oButton = document.createElement('div');
	oButton.appendChild(document.createTextNode('zoom...'));
	oButton.id='gzoom-control';
	//DOM:map covers
	acl.style([oButton],{width:'52px',cursor:'pointer',background:'#fff',border:'1px solid black',padding:'0px 5px 1px 5px',zIndex:200});
	oMC.appendChild(oButton);
	var o = document.createElement("div");
  o.id='gzoom-map-cover';
	o.innerHTML='<div id="gzoom-outline" style="position:absolute;display:none;"></div><div id="gzoom-mct" style="position:absolute;display:none;"></div><div id="gzoom-mcl" style="position:absolute;display:none;"></div><div id="gzoom-mcr" style="position:absolute;display:none;"></div><div id="gzoom-mcb" style="position:absolute;display:none;"></div>';
	acl.style([o],{position:'absolute',display:'none',overflow:'hidden',cursor:'crosshair',zIndex:101});
	oMC.appendChild(o);

  // add event listeners
	GEvent.addDomListener(oButton, 'click', GZoomControl.prototype.initCover_);
	GEvent.addDomListener(o, 'mousedown', GZoomControl.prototype.coverMousedown_);
	GEvent.addDomListener(document, 'mousemove', GZoomControl.prototype.drag_);
	GEvent.addDomListener(document, 'mouseup', GZoomControl.prototype.mouseup_);

  // get globals
  var G=GZoomControl.G;
	G.oMapPos=acl.getElementPosition(oMap.getContainer());
	G.oOutline=$id("gzoom-outline");	
	G.oButton=$id("gzoom-control");
	G.mc=$id("gzoom-map-cover");
	G.mct=$id("gzoom-mct");
	G.mcr=$id("gzoom-mcr");
	G.mcb=$id("gzoom-mcb");
	G.mcl=$id("gzoom-mcl");
	G.oMap = oMap;

	G.nBorderCorrect = G.style.nOutlineWidth*2;	
  this.setDimensions_();

  //styles
  this.initStyles_();
  /*G.mct.style.background='red';G.mcr.style.background='yellow';G.mcb.style.background='blue';*/

  debug("Finished Initializing gzoom control");  
  return oButton;
};

// Default location for the control
GZoomControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(3, 280));
};

// ******************************************************************************************
// Private methods
// ******************************************************************************************
GZoomControl.prototype.coverMousedown_ = function(e){
  var G=GZoomControl.G;
  var oPos = GZoomControl.prototype.getRelPos_(e);
  debug("Mouse down at "+oPos.left+", "+oPos.top);
  G.nStartX=oPos.left;
  G.nStartY=oPos.top;
  
	acl.style([G.mc],{background:'transparent',opacity:1,filter:'alpha(opacity=100)'});
  acl.style([G.oOutline],{left:G.nStartX+'px',top:G.nStartY+'px',display:'block',width:'1px',height:'1px'});
  G.bDragging=true;

  G.mct.style.top=(G.nStartY-G.nMapHeight)+'px';
  G.mct.style.display='block';
  G.mcl.style.left=(G.nStartX-G.nMapWidth)+'px';
  G.mcl.style.top=(G.nStartY)+'px';
  G.mcl.style.display='block';

  G.mcr.style.left=(G.nStartX)+'px';
  G.mcr.style.top=(G.nStartY)+'px';
  G.mcr.style.display='block';
  G.mcb.style.left=(G.nStartX)+'px';
  G.mcb.style.top=(G.nStartY)+'px';
  G.mcb.style.width='0px';
  G.mcb.style.display='block';

  debug("mouse down done");
  return false;
};

GZoomControl.prototype.drag_=function(e){
  var G=GZoomControl.G;
  if(G.bDragging) {
    var oPos=GZoomControl.prototype.getRelPos_(e);
    oRec = GZoomControl.prototype.getRectangle_(G.nStartX,G.nStartY,oPos,G.nMapRatio);
    G.oOutline.style.width=oRec.nWidth+"px";
    G.oOutline.style.height=oRec.nHeight+"px";
    
    G.mcr.style.left=(oRec.nEndX+G.nBorderCorrect)+'px';
    G.mcb.style.top=(oRec.nEndY+G.nBorderCorrect)+'px';
    G.mcb.style.width=(oRec.nWidth+G.nBorderCorrect)+'px';
    return false;
  }  
};
GZoomControl.prototype.mouseup_=function(e){
  var G=GZoomControl.G;
  if (G.bDragging) {
    var oPos = GZoomControl.prototype.getRelPos_(e);
    G.bDragging=false;
    
    var oRec = GZoomControl.prototype.getRectangle_(G.nStartX,G.nStartY,oPos,G.nMapRatio);
    debug("mouse up at "+oRec.nEndX+", "+oRec.nEndY+". Height/width="+oRec.nWidth+","+oRec.nHeight); 

    GZoomControl.prototype.resetDragZoom_();

    sw = G.oMap.fromContainerPixelToLatLng(new GPoint(oRec.nStartX,oRec.nEndY) ); 
    ne = G.oMap.fromContainerPixelToLatLng(new GPoint(oRec.nEndX,oRec.nStartY) ); 
    
    nw = G.oMap.fromContainerPixelToLatLng(new GPoint(oRec.nStartX,oRec.nStartY) ); 
    se = G.oMap.fromContainerPixelToLatLng(new GPoint(oRec.nEndX,oRec.nEndY) ); 
    var oZoomArea = new GPolyline([nw,ne,se,sw,nw],G.style.sOutlineColor,G.style.nOutlineWidth+1,.4);
    try{
      G.oMap.addOverlay(oZoomArea);
      setTimeout (function(){G.oMap.removeOverlay(oZoomArea)},6000);      
    }catch(e){
      jslog.error("error adding zoomarea overlay:"+e.message);
    }
    
    oBounds=new GLatLngBounds(sw,ne);
    nZoom=G.oMap.getBoundsZoomLevel(oBounds);
    oCenter=oBounds.getCenter();
    G.oMap.setCenter(oCenter, nZoom);
  }
};

// set the cover sizes according to the size of the map
GZoomControl.prototype.setDimensions_=function() {
  var G=GZoomControl.G;
  var oSize = G.oMap.getSize();
  G.nMapWidth  = oSize.width;
  G.nMapHeight = oSize.height;
  G.nMapRatio  = G.nMapHeight/G.nMapWidth;
	acl.style([G.mc,G.mct,G.mcr,G.mcb,G.mcl],{width:G.nMapWidth+'px', height:G.nMapHeight+'px'});
};

GZoomControl.prototype.initStyles_=function(){
  var G=GZoomControl.G;
	acl.style([G.mc,G.mct,G.mcr,G.mcb,G.mcl],{filter:G.style.sIEAlpha,opacity:G.style.nOpacity,background:G.style.sColor});
  G.oOutline.style.border=G.style.sBorder;  
  debug("done initStyles_");	
};

GZoomControl.prototype.initCover_=function(){
  var G=GZoomControl.G;
  if (G.mc.style.display=='block'){ // reset if clicked before dragging
    GZoomControl.prototype.resetDragZoom_();
  } else {
    G.oButton.innerHTML='Drag a region on the map';
  	G.oButton.style.background='#ff0';
  	acl.style([G.mc],{display:'block',background:G.style.sColor});
    debug("done initCover_");
  }
};

GZoomControl.prototype.getRelPos_=function(e) {
  var oPos=acl.getMousePosition (e);
  var G=GZoomControl.G;
  return {top:(oPos.top-G.oMapPos.top),left:(oPos.left-G.oMapPos.left)};
};

GZoomControl.prototype.getRectangle_=function(nStartX,nStartY,oPos,nRatio){
	var dX=oPos.left-nStartX;
	var dY=oPos.top-nStartY;
	if (dX <0) dX =dX*-1;
	if (dY <0) dY =dY*-1;
	delta = dX > dY ? dX : dY;

  return {
    nStartX:nStartX,
    nStartY:nStartY,
    nEndX:nStartX+delta,
    nEndY:nStartY+parseInt(delta*nRatio),
    nWidth:delta,
    nHeight:parseInt(delta*nRatio)
  }
};

GZoomControl.prototype.resetDragZoom_=function() {
	var G=GZoomControl.G;
	acl.style([G.mc,G.mct,G.mcr,G.mcb,G.mcl],{display:'none',opacity:G.style.nOpacity,filter:G.style.sIEAlpha});
	G.oOutline.style.display='none';	
	G.oButton.innerHTML='zoom...';
	G.oButton.style.background='white';
  debug("done with reset drag zoom");
};

/* alias get element by id */
function $id(sId) { return document.getElementById(sId); }
/* utility functions in acl namespace */
if (!window['acldefined']) {var acl={};window['acldefined']=true;}//only set the acl namespace once, then set a flag

/* A general-purpose function to get the absolute position of
the mouse */
acl.getMousePosition=function(e) {
	var posx = 0;
	var posy = 0;
	if (!e) var e = window.event;
	if (e.pageX || e.pageY) {
		posx = e.pageX;
		posy = e.pageY;
	} else if (e.clientX || e.clientY){
		posx = e.clientX + (document.documentElement.scrollLeft?document.documentElement.scrollLeft:document.body.scrollLeft);
		posy = e.clientY + (document.documentElement.scrollTop?document.documentElement.scrollTop:document.body.scrollTop);
	}	
	return {left:posx, top:posy};  
};

/*
To Use: 
	var pos = acl.getElementPosition(element);
	var left = pos.left;
	var top = pos.top;
*/
acl.getElementPosition=function(eElement) {
		var nLeftPos = eElement.offsetLeft;          // initialize var to store calculations
	var nTopPos = eElement.offsetTop;            // initialize var to store calculations
	var eParElement = eElement.offsetParent;     // identify first offset parent element  
	while (eParElement != null ) {                // move up through element hierarchy
				nLeftPos += eParElement.offsetLeft;      // appending left offset of each parent
				nTopPos += eParElement.offsetTop;  
				eParElement = eParElement.offsetParent;  // until no more offset parents exist
		}
		return {left:nLeftPos, top:nTopPos};
};
//elements is either a coma-delimited list of ids or an array of DOM objects. o is a hash of styles to be applied
//example: style('d1,d2',{color:'yellow'});  
acl.style=function(a,o){
	if (typeof(a)=='string') {a=acl.getManyElements(a);}
	for (var i=0;i<a.length;i++){
		for (var s in o) { a[i].style[s]=o[s];}
	}
};
acl.getManyElements=function(s){		
	t=s.split(',');
	a=[];
	for (var i=0;i<t.length;i++){a[a.length]=$id(t[i])};
	return a;
};
	
var jslog = {debug:function(){},info:function(){}, 
	warning:function(){}, error:function(){},
	text:function(){}}; var debug=function(){};
if (location.href.match(/enablejslog/)){
		document.write('<script type="text/javascript" src="http://earthcode.com/include/javascripts/jslog.js"></script>');};	

