/*Define an overlay collection*/
function OverlayCollection(name, pagesize){
	this.data = new Object();
	this.length = 0;
	this.bounds = new google.maps.LatLngBounds();
	this.pagesize = pagesize;
	this.name = name;
	this.currPage = 1;
	this.useLabels = false;
	this.labelType = 'Alpha';
	this.handlers = new Object();
	this.$svGM = jQuery.fn.svGoogleMaps;
	
	var self = this;
	
	this.getIconStyle = function(placemark) {
		return 'default';
	}

	this.removeHandler = function(type, fn) {
		if (this.handlers[type]) {
			for (var i = 0; i < this.handlers[type].length; i++){
				if (this.handlers[type][i] == fn) {
					this.handlers[type].splice(i,1);
				}
			}
		}
	}

	this.addHandler = function(type,fn,bind){
		if(!this.handlers[type])
			this.handlers[type] = new Array();
		this.handlers[type].push((bind ? jQuery.shove(fn, this) : fn));
	}
	
	this.execHandler = function(){
		var type = arguments[0];
		if(arguments.length > 1){
			var source = arguments[1];
		}
		var a = new Array();
		for (var i = 1; i < arguments.length; i++){
			a.push(arguments[i]);
		}
		if(this.handlers[type] && this.handlers[type].length){
			for (var i = 0; i < this.handlers[type].length; i++){
				this.handlers[type][i].apply(source,a);
			}
		}
	}
	
	this.check = function(placemark){
		if (this.data['itin_' + placemark.prikey]) {
			return true;
		} else {
			return false;
		}
	}
	
	this.clear = function(placemark){
		if (this.check(placemark)) {
			delete this.data['itin_' + placemark.prikey];
			this.length--;
		}
		this.calcBounds();
	}
	
	this.clearAll = function(){
		this.data = new Object();
		this.length = 0;
		this.bounds = new google.maps.LatLngBounds();
	}
	
	//Add a Simple Marker
	this.addPlacemark = function(placemark, cancelHandlers) {
		logit('Called: ' + this.name + '.addPlacemark - ' + placemark.prikey);
		
		var exists = this.check(placemark);
		
		if (!exists) {
			placemark.collection = this;
			this.data['itin_' + placemark.prikey] = placemark;
			this.length++;
			
			return true;
		} else {
			return false;
		}
		
		logit('End: ' + this.name + '.addPlacemark - ' + placemark.prikey);
	}

	this.addPlacemarks = function(placemarks, cancelHandlers){
		logit('Called: ' + this.name + '.addPlacemarks');
		
		for (var i = 0; i < placemarks.length; i++) {
			this.addPlacemark(placemarks[i], true);
		}
		
		if (!cancelHandlers) {
			self.execHandler('addremove', 'addplacemarks');
		}
		
		logit('End: ' + self.name + '.addPlacemarks');
	}

	this.showPlacemark = function(placemark, cancelHandlers, labelNum) {
		logit('Called: ' + this.name + '.showPlacemark - ' + placemark.prikey);
		
		var iconStyle = placemark.pinned ? 'pushpin' : self.getIconStyle(placemark);
		placemark.iconstyle = iconStyle;
		
		if (typeof labelNum != 'number') {
			labelNum = this.length - 1;
		}
		
		if (self.useLabels) {
			placemark.label = (self.labelType == 'Alpha' ? chr(labelNum + asc('A')) : (labelNum + 1));
		} else {
			placemark.label = '';
		}
		
		placemark.icon = self.$svGM.args.m.createCustomIcon(iconStyle, placemark.label);
		
		if (placemark.point === null) {
			placemark.point = new google.maps.LatLng(placemark.latitude, placemark.longitude);
		}
		
		var marker = new google.maps.Marker(placemark.point, {icon: placemark.icon, zIndexProcess: jQuery.shove(self.$svGM.args.m.sendBack, this)});
		marker.title = placemark.tooltip;
		
		if (!placemark.infoWindowPlaceholder) {
			placemark.infoWindowPlaceholder = this.getInfoHTML();
		}
		
		//Add Reverse Lookups
		placemark.marker = marker;
		
		this.hidePlacemark(placemark, true);
		
		self.$svGM.args.m.bounds.extend(placemark.marker.getPoint());
		self.$svGM.args.m.gmap.addOverlay(placemark.marker);
		
		if (placemark.icon.hover) {
			google.maps.Event.addListener(marker,"mouseover",function(){
				var imgsrc = this.getIcon().image;
				var newsrc = imgsrc.replace('_hover','');
				var newsrc = newsrc.replace('.png','');
				var components = newsrc.split('_');
				if (components.length > 1) {
					label = components[components.length - 1];
					components = components.splice(components, components.length - 1, 1);
					var str = components.join('_');
					newsrc = str + '_hover' + '_' + label + '.png';
				} else {
					newsrc = newsrc + '_hover.png';
				}
				this.setImage(newsrc);	
				//google.maps.Log.write(newsrc);
			});
	
			google.maps.Event.addListener(marker,"mouseout",function(){
				var imgsrc = this.getIcon().image;
				var newsrc = imgsrc.replace('_hover','');
				this.setImage(newsrc);	
				//google.maps.Log.write(newsrc);
			});
		}
		
		if (marker.tooltip) {
			logit('adding tooltip - ' + marker.title);
			
			self.$svGM.args.m.gmap.addOverlay(marker.tooltip);
			
			google.maps.Event.addListener(marker, "mouseover", 
				function() {
					this.tooltip.show();
					
					return false;
				}
			)
			
			google.maps.Event.addListener(marker, "mouseout",
				function() {
					this.tooltip.hide();
					
					return false;
				}
			)
		}
		if (placemark.infoWindowPlaceholder) {
			google.maps.Event.addListener(marker, 'click', function() {
				self.$svGM.args.m.gmap.setCenter(marker.getPoint());
				marker.openInfoWindowHtml(parsePlacemarkData(placemark.infoWindowPlaceholder, placemark));
				
				self.execHandler('openinfobubble', placemark);
			});
			
			google.maps.Event.addListener(marker, 'mouseover', function() {
				self.$svGM.args.m.mouseOverObj = {'marker': marker, 'placemark': placemark};
				self.$svGM.args.m.mouseOverTimeout = setTimeout(function() {
					if (typeof self.$svGM.args.m.mouseOverObj != 'undefined' && self.$svGM.args.m.mouseOverObj != null) {
						self.$svGM.args.m.gmap.setCenter(self.$svGM.args.m.mouseOverObj.marker.getPoint());
						
						marker.openInfoWindowHtml(parsePlacemarkData(placemark.infoWindowPlaceholder, placemark));
						self.execHandler('openinfobubble', self.$svGM.args.m.mouseOverObj.placemark);
						
						self.$svGM.args.m.mouseOverObj = null;
						self.$svGM.args.m.mouseOverTimeout = null;
					}
				}, 750);
			});
			
			google.maps.Event.addListener(marker, 'mouseout', function() {
				self.$svGM.args.m.mouseOverObj = null;
				if (self.$svGM.args.m.mouseOverTimeout) {
					clearTimeout(self.$svGM.args.m.mouseOverTimeout);
				}
				self.$svGM.args.m.mouseOverTimeout = null;
			});
			
			google.maps.Event.addListener(marker, 'infowindowbeforeclose', function() {
				if (self.$svGM.args.svPano !== null) {
					self.$svGM.args.svPano.remove();
				}
				self.$svGM.args.svPano = null;
			});
		}

		if (!cancelHandlers) {
			self.execHandler('showhide', 'showplacemark');
		}
		
		logit('End: ' + this.name + '.showPlacemark - ' + placemark.prikey);
	}

	this.showPlacemarks = function(page, cancelHandlers) {
		logit('Called: ' + this.name + '.showPlacemarks - ' + page);
		
		this.hidePlacemarks();
		
		if (!page) {
			page = 1;
		}

		this.currPage = page;

		var placemarks = this.getPage(page);
		
		//Show them all
		for (var i = 0; i < placemarks.length; i++) {
			this.showPlacemark(placemarks[i], true, i);
		}

		//Set the center and zoom of map
		if (!this.cancelCentering) {
			self.$svGM.args.m.setBoundsCenterAndZoom();
		} else if (map.circle !== null) {
			self.$svGM.args.m.gmap.setCenter(self.$svGM.args.m.circle.getBounds().getCenter(), self.$svGM.args.m.gmap.getBoundsZoomLevel(self.$svGM.args.m.circle.getBounds()));
		}

		if (!cancelHandlers) {
			self.execHandler('showhide', 'showplacemarks');
		}
		
		logit('End: ' + this.name + '.showPlacemarks - ' + page);
	}
	
	this.hidePlacemark = function(placemark, cancelHandlers) {
		logit('Called: ' + this.name + '.hidePlacemark - ' + placemark.prikey);
		
		if (placemark.marker && this.check(placemark)) {
			self.$svGM.args.m.gmap.removeOverlay(placemark.marker);
		}

		if (!cancelHandlers) {
			self.execHandler('showhide', 'hideplacemark');
		}
		
		logit('End: ' + this.name + '.hidePlacemark - ' + placemark.prikey);
	}
	
	this.hidePlacemarks = function(cancelHandlers) {
		logit('Called: ' + this.name + '.hidePlacemarks');
		
		for (var i in this.data){
			if (this.data[i].marker) {
				self.$svGM.args.m.gmap.removeOverlay(this.data[i].marker);
			}
		}

		if (!cancelHandlers) {
			self.execHandler('showhide', 'hideplacemarks');
		}
		
		logit('End: ' + this.name + '.hidePlacemark');
	}
	
	this.removeCollection = function() {
		if (this.closeInfoWindow) {
			overlay.closeInfoWindow();
		}
		
		self.$svGM.args.m.gmap.removeOverlay(this);
		
		if (this.tooltip) {
			self.$svGM.args.m.gmap.removeOverlay(this.tooltip);
		}
	}

	this.removePlacemark = function(placemark, cancelHandlers) {
		logit('Called: ' + this.name + '.removePlacemark - ' + placemark.prikey);
		
		if (placemark.marker) {
			self.$svGM.args.m.gmap.removeOverlay(placemark.marker);
		}
		
		this.clear(placemark);
		
		if (!cancelHandlers) {
			self.execHandler('addremove', 'removeplacemark');
		}
		
		logit('End: ' + this.name + '.removePlacemark - ' + placemark.prikey);
	}
	
	//Remove all placemarks from the map
	this.removePlacemarks = function(cancelHandlers) {
		logit('Called: ' + this.name + '.removePlacemarks');
		
		for (var i in this.data){
			this.removePlacemark(this.data[i]);
		}
		
		this.removeCollection();
		this.clearAll();
		
		if (!cancelHandlers) {
			self.execHandler('addremove', 'removeplacemarks');
		}
		
		logit('End: ' + this.name + '.removePlacemarks');
	}
	
	this.get = function(prikey){
		return this.data['itin_' + prikey];
	}
	
	this.numPages = function(){
		return Math.ceil(this.length / this.pagesize);
	}

	this.getPage = function(page){
		var oc = new OverlayCollection();
		var arr = new Array();
		var startrow = (page-1) * this.pagesize;
		var endrow = (Math.min(this.length,page * this.pagesize-1));

		var cnt = 0;
		if(!this.sortIndex){
			for(var i in this.data){
				if(cnt > endrow)
					break;
				if(cnt >= startrow)
					arr.push(this.data[i]);
				cnt++;
			}
			return arr;
		}
		else{
			return this.sortIndex.slice(startrow,endrow);
		}
	}
	
	this.calcBounds = function(){
		var pm = this.getPage(this.currPage);
		this.bounds = new google.maps.LatLngBounds();
		for (var i = 0; i < pm.length; i++){
			if(pm[i].marker)
				this.bounds.extend(pm[i].marker.getPoint());
		}
		return this.bounds;
	}
	
	this.getInfoHTML = function() {
		var str = new String();
		
		str = "<div class=\"infoWindowTitle\">placemark:name</div>";
		str += "<div class=\"infoWindowAddress\">placemark:address</div>";
		
		return str;
	}

	this.findSpot = function(arr,field,searchValue,low,high){
		var l = arr.length;
	
		if(typeof(low) == 'undefined')
			var low = 0;
	
		if(typeof(high) == 'undefined')
			var high = arr.length-1;
	
		if (high < low)
			return low;
		else if (high == low){
			return arr[low][field] > searchValue ? low : low+1;
		}
	
		if(arr[high][field] < searchValue)
			return high + 1;
	
		if (arr[low][field] > searchValue)
			return Math.max(low - 1,0);
	
		var i = low + Math.ceil((high-low) / 2);
	
	
		if(arr[i][field] > searchValue)
			return this.findSpot(arr,field,searchValue,low,i-1);
		else if(arr[i][field] < searchValue)
			return this.findSpot(arr,field,searchValue,i+1,high);
		else
			return i;
	}

	this.sortBy = function(sortBy){
		var index = new Array();
		
		for(var i in this.data)
			index.push(this.data[i]);
			
		index.sort(function(a,b){return a[sortBy] > b[sortBy]});
		
		this.clearAll();
		for(var i = 0; i < index.length; i++)
			this.addPlacemark(index[i]);
	},
	this.getToolTip = function(placemark){
		return placemark.name;
	}
}
