kmap = {}

kmap.KMap = Class.create({
	initialize : function(eMap, options) {
		this.mapElement = $(eMap);
		this.options = options;
		this.addresses = {};
		Event.observe(window,"load",this._handleLoad.bindAsEventListener(this));
		Event.observe(window,"unload",this._handleUnload.bindAsEventListener(this));
	}
	, geocode : function(sAddress, opts) {
		this.gGeocoder.getLatLng(sAddress,function(gllPoint) {
			if(!gllPoint) {
				//Failed to retrieve lat/lng pt from Google for address
				if(opts.onFailure) {
					opts.onFailure();
				}
			} else {
				if(opts.onSuccess) {
					opts.onSuccess(gllPoint);
				}
			}
		}.bind(this));
	}
	, addAddress : function(kAddress) {
		this.addresses[kAddress.address] = kAddress;
		kAddress.addInto(this);
	}
	, pointAdded : function(gllPt) {
		 if(!this.gMap.isLoaded()) {
		 	this.gMap.setCenter(gllPt);
		 }
		 if(!this.gBounds) {
		   this.gBounds = new GLatLngBounds(); 
		 }
		 this.gBounds.extend(gllPt);
	}
	, openInfoWindow : function(sAddress) {
		this.addresses[sAddress].openInfoWindow(true);
	}
	, _handleLoad : function() {
		if(GMap2 && GBrowserIsCompatible()) {
			this.gGeocoder = new GClientGeocoder();
	    this.gMap = new GMap2(this.mapElement);
			if(this.options.addresses) {
				for(var i=0; i<this.options.addresses.length; i++) {
					this.addAddress(this.options.addresses[i]);
				}
			}
			if(this.options.controls) {
				for(var i=0; i<this.options.controls.length; i++) {
					this.gMap.addControl(this.options.controls[i]);
				}
			}
			if(this.options.mapType) {
				this.gMap.setMapType(this.options.mapType);				
			}
			if(this.options.zoomLevel) {
				this.gMap.setZoom(this.options.zoomLevel);
			} else {
				if(this.gBounds) {
					var iZoom = this.gMap.getBoundsZoomLevel(this.gBounds);
					//PHD 4/6/2008 - Google often doesn't have imagery in higher zooms, 
					//so back out a bit to give us a better chance of having images
					if(iZoom > 18) {
						iZoom = 18
					}
					this.gMap.setZoom(iZoom);
					this.gMap.panTo(this.gBounds.getCenter());
				}
			}
			this.mapElement.fire("kmap:load",this);
		} else {
			this.mapElement.innerHTML = "Google maps cannot be loaded.";
		}		
	}
	, _handleUnload : function() {
		if(this.gMap) {
			GUnload();
		}
	}
});

kmap.KAddress = Class.create({
  initialize : function(sName, sAddress, description,options) {
  		this.description = description;
		this.name = sName;
		this.address = sAddress;
		this.options = options;
		if(this.options.point) {
			this.point = this.options.point;
		}
	}
	, addInto : function(kMap) {
		this.kMap = kMap;
		this.map = this.kMap.gMap;
		this.gc = this.kMap.gGeocoder
		if(!this.point) {
			this.kMap.geocode(this.address,{
				onSuccess : function(gllPoint) {
					this.point = gllPoint;
					this._addPointToMap();
				}.bind(this)
			});				
		} else {
			this._addPointToMap();
		}
	}
	, _addPointToMap : function(){
		 this.kMap.pointAdded(this.point);
	   this.marker = this._newMarker();
	   this.mark();		
		 
	}
	, _defaultMarkerHtml : function() {
		var sMarkerText = this.description;
		if(this.name && this.name.length > 0) {
			sMarkerText = "<b>"+this.name+"</b><br/>"+sMarkerText;
		}
		return sMarkerText;				
	}
	, _newMarker : function() {
		var mk = null;
		if(this.options.newMarker) {
			mk = this.options.newMarker(this);
		} else {
			mk = new GMarker(this.point,{title:this.description});
		}
		GEvent.addListener(mk,"click",function(){
			this.openInfoWindow(false);
		}.bind(this));
		return mk;
	}
	, mark : function() {
		this.map.addOverlay(this.marker);
		this._marked = true;
	}
	, getInfoWindowHtml : function() {
		if(!this.html) {
			if(this.options.newInfoWindowHtml) {
				this.html = this.options.newInfoWindowHtml(this);
			} else {
				this.html = this._defaultMarkerHtml();
			}
		}		
		return this.html;
	}
	, openInfoWindow : function(bCenter) {
		if(!this._marked) {
			this.mark();				
		}
		if(bCenter) {
			this.centerOn();
		}
		this.marker.openInfoWindowHtml(this.getInfoWindowHtml());
	}
	, centerOn : function() {
		this.map.setCenter(this.point);
	}
	, getOpenInfoWindowEventListener : function() {
		return function() {
			this.openInfoWindow(true);
		}.bind(this);
	}
});