/* ======= Constructor ======= */

function Geo() {};

/* ======= PUBLIC attributes and methods ======= */

Geo.prototype.mode = "point"; // polyline | polygon | points | point
Geo.prototype.fillColor = "#0000FF"; // blue fill
Geo.prototype.fillColorArray = ["#0000FF","#F00","#00FF1C","#FDFF00","#FB00FF"];
Geo.prototype.lineColor = "#000000"; // black line
Geo.prototype.opacity = 0.5;
Geo.prototype.lineWeight = 2;
Geo.prototype.centerLat = 57.703138
Geo.prototype.centerLng = 11.992865;
Geo.prototype.zoom = 12;
Geo.prototype.polygonDepth = "20";
Geo.prototype.mapId = ""; // id of the div which holds the map
Geo.prototype.dataField = null; // obj of the hidden field in dynamaster which holds the KML-string

/**
 * intraInit() initializes a map within the dynamaster intra
 * @args: (obj) JSON-object with attributes which will be merged into this instance
 * @mapId: (string) div-id which holds the map
 * @dataField: (DOM-obj) hidden input field in dynamaster which holds the data
 * @inputPrefix: (string) prefix for all form input field ids
 */
Geo.prototype.intraInit = function(inputPrefix, dataField) {
	this.inputPrefix = inputPrefix;
	this.dataField = dataField;
	this.mapId = $(this.inputPrefix + "googlemap");
	if(this.dataField.value.length > 0) this.merge(this.strToJSON(this.dataField.value));
	this.createMap();
	var those = this;
	GEvent.addListener(this.map, 'click', function(marker, clickedPoint) { those.mapClick(clickedPoint) });
	GEvent.addListener(this.map, 'moveend', function() { those.update(); });
	this.geocoder = new GClientGeocoder();
	this.populateForm();
	if(this.polyPoints.length > 0) this.reDrawPolygon(true);
}

/**
 * extraInit() initializes a map on the outside
 * @args: (obj) JSON-object with attributes which will be merged into this instance
 */
Geo.prototype.extraInit = function(mapId, args) {
	this.mapId = $(mapId);
	this.merge(args);
	this.createMap();
	if(this.polyPoints.length > 0) this.reDrawPolygon(false);
}

/**
 * set() sets a public attribute
 * @name: (string) name of the attribute
 * @value: (string) value of the attribute
 */
Geo.prototype.set = function(name, value) {
	this[name] = value;
	this.update();
}

/**
 * deleteLastPoint() deletes the last point on the map
 */
Geo.prototype.removeLastPoint = function() {
	if(this.polyPoints.length > 0) {
		this.polyPoints.pop();
		this.update();
	}
}

/**
 * setCenterByAddress() centers the map on a given address
 * @address: (string) an valid address
 */
Geo.prototype.setCenterByAddress = function(address) {
	var that = this;
	this.geocoder.getLatLng(
		address,
		function(point) { if (point) that.map.setCenter(point); }
	);
}

/**
 * addShape() adds a different shape to this map
 * @shape: (object) a Geo-object which will be added to the map
 * (see the method saveJSONString() for the syntax)
 */
Geo.prototype.addShape = function(shape) {
	this.polyPoints = [];
	this.merge(shape);
	this.drawPolygon();
}


/* ======= STATIC methods ======= */

/**
 * strToJSON() returns a JSON-object
 * @string: a JSON-string like that one you get from saveJSONString()
 */
Geo.prototype.strToJSON = function(string) {
	return new Function ('return ' + string)();
}
	

/* =======  PRIVATE attributes and methods =======  */

Geo.prototype.map = null;
Geo.prototype.polyShape = null;
Geo.prototype.polyPoints = [];
Geo.prototype.marker = null;
Geo.prototype.geocoder = null;
Geo.prototype.inputPrefix = "";

Geo.prototype.update = function() {
	this.saveJSONString();
	this.reDrawPolygon(true);
}

Geo.prototype.merge = function(args) {
	for(var i in args) {
		if(i != "polyPoints") this[i] = args[i];
		else {
			for(var j=0; j<args[i].length; j++) {
				this.polyPoints.push( new GLatLng(args[i][j][0], args[i][j][1]) );				
			}
		}
	}
}

Geo.prototype.populateForm = function() {
	for(var i in this) {
		if($(this.inputPrefix + i) && i!="mode") $(this.inputPrefix + i).value = this[i];
		else if(i == "mode") $(this.inputPrefix + i + "_" + this[i]).checked = true;
	}
}

Geo.prototype.mapClick = function(clickedPoint) {
	if(clickedPoint) {
		if(this.mode == "point") this.polyPoints = [clickedPoint];
		else this.polyPoints.push(clickedPoint);
		this.update();		
	}
}

Geo.prototype.createMap = function() {
	if (GBrowserIsCompatible()) {
		this.map = new GMap2(this.mapId);
		this.map.setCenter(new GLatLng(this.centerLat, this.centerLng), this.zoom);
		this.map.addControl(new GLargeMapControl());
		this.map.addControl(new GMapTypeControl());
	} else {
		throw "This browser is not compatible to Google Maps";
	}
}

Geo.prototype.reDrawPolygon = function(lastPoint) {
	if(this.polyShape) {
		this.map.removeOverlay(this.polyShape);
		this.polyShape = null;
	}
	this.map.clearOverlays();
	this.drawPolygon(lastPoint);
}

Geo.prototype.drawPolygon = function(lastPoint) {
	if (this.mode == "polygon") {
		var tmp_polyPoints = this.polyPoints.slice();
		if(!lastPoint) tmp_polyPoints.push(tmp_polyPoints[0]);
		this.polyShape = new GPolygon(tmp_polyPoints, this.lineColor, this.lineWeight, this.opacity, this.fillColor, this.opacity);
	}
	else if(this.mode == "polyline") this.polyShape = new GPolyline(this.polyPoints, this.lineColor, this.lineWeight, this.opacity);
	
	if(this.mode == "points") {
		for(var i=0; i<this.polyPoints.length; i++) {
			this.map.addOverlay(new GMarker(this.polyPoints[i]));
		}
	} else if(this.polyPoints.length > 0 && (lastPoint || this.mode == "point")) {
		this.marker = new GMarker(this.polyPoints[this.polyPoints.length -1]);
		this.map.addOverlay(this.marker);					
	}

	if(this.polyShape) {
		if(this.dataField) {
			var those = this;
			GEvent.addListener(this.polyShape, 'click', function(clickedPoint) { those.mapClick(clickedPoint) });
		}
		this.map.addOverlay(this.polyShape);
	}	
}

Geo.prototype.saveJSONString = function() {

	var center = this.map.getCenter();
	var json = "{ " +
		"mode:'" + this.mode + "', " +
	    "fillColor:'" + this.fillColor + "', " +
	    "lineColor:'" + this.lineColor + "', " +
	    "opacity:" + this.opacity + ", " +
	    "lineWeight:" + this.lineWeight + ", " +
		"centerLat:" + center.lat() + ", " +
		"centerLng:" + center.lng() + ", " +
		"zoom:" + this.map.getZoom() + ", " +
		"kmlFillColor:'" + this.kmlFillColor + "', " +
		"polyPoints:[";

	for (var i = 0; i<(this.polyPoints.length); i++) {
		json +=  "[" + this.polyPoints[i].lat() + "," + this.polyPoints[i].lng() + "] ";
		if(i != (this.polyPoints.length - 1)) json += ",";
	}
		
	json += "]}";
	
	this.dataField.value = json;
}


/* additional functions */
String.prototype.trim = function () {
    return this.replace(/^\s*/, "").replace(/\s*$/, "");
}
if(typeof $ == "undefined") {
	function $(obj) {
		if(typeof obj == "string") return document.getElementById(obj);
		return obj;
	}	
}
