//<!--
//# Written by Russell Moffitt, NOAA
//# Modified Oct 2005
//# License: GPL
//-->

/*
ZoomBox requires the xbrowser (modified cross-browser.com x lib) for
the functions that handle mouse events.  Both x_core.js and x_event.js
must be imported in the HTML code before this script.
*/

//////////////////////////////////
// Begin ZoomBox class definition
//////////////////////////////////

function ZoomBox(parentLayer) {

	/* Defines the following methods:
	this.setCoords
	this.drawBox     // force draw box
	this.drawCross   // force draw cross
	this.drawCursor  // passes off to drawBox or drawCross, depending on mode
	this.showCursor  // send false arg to hide
	this.setMode     // 'box' or 'cross'
	this.setColor
	this.setJitter
	this.reset
	
	this.getParentWidth
	this.getParentHeight
	this.getTLX
	this.getTLY
	this.getBRX
	this.getBRY
	
	and the following internal elements:
	this.box (rubberband box)
	this.cross (crosshair cursor)
	this.line (vertical or horizontal line transect)
	*/
	
	this.parentLayer = document;
	if (parentLayer) this.parentLayer = xGetElementById(parentLayer);
	
	this.glass = document.createElement('div');
	this.glass.className = "zoomglass";
	this.parentLayer.insertBefore(this.glass, this.parentLayer.firstChild);
	
	this.box = document.createElement('div');
	this.box.className = "zoombox";
	xHide(this.box);
	this.parentLayer.insertBefore(this.box, this.glass.nextSibling);
	
	this.line = document.createElement('div');
	this.line.className = "zoomline_h";
	this.line.arrow1 = document.createElement('div');
	this.line.arrow1.className = "zoomarrow1";
	this.line.arrow2 = document.createElement('div');
	this.line.arrow2.className = "zoomarrow2";
	this.line.appendChild(this.line.arrow1);
	this.line.arrow1.appendChild(this.line.arrow2);
	xHide(this.line);
	this.parentLayer.insertBefore(this.line, this.glass.nextSibling);
	
	this.cross = document.createElement('div');
	this.cross.className = "zoomcross";
	xHide(this.cross);
	this.parentLayer.insertBefore(this.cross, this.glass.nextSibling);
	
	// Set this so mouse event listeners can find the zoombox from the parentLayer object
	this.parentLayer._zoombox = this;
	
	this.setJitter(5);	// Minumum valid box size for zoom
	this.setCoords(0,0,0,0);
	this.setColor('#FF0000');// Default color RED
	this.modelist = ['box', 'cross', 'line'];
	this.setMode('box');
}

ZoomBox.prototype.getParentWidth = function() {
	return(xWidth(this.parentLayer));
}

ZoomBox.prototype.getParentHeight = function() {
	return(xHeight(this.parentLayer));
}

ZoomBox.prototype.setMode = function(mode) {
	mode = mode.toLowerCase();
	if (mode == 'box') this.mode = 'box';
	if (mode == 'cross') this.mode = 'cross';
	if (mode == 'line') this.mode = 'line';
}


ZoomBox.prototype.setColor = function(color) {
	this.color = color;
	this.box.style.borderColor = this.color;
	this.line.style.borderColor = this.color;
}

ZoomBox.prototype.setJitter = function(jitter) {
	this.jitter = jitter;
}

ZoomBox.prototype.setCoords = function(x1, y1, x2, y2) {
	// Call as either setCoords(x1,y1,x2,y2) or setCoords(x1,y1)
	this.X1 = this.X2 = parseInt(x1);
	this.Y1 = this.Y2 = parseInt(y1);
	if (xDef(x2) && xDef(y2)) {
		this.X2 = parseInt(x2);
		this.Y2 = parseInt(y2);
	//alert("init +" + this.X1 + " to init +" + this.X2);
	}
}

ZoomBox.prototype.reset = function() {
	this.setCoords(0,0);
	this.showCursor(false);
}

ZoomBox.prototype.drawBox = function(x1, y1, x2, y2) {
	//this.showCursor(false);
	this.setMode('box');
	if (xDef(x1) && xDef(y1) && xDef(x2) && xDef(y2)) this.setCoords(x1, y1, x2, y2);
	var w = this.getBRX() - this.getTLX() + 1;
	var h = this.getBRY() - this.getTLY() + 1;
	xMoveTo(this.box, this.getTLX(), this.getTLY());
	if (w < 4) {
		this.box.style.width = '0px';
	} else {
		xWidth(this.box, w);
	}
	if (h < 4) {
		this.box.style.height = '0px';
	} else {
		xHeight(this.box, h);
	}
	this.showCursor();
}

ZoomBox.prototype.drawLine = function(x1, y1, x2, y2) {
	//this.showCursor(false);
	this.setMode('line');
	if (xDef(x1) && xDef(y1) && xDef(x2) && xDef(y2)) this.setCoords(x1, y1, x2, y2);
	var w = this.getBRX() - this.getTLX() + 1;
	var h = this.getBRY() - this.getTLY() + 1;
	var size = 9;
	var halfsize = Math.round(size/2);
	if (w >= h) {
		// draw horizontal line
		var y = this.Y1 - halfsize;
		this.line.style.height = '9px';
		xMoveTo(this.line, this.getTLX(), y);
		xWidth(this.line, w);
		this.line.className = "zoomline_h";
	} else {
		//draw vertical line
		var x = this.X1 - halfsize;
		this.line.style.width = '9px';
		xMoveTo(this.line, x, this.getTLY());
		xHeight(this.line, h);
		this.line.className = "zoomline_v";
	}
	this.showCursor();
}

ZoomBox.prototype.drawCross = function(x, y) {
	//this.showCursor(false);
	this.setMode('cross');
	if (xDef(x) && xDef(y)) this.setCoords(x, y);
	var xsize = xWidth(this.cross);
	var halfsize = Math.round(xsize/2);
	l = this.getBRX() - halfsize;
	t = this.getBRY() - halfsize
	xMoveTo(this.cross, l, t);
	this.showCursor();
}

ZoomBox.prototype.drawCursor = function(x1, y1, x2, y2) {
	if (this.mode == 'box') this.drawBox(x1, y1, x2, y2);
	if (this.mode == 'cross') this.drawCross(x2, y2);
	if (this.mode == 'line') this.drawLine(x1, y1, x2, y2);
}

ZoomBox.prototype.showCursor = function(showit) {
	if (!xDef(showit)) showit = true;
	if (showit) {
		if (this.mode == 'box') {
			xHide(this.cross);
			xHide(this.line);
			xShow(this.box);
		} else if (this.mode == 'cross') {
			xHide(this.box);
			xHide(this.line);
			xShow(this.cross);
		} else if (this.mode == 'line') {
			xHide(this.box);
			xHide(this.cross);
			xShow(this.line);
		}
	} else {
		xHide(this.box);
		xHide(this.cross);
		xHide(this.line);
	}
}

ZoomBox.prototype.getTLX = function() { return(Math.min(this.X1, this.X2)); }
ZoomBox.prototype.getTLY = function() { return(Math.min(this.Y1, this.Y2)); }
ZoomBox.prototype.getBRX = function() { return(Math.max(this.X2, this.X1)); }
ZoomBox.prototype.getBRY = function() { return(Math.max(this.Y2, this.Y1)); }


ZoomBox.prototype.startMouseDown = function() {
	xAddEventListener(this.parentLayer, 'mousedown', zbMouseDown, false);
	//xAddEventListener(this.glass, 'mousedown', zbMouseDown, false);
}
ZoomBox.prototype.removeMouseDown = function() {
	xRemoveEventListener(this.parentLayer, 'mousedown', zbMouseDown, false);
	//xRemoveEventListener(this.glass, 'mousedown', zbMouseDown, false);
}

//////////////////////////////////
// End ZoomBox class definition
//////////////////////////////////

//////////////////////////////////
// Example mouse event handlers
//////////////////////////////////
/*
These will work by default, but you may want to write your
own to implement custom behaviors.  Best to set write your 
own functions externally and set zoombox.onMouseDown/Move/Up
to point to your functions.  They pass the _zb object and the
current pageX/Y.  _zb contains 
  .ele (the current zoombox object)
  .pX1 .pY1 (initial pageX/Y)
  .eX1 .eY1 (initial container X/Y offset)
If you don't write your own handlers and want the default
behavior, you should write a function to attach to zoombox.onZoomEnd.
It passes the zoombox object.  It is not triggered if you set
zoombox.onMouseUp.
*/

var _zb = {ele:null, pageX1:null, pageY1:null, eX1:null, eY1:null};

function zbAddDocumentListeners() {
	xAddEventListener(document, 'mousemove', zbMouseMove, false);
	xAddEventListener(document, 'mouseup', zbMouseUp, false);
}

function zbRemoveDocumentListeners() {
	xRemoveEventListener(document, 'mousemove', zbMouseUp, false);
	xRemoveEventListener(document, 'mouseup', zbMouseUp, false);
}

function zbMouseDown(evt) {
	e = new xEvent(evt); // make cross-browser event object
	if (e.which != 1) return(true);
	xPreventDefault(evt);
	// A clear "glass" layer has been placed in front of all elements in the container.
	// We are capturing the mouse coords from the offsets from either "glass" or the parent container,
	// which should be exactly the same.  If we didn't do this, sub elements inside the
	// the parent container would be our target in some browsers, and it is way too hard
	// to determine the offset coords of a parent in different browsers, since borders and
	// such can be handled differently.  This saves us some headache.  The downside is that
	// right clicking won't give you the option of saving an image.  This needs to be addressed.
	var zoomParent = (e.target.className == 'zoomglass') ? e.target.offsetParent : e.currentTarget;
	var zoombox = zoomParent._zoombox;
	_zb.ele = zoombox; // set a global variable pointing to the active zoombox
	_zb.pX1 = e.pageX;
	_zb.pY1 = e.pageY;
	_zb.eX1 = e.offsetX;
	_zb.eY1 = e.offsetY;
	zbAddDocumentListeners();
	if (zoombox.onMouseDown) {
		zoombox.onMouseDown(_zb, e.pageX, e.pageY);
	} else {
		var x = e.offsetX;
		var y = e.offsetY;
		if (x < 0) x = 0;
		if (y < 0) y = 0;
		if (x >= zoombox.getParentWidth()) x = zoombox.getParentWidth() - 1;
		if (y >= zoombox.getParentHeight()) y = zoombox.getParentHeight() - 1;
		zoombox.reset();
		zoombox.setCoords(x, y);
		zoombox.setMode('cross');  // Start box or cross by drawing cross, draw box once mouse starts moving
		zoombox.drawCursor();
	}
}

zbMouseMove = function(evt) {
	if (_zb.ele) {
		xPreventDefault(evt);
		e = new xEvent(evt); // make cross-browser event object
		var zoombox = _zb.ele; // We have an active zoombox
		var zoomParent = zoombox.parentLayer;
		if (zoombox.onMouseMove) {
			zoombox.onMouseMove(_zb, e.pageX, e.pageY);
		} else {
			// Calculate coordinates inside zoombox container
			var x = e.pageX - _zb.pX1 + _zb.eX1;
			var y = e.pageY - _zb.pY1 + _zb.eY1;
			if (x < 0) x = 0;
			if (y < 0) y = 0;
			if (x >= zoombox.getParentWidth()) x = zoombox.getParentWidth() - 1;
			if (y >= zoombox.getParentHeight()) y = zoombox.getParentHeight() - 1;
			zoombox.setCoords(zoombox.X1, zoombox.Y1, x, y);
			zoombox.setMode('box');
			zoombox.drawCursor();
		}
	}
}

zbMouseUp = function(evt) {
	if (_zb.ele) {
		xPreventDefault(evt);
		e = new xEvent(evt); // make cross-browser event object
		var zoombox = _zb.ele; // We have an active zoombox
		var zoomParent = zoombox.parentLayer;
		zbRemoveDocumentListeners();
		if (zoombox.onMouseUp) {
			zoombox.onMouseUp(_zb, e.pageX, e.pageY);
		} else {
			// Calculate coordinates inside zoombox container
			var x = e.pageX - _zb.pX1 + _zb.eX1;
			var y = e.pageY - _zb.pY1 + _zb.eY1;
			if (x < 0) x = 0;
			if (y < 0) y = 0;
			if (x >= zoombox.getParentWidth()) x = zoombox.getParentWidth() - 1;
			if (y >= zoombox.getParentHeight()) y = zoombox.getParentHeight() - 1;
			if ((Math.abs(zoombox.X1 - x) <= zoombox.jitter) && (Math.abs(zoombox.Y1 - y) <= zoombox.jitter)) {
				// box is too small, stick to the original point and draw a cross
		 		zoombox.setCoords(zoombox.X2, zoombox.Y2, zoombox.X2, zoombox.Y2);
				zoombox.setMode('cross');
				zoombox.drawCursor(); // force cross
			} else {
				zoombox.setCoords(zoombox.X1, zoombox.Y1, x, y);
				zoombox.setMode('box');
				zoombox.drawCursor();
			}
			// Now that we've finished drawing ourself, let someone else know we're done
			if (zoombox.onZoomEnd) zoombox.onZoomEnd(zoombox);
		}
		// Disable active zoombox drawing
		_zb = {ele:null, pageX1:null, pageY1:null, eX1:null, eY1:null};

	}
}
