//this is the onions own googlemap api
var googlemap_instances = new Array();

//add events to page
onionaddload(googlemap_onload);
onionaddunload(GUnload);

function googlemap_onload() {
	//this is called when the page loads
	
	//make sure teh browser is compatible
	if (GBrowserIsCompatible() == false) { return false; }
	
	//init each map one by one
	for(index = 0;index < googlemap_instances.length;index++) {
		//get the instance
		googlemap_instances[index].init();
	}
}

function googlemap_onunload() {
	//this is called when the page unloads
	GUnload();
}

function googlemap(noptions) {
	// --- setup the instance ---------
	me = this;
	me.options = noptions;
	me.addresscache = new Array();
	me.index = googlemap_instances.length;
	googlemap_instances[this.index] = this;
	
	//setup event handle stores
	me.events = {"addmaptype":{},"removemaptype":{},"click":{},"dblclick":{},"singlerightclick":{},"movestart":{},"move":{},"moveend":{},"zoomend":{},"maptypechanged":{},"infowindowopen":{},"infowindowbeforeclose":{},"infowdinwoclose":{},"addoverlay":{},"removeoverlay":{},"mouseover":{},"mouseout":{},"mousemove":{},"dragstart":{},"drag":{},"dragend":{},"load":{}};
	
	// --- methods ---------
	//init
	me.init = function() {
		//this function will init the googlemap
		
		//--- get the element to use ---------
		me.element = oniongetelement(me.options["element"]);
		
		//--- init the googlemap ---------
		me.map = new GMap2(me.element);
		me.setmapcontrols(me.options["mapcontrols"]);
		if (me.options["maptypecontrols"] != undefined) {
			$value_normal = me.options["maptypecontrols"]["normal"];
			$value_hybrid = me.options["maptypecontrols"]["hybrid"];
			$value_satellite = me.options["maptypecontrols"]["satellite"];
		} else {
			$value_normal = false;
			$value_hybrid = false;
			$value_satellite = false;
		}
		me.setmaptypecontrols($value_normal,$value_hybrid,$value_satellite);
		me.setmaptype(me.options["maptype"]);
				
		//--- set the starting location ---------
		if (me.options["latitude"] != undefined && me.options["longitude"] != undefined) {
			me.currentpoint = me.getpoint(me.options["latitude"],me.options["longitude"]);
		}
		
		//goto to default address
		if (me.currentpoint == undefined || !me.currentpoint) {
			//get default location (london)
			me.currentpoint = me.getpoint(51.5002,0.1262);
		}
		
		//move to the point or goto address
		//goto address
		if (me.options["address"] != undefined) {
			me.setaddress(me.options["address"],function(npoint) {
				me.setlocation(npoint);
				me.setaddress(me.options["address"]);
				//set zoom level
				if (me.options["zoom"] != undefined) { me.setzoom(me.options["zoom"]); }
			});
		} else {
			me.setlocation(me.currentpoint);
			//set zoom level
			if (me.options["zoom"] != undefined) { me.setzoom(me.options["zoom"]); }
		}
		
		//add markers
		if (me.options["markers"] != undefined) {
			for(markerindex in me.options["markers"]) {
				//get the current marker
				var markeroption = me.options["markers"][markerindex];
				//get the location
				var markerpoint = me.getpoint(parseFloat(markeroption["latitude"]),parseFloat(markeroption["longitude"]));
				
				//create the marker
				me.addmarker(markerpoint,markeroption["icon"],markeroption["title"],markeroption["clickable"],markeroption["draggable"],markeroption["bouncy"]);
			}
		}
	};
	
	//addevent
	me.addevent = function(nevent,nfunction) {
		//this will add a function for a given event
		//click,  dblclick,  infowindowopen,  infowindowclose,  remove,  dragstart,  dragend,  visibilitychanged
		
		//fix the casing on the event name
		nevent = nevent.toLowerCase();
		
		//make sure it is a valid event
		if (me.events[nevent] == undefined) { return null; }
		
		//create the event listener
		me.events[nevent][me.events[nevent].length] = new googleevent(GEvent.addListener(me.map,nevent,function(nparam1,nparam2,nparam3){nfunction(nevent,me,nparam1,nparam2,nparam3);}));
	};
	
	//clear event
	me.clearevent = function(nevent) {
		//fix the casing on the event name
		nevent = nevent.toLowerCase();
		
		//this will clear all event listeners for a particular event
		if (me.events[nevent] == undefined) { return false; }
		
		//remove all the listeners
		for(index = 0;index < me.events[nevent].length;index++) {
			me.events[nevent][index].remove();
		}
		
		//remove the array key
		delete(me.events[nevent]);
		
		//recreate the array key
		me.events[nevent] = new Array();
	};
	
	//reset
	me.resetlocation = function() {
		//make sure map is ready
		if (me.ready() == false) { return false; }
	
		//this function will reset the map to the stored center point
		me.setlocation(me.currentpoint);
	};
	
	//set address
	me.setaddress = function(naddress,ncallback) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
		
		//this function will try and make the map goto an address
		//create an instance of the geocoder for this map
		if (me.geocoder == undefined) { me.geocoder = new GClientGeocoder; }
		
		//check cache
		if (me.addresscache[naddress.toLowerCase()] != undefined) {
			//update the current point
			//check for callback
			if (ncallback == undefined) { ncallback = me.setlocation; }
			me.currentlocation = me.addresscache[naddress.toLowerCase()];
			ncallback(me.addresscache[naddress.toLowerCase()]);
		} else {
			//get a lat long from the address
			if (ncallback == undefined) { ncallback = me.setlocation; }
			me.geocoder.getLatLng(naddress,function(npoint) {
				me.currentlocation = npoint;
				me.addresscache[naddress.toLowerCase()] = npoint;
				ncallback(npoint);
			});
		}
	}
	
	//goto address
	me.gotoaddress = function(naddress,ncallback) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
		
		//this function will try and make the map goto an address
		//create an instance of the geocoder for this map
		if (me.geocoder == undefined) { me.geocoder = new GClientGeocoder; }
		
		//check cache
		if (me.addresscache[naddress.toLowerCase()] != undefined) {
			//update the current point
			//check for callback
			if (ncallback == undefined) { ncallback = me.gotolocation; }
			me.currentlocation = me.addresscache[naddress.toLowerCase()];
			ncallback(me.addresscache[naddress.toLowerCase()]);
		} else {
			//get a lat long from the address
			if (ncallback == undefined) { ncallback = me.gotolocation; }
			me.geocoder.getLatLng(naddress,function(npoint) {
				me.currentlocation = npoint;
				me.addresscache[naddress.toLowerCase()] = npoint;
				ncallback(npoint);
			});
		}
	}
	
	//goto center point
	me.gotolocation = function(npoint) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
	
		//check to see if latlng seperated
		if (npoint) {
			me.currentpoint = npoint;
			return me.map.panTo(npoint);
		} else {
			alert("couldn't find address");
		}
	};
	
	//set center point
	me.setlocation = function(npoint) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
	
		//check to see if latlng seperated
		if (npoint) {
			me.currentpoint = npoint;
			return me.map.setCenter(npoint);
		} else {
			alert("couldn't find address");
		}
	};
	
	//current location
	me.getlocation = function() {
		return me.currentlocation;
	}
	
	//ready
	me.ready = function() {
		if (me.map != undefined && me.map != null) {
			return true;
		} else {
			return false;
		}
	};
	
	//setzoom
	me.setzoom = function(nzoom) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
		
		if (nzoom < 0) { nzoom = 0; }
		if (nzoom > 19) { nzoom = 19; }
		me.map.setZoom(nzoom);
	}
	
	//setballoon
	me.setballoon = function(ncontents,npoint) {
		//this lets you set a balloon to popup at a specified position, if no position is found the current oen will be used
		//if (nposition
	};
	
	//getpoint
	me.getpoint = function(nparam1,nparam2) {
		//this function will return a point based on location
		if (nparam1 == null || nparam1 == undefined) { nparam1 = 0.0; }
		if (nparam2 == null || nparam2 == undefined) { nparam2 = 0.0; }
		return new GLatLng(nparam1,nparam2);
	};
	
	//add marker
	me.addmarker = function(npoint,nicon,ntitle,nclickable,ndraggable,nbouncy) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
		
		var marker = new googlemarker(npoint,nicon,ntitle,nclickable,ndraggable,nbouncy);
		me.map.addOverlay(marker.marker);
		return marker;
	};
	
	//mapcontrols
	me.setmapcontrols = function(nmapcontrols) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
	
		if (nmapcontrols == undefined || nmapcontrols == null || nmapcontrols == false || (nmapcontrols.toLowerCase() != "small" && nmapcontrols.toLowerCase() != "large")) {
			//disable map controls
			if (me.mapcontrols != undefined) {
				me.map.removeControl(me.mapcontrols);
				delete me.mapcontrols;
			}
		} else {
			//enable map controls
			switch(nmapcontrols.toLowerCase()) {
				case "small":
					//remove the control if it is the wrong one
					if (me.mapcontrols != undefined && (me.mapcontrols instanceof GSmallMapControl) == false) {
						me.map.removeControl(me.mapcontrols);
						delete me.mapcontrols;
					}
					//add the control if it doesn't exist
					if (me.mapcontrols == undefined) {
						me.mapcontrols = new GSmallMapControl();
						me.map.addControl(me.mapcontrols);
					}
					break;
				case "large":
					//remove the control if it is the wrong one
					if (me.mapcontrols != undefined && (me.mapcontrols instanceof GLargeMapControl) == false) {
						me.map.removeControl(me.mapcontrols);
						delete me.mapcontrols;
					}
					//add the control if it doesn't exist
					if (me.mapcontrols == undefined) {
						me.mapcontrols = new GLargeMapControl();
						me.map.addControl(me.mapcontrols);
					}
					break;
			}
		}
	};
	
	//maptypecontrols
	me.setmaptypecontrols = function(nnormal,nhybrid,nsatellite) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
	
		//setup teh map type controls on the map
		//fix broken values
		if (nnormal == undefined) { var nnormal = false; }
		if (nhybrid == undefined) { var nhybrid = false; }
		if (nsatellite == undefined) { var nsatellite = false; }
		
		//check to see action
		if (nnormal != false || nhybrid != false || nsatellite != false) {
			//show some controls
			//normal
			if (nnormal == true) {
				me.map.addMapType(G_NORMAL_MAP);
			} else {
				me.map.removeMapType(G_NORMAL_MAP);
			}
			//hybrid
			if (nhybrid == true) {
				me.map.addMapType(G_HYBRID_MAP);
			} else {
				me.map.removeMapType(G_HYBRID_MAP);
			}
			//satellite
			if (nsatellite == true) {
				me.map.addMapType(G_SATELLITE_MAP);
			} else {
				me.map.removeMapType(G_SATELLITE_MAP);
			}
			
			//add teh control if it has not already been added
			if (me.maptypecontrol == undefined) {
				me.maptypecontrol = new GMapTypeControl();
				me.map.addControl(me.maptypecontrol);
			}

		} else {
			//hide all controls
			if (me.maptypecontrol != undefined) {
				me.map.removeControl(me.maptypecontrol);
				
				var currentmaptype = me.map.getCurrentMapType();
				if (currentmaptype != G_NORMAL_MAP) { me.map.removeMapType(G_NORMAL_MAP); }
				if (currentmaptype != G_HYBRID_MAP) { me.map.removeMapType(G_HYBRID_MAP); }
				if (currentmaptype != G_SATELLITE_MAP) { me.map.removeMapType(G_SATELLITE_MAP); }
				delete(me.maptypecontrol);
			}
		}
	};
	
	//maptype
	me.setmaptype = function(nname) {
		//make sure map is ready
		if (me.ready() == false) { return false; }
	
		switch (nname.toLowerCase()) {
			case "g_satellite_map":case "photo":case "satellite":case "sat":case "satalite":
				me.map.setMapType(G_SATELLITE_MAP);
				break;
			case "g_hybrid_map":case "hybrid":case "combo":case "overlay":
				me.map.setMapType(G_HYBRID_MAP);
				break;
			default:
				me.map.setMapType(G_NORMAL_MAP);
				break;
		}
	};
}

function googlemarker(npoint,nicon,ntitle,nclickable,ndraggable,nbouncy) {
	//this will setup the new instance of the googlemarker
	var me = this;
	
	//setup default values
	if (nicon == undefined || nicon == null || nicon == false) { nicon = G_DEFAULT_ICON; }
	if (ntitle == undefined || ntitle == null || ntitle == false) { ntitle = ""; }
	if (nclickable == undefined || nclickable == null || nclickable == false) { nclickable = false; }
	if (ndraggable == undefined || ndraggable == null || ndraggable == false) { ndraggable = false; }
	if (nbouncy == undefined || nbouncy == null || nbouncy == false) { nbouncy = false; }
	
	//setup event handle stores
	me.events = {"click":{},"dblclick":{},"infowindowopen":{},"infowindowclose":{},"remove":{},"dragstart":{},"dragend":{},"visibilitychanged":{}};
	
	//create teh marker
	me.marker = new GMarker(npoint,{
		icon:nicon,
		title:ntitle,
		clickable:nclickable,
		draggable:ndraggable,
		bouncy:nbouncy
	});
	
	// --- methods ---------
	me.addevent = function(nevent,nfunction) {
		//this will add a function for a given event
		//click,  dblclick,  infowindowopen,  infowindowclose,  remove,  dragstart,  dragend,  visibilitychanged
		
		//fix the casing on the event name
		nevent = nevent.toLowerCase();
		
		//make sure it is a valid event
		if (me.events[nevent] == undefined) { return null; }
		
		//create the event listener
		me.events[nevent][me.events[nevent].length] = new googleevent(GEvent.addListener(me.marker,nevent,function(nobject,npoint){nfunction(nevent,me,nobject,npoint);}));
	};
	
	me.clearevent = function(nevent) {
		//fix the casing on the event name
		nevent = nevent.toLowerCase();
		
		//this will clear all event listeners for a particular event
		if (me.events[nevent] == undefined) { return false; }
		
		//remove all the listeners
		for(index = 0;index < me.events[nevent].length;index++) {
			me.events[nevent][index].remove();
		}
		
		//remove the array key
		delete(me.events[nevent]);
		
		//recreate the array key
		me.events[nevent] = new Array();
	};
	
	me.clearevents = function() {
		//clear ALL events
		for(key in me.events) {
			console.log(key);
		}
	};
	
	me.setvisible = function(nstate) {
		if (nstate == undefined || nstate == null) { nstate = true; }
		if (nstate) {
			me.marker.show();
		} else {
			me.marker.hide();
		}
	};
	
	me.setdraggable = function(nstate) {
		if (nstate == undefined || nstate == null) { nstate = true; }
		if (nstate) {
			me.marker.enableDragging();
		} else {
			me.marker.disableDragging();
		}
	};
	
	me.setlocation = function(npoint) {
		//check to see if latlng seperated
		if (npoint) {
			return me.marker.setPoint(npoint);
		} else {
			alert("couldn't find address");
		}		
	};
	
	me.getlocation = function() {
		//this function will get the location of the marker and call the callback
		return me.marker.getPoint();
	}
}

function googleevent(neventlistener) {
	var me = this;
	// --- properties ---------
	me.eventlistener = neventlistener;
	
	// --- methods ---------
	me.remove = function() {
		GEvent.removeListener(me.eventlistener);
	};
};