/*
 * The SResourceSearchControl is the base-class for the search controls and
 * provide a container and a set of mouse-callbacks to get notified, about user
 * activity. 
 */
var SResourceControl = Class.create();
SResourceControl.prototype = Object.extend(new GControl(), {

	initialize : function(map) {
		return this.initializeSResourceControl(map);
	},
	
	initializeSResourceControl : function(map) {
		if (!map) {
			return null;
		}
			
		this.map = map;
		this.div = document.createElement('div');
		this.div.className = 'srcc';
		
		this.div.style.width = '100%';
		this.div.style.height = '100%';
		
		var self = this;
		this.div.onmousedown = function(event) {
			self.drag = true;
			self.onMouseDown(self.getPointFromEvent(event));
		}
		
		this.div.onmousemove = function(event) {
			self.onMouseMove(self.getPointFromEvent(event));
		}
		
		this.div.onmouseup = function(event) {
			var point = self.getPointFromEvent(event)
			self.onMouseUp(point);
			self.onMouseClick(point);
			self.drag = false;
		}
		
		this.map.getContainer().appendChild(this.div);
		
		var p = Position.cumulativeOffset(this.div);
		this.divOffset = new GPoint(p[0], p[1]);
		
		return this.div;
	},
	
	/*
	 * Overwrite theese callbacks, if you wish to get notified about the
	 * mouse events on the control.
	 */
	onMouseDown : function(point) {},
	onMouseMove : function(point) {},
	onMouseUp : function(point) {},
	onMouseClick : function(point) {},
	
	getDefaultPosition : function() {
		return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0, 0));
	},
	
	getPointFromEvent : function(e) {
		var x = 0;
		var y = 0;
		if (!e) {
			var e = window.event;
		}
		if (e.pageX || e.pageY) {
			x = e.pageX;
			y = e.pageY;
		}
		else if (e.clientX || e.clientY) {
			x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		}
		
		return new GPoint(x - this.divOffset.x, y - this.divOffset.y);
	},
	
	destroy : function() {
		this.destroySResourceSearch();
	},
	
	destroySResourceSearch : function() {
		this.map.removeControl(this);
	}
});

/*
 * Use this control to provide a too to zoom in within map, by using a bounding box.
 */
var SResourceZoomInControl = Class.create();
SResourceZoomInControl.prototype = Object.extend(new SResourceControl(), {
	
	distance : 20,
	
	initialize : function(map) {
		return this.initializeSResourceZoomIn(map);
	},
	
	initializeSResourceZoomIn : function(map) {
		if (this.initializeSResourceControl(map)) {
			rControl.reset(rControl.sZoom);
			this.size = map.getSize();
		
			this.vt = document.createElement('div');
			this.vb = document.createElement('div');
			this.hl = document.createElement('div');
			this.hr = document.createElement('div');
			
			this.vt.className = 'srbbscpcv';
			this.vb.className = 'srbbscpcv';
			this.hl.className = 'srbbscpch';
			this.hr.className = 'srbbscpch';
			
			this.vt.style.display = 'none';
			this.vb.style.display = 'none';
			this.hl.style.display = 'none';
			this.hr.style.display = 'none';
			
			this.div.appendChild(this.vt);
			this.div.appendChild(this.vb);
			this.div.appendChild(this.hl);
			this.div.appendChild(this.hr);
			
			this.nwPoint = document.createElement('span');
			this.sePoint = document.createElement('span');
			
			this.nwPoint.className = 'srbbscnwp';
			this.sePoint.className = 'srbbscsep';
			this.sePoint.style.display = 'none';
			
			this.div.appendChild(this.nwPoint);
			this.div.appendChild(this.sePoint);
			
			this.initEdges();	
		}
		return this.div;
	},
	
	initEdges : function() {
		for (i = 0; i < this.size.width / this.distance; i++) {
			var edge = this.getNewEdge(i % 2);
			edge.style.top = 0 + 'px';
			edge.style.left = this.distance * i + 'px';
			this.vt.appendChild(edge);
			
			var edge = this.getNewEdge(i % 2);
			edge.style.top = 0 + 'px';
			edge.style.left = this.distance * i + 'px';
			this.vb.appendChild(edge);
		}
		for (i = 0; i < this.size.height / this.distance; i++) {
			var edge = this.getNewEdge(i % 2);
			edge.style.top = this.distance * i + 'px';
			edge.style.left = 0 + 'px';
			this.hl.appendChild(edge);
			
			var edge = this.getNewEdge(i % 2);
			edge.style.top = this.distance * i + 'px';
			edge.style.left = 0 + 'px';
			this.hr.appendChild(edge);
		} 
	},
	
	getNewEdge : function(odd) {
		var span = document.createElement('span');
		span.className = odd ? 'srbbscp-o' : 'srbbscp-e';
		return span;
	},
	
	onMouseDown : function(point) {
		/* Save North-West point */
		this.nw = point;
		this.nwPoint.style.left = point.x + 'px';
		this.nwPoint.style.top = point.y + 'px';
		this.sePoint.style.display = '';
		
		this.vt.style.display = '';
		this.vb.style.display = '';
		this.hl.style.display = '';
		this.hr.style.display = '';
	},
	
	onMouseMove : function(point) {
		if (this.drag) {
			var nw = new GPoint(
				this.nw.x <= point.x ? this.nw.x : point.x,
				this.nw.y <= point.y ? this.nw.y : point.y
			);
			
			var se = new GPoint(
				this.nw.x <= point.x ? point.x : this.nw.x,
				this.nw.y <= point.y ? point.y : this.nw.y
			);
			
			var width = se.x - nw.x;
			var height = se.y - nw.y;
			
			this.setVt(new GPoint(nw.x, nw.y), width);
			this.setHl(new GPoint(nw.x, nw.y), height);
			
			this.setVb(new GPoint(nw.x, se.y), width);
			this.setHr(new GPoint(se.x, nw.y), height);
			
			this.sePoint.style.left = point.x + 'px';
			this.sePoint.style.top = point.y + 'px';
		} else {
			this.nwPoint.style.left = point.x + 'px';
			this.nwPoint.style.top = point.y + 'px';
		}
	},
	
	onMouseUp : function(point) {
		/* Save South-East point */
		this.nw = new GPoint(
			this.nw.x <= point.x ? this.nw.x : point.x,
			this.nw.y <= point.y ? this.nw.y : point.y
		);
		
		this.se = new GPoint(
			this.nw.x <= point.x ? point.x : this.nw.x,
			this.nw.y <= point.y ? point.y : this.nw.y
		);
		
		this.onBoundingBox();
	},
	
	onBoundingBox : function() {
		this.zoomIn();
		this.map.rControl.reset();
	},
	
	zoomIn : function() {
		var bounds = new GLatLngBounds();
		bounds.extend(this.map.fromContainerPixelToLatLng(this.nw));
		bounds.extend(this.map.fromContainerPixelToLatLng(this.se));
		this.map.setCenter(bounds.getCenter(), this.map.getBoundsZoomLevel(bounds));
	},
	
	setVt : function(point, width) {
		this.vt.style.left = point.x + 'px';
		this.vt.style.top = point.y + 'px';
		this.vt.style.width = width + 'px';
	},
	
	setVb : function(point, width) {
		this.vb.style.left = point.x + 'px';
		this.vb.style.top = point.y + 'px';
		this.vb.style.width = width + 'px';
	},
	
	setHl : function(point, height) {
		this.hl.style.left = point.x + 'px';
		this.hl.style.top = point.y + 'px';
		this.hl.style.height = height + 'px';
	},
	
	setHr : function(point, height) {
		this.hr.style.left = point.x + 'px';
		this.hr.style.top = point.y + 'px';
		this.hr.style.height = height + 'px';
	}
});


var SResourceBBSearchControl = Class.create();
SResourceBBSearchControl.prototype = Object.extend(new SResourceZoomInControl(), {
	
	initialize : function(map) {
		return this.initializeSResourceBBSearch(map);
	},
	
	initializeSResourceBBSearch : function(map) {
		if (this.initializeSResourceZoomIn(map)) {
			rControl.reset(rControl.sFind);
		}
		return this.div;
	},
	
	onBoundingBox : function() {
		this.doSearch();
		this.map.rControl.reset();
	},
	
	doSearch : function() {
		var type = 'bounding_box';
		var c = this.map.fromContainerPixelToLatLng(this.nw);
		var r = this.map.fromContainerPixelToLatLng(this.se);
		coords = [{x : c.lng(), y : c.lat()}, {x : r.lng(), y : r.lat()}];
		var hash = new Hash({
			'search[geo][function]' : type,
			'search[geo][coords][][x]' : [coords[0].x, coords[1].x],
			'search[geo][coords][][y]' : [coords[0].y, coords[1].y]
		});
		this.map.rControl.find(hash);
	}
});

/*
 * The SResourceRadialSearchControl is Google Maps GControl to find resources
 * within an appropriate radius. 
 */
var SResourceRadialSearchControl = Class.create();
SResourceRadialSearchControl.prototype = Object.extend(new SResourceControl(), {
	
	drag : false,
	minEdges : 8,
	maxEdges : 72,

	initialize : function(map) {
		return this.initializeSResourceRadialSearch(map);
	},
	
	initializeSResourceRadialSearch : function(map) {
		if (this.initializeSResourceControl(map)) {
			rControl.reset(rControl.sFind);
			this.edges = new Array();
			
			for (i = 0; i < this.maxEdges; i++) {
				var span = document.createElement('span');
				span.index = i;
				span.className = (i % 2 == 0) ? 'srrscp-o' : 'srrscp-e';
				span.style.display = 'none';
				this.div.appendChild(span);
				this.edges.push(span);
			}
			
			this.cp = document.createElement('span');
			this.rp = document.createElement('span');
			this.tt = document.createElement('span');
			this.div.appendChild(this.cp);
			this.div.appendChild(this.rp);
			this.div.appendChild(this.tt);
			this.cp.className = 'srrsccp';
			this.rp.className = 'srrscrp';
			this.tt.className = 'srrsctt';
			this.rp.style.display = 'none';
			this.tt.style.display = 'none';
		}
		return this.div;
	},
	
	/*
	 * If user click the mouse down button the procedure will be started.
	 * A center point will be placed and the tooltip with the distance shows up.
	 */
	onMouseDown : function(point) {
		this.center = point;
		this.rp.style.display = '';
		this.tt.style.display = '';
	},
	
	/*
	 * By moving the mouse a circle of the edges will be drawn.
	 * Also a radius will be calculated and displayed as tooltip of the
	 * radius point.
	 */
	onMouseMove : function(point) {
		if (this.drag) {
			var self = this;
			this.placeRadiusPoint(point);
			
			with (Math) {
				var radius = floor(sqrt(pow((this.center.x - point.x), 2) + pow((this.center.y - point.y), 2)));
				var cpLatLng = this.map.fromDivPixelToLatLng(this.center);
				var rLatLng = this.map.fromDivPixelToLatLng(point);
				var text = Math.round(cpLatLng.distanceFrom(rLatLng) / 1000) + ' km';
				this.placeToolTip(point, text);
			}
			edgesCount = radius * 8 / 40;
			edgesCount = (edgesCount < this.minEdges) ? this.minEdges : ((edgesCount > this.maxEdges) ? this.maxEdges : Math.round(edgesCount));
			
			for (i = 0; i < edgesCount; i++ ) {
				var rad = this.edges[i].index * (360 / edgesCount) * (Math.PI / 180);
				this.edges[i].style.display = '';
				this.edges[i].style.left = self.center.x - 1 + radius * Math.cos(rad) + 'px';
				this.edges[i].style.top = self.center.y - 1 + radius * Math.sin(rad) + 'px';
			}
			for (i = edgesCount; i < this.maxEdges; i++) {
				this.edges[i].style.display = 'none';
			}
		} else {
			this.placeCenterPoint(point);
		}
	},
	
	/*
	 * On the mouse-up event the procedure will be finished. A search-request will be
	 * triggered and this control removed.
	 */
	onMouseUp : function(point) {
		this.radius = point;
		this.doSearch();
		this.map.rControl.reset();
	},
	
	placeCenterPoint : function(point) {
		this.cp.style.left = point.x - 3 + 'px';
		this.cp.style.top = point.y - 3 + 'px';
	},
	
	placeRadiusPoint : function(point) {
		this.rp.style.left = point.x - 3 + 'px';
		this.rp.style.top = point.y - 3 + 'px';
	},
	
	placeToolTip : function(point, text) {
		if (text) {
			this.tt.innerHTML = text;
		}
		this.tt.style.left = point.x - 30 + 'px';
		this.tt.style.top = point.y - 25 + 'px';
	},
	
	doSearch : function() {
		var type = 'radial';
		var c = this.map.fromContainerPixelToLatLng(this.center);
		var r = this.map.fromContainerPixelToLatLng(this.radius);
		coords = [{x : c.lng(), y : c.lat()}, {x : r.lng(), y : r.lat()}];
		var hash = new Hash({
			'search[geo][function]' : type,
			'search[geo][coords][][x]' : [coords[0].x, coords[1].x],
			'search[geo][coords][][y]' : [coords[0].y, coords[1].y]
		});
		this.map.rControl.find(hash);
	}
});