// JavaScript Document
// Requires Prototype.js

if(!maps)
	var maps = new Object();

if(window['placemarks'] == 'undefined')
	var placemarks = new Object();

//Object Representing a Simpleview Map
function Map(name,divname,defaultLat,defaultLng,defaultZoom){
	this.defaultSettings = {
		control: new GSmallMapControl(),
		defaultLat: defaultLat,
		defaultLng: defaultLng,
		defaultZoom: defaultZoom,
		defaultPoint: new GLatLng(defaultLat,defaultLng)
	}

	this.settings = {
		control: new GSmallMapControl(),
		defaultLat: defaultLat,
		defaultLng: defaultLng,
		defaultZoom: defaultZoom,
		defaultPoint: new GLatLng(defaultLat,defaultLng)
	}
	this.zoomAdjust = 0;
	this.bounds = new GLatLngBounds();
	this.name = name;
	this.gmap = null;
	this.additionalBounds = null;

	this.collections = new Object();
	this.defaultCollection = null;

	this.allFilters = new Object();
	this.cancelCentering = false;


	//Create An Alias
	var map = this;

	this.sortCollection = function(collection,sortBy){
		this.collections[collection].sortBy(sortBy);
	}

	this.initCustomIcons = function(){
		this.iconStyles = {
			'default':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/flag_orange_icon:label.png',
				shadow:"http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/flag_orange_shadow.png",
				iconSize: new GSize(24.0, 19.0),
				shadowSize: new GSize(30.0, 19.0),
				iconAnchor: new GPoint(1, 19),
				infoWindowAnchor: new GPoint(12.0, 10.0)
			},
			'black-pointer':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/black-pointer_icon:label.png',
				shadow:"http://www.google.com/mapfiles/shadow50.png",
				iconSize: new GSize(32.0, 32.0),
				shadowSize: new GSize(49.0, 32.0),
				iconAnchor: new GPoint(16.0, 16.0),
				infoWindowAnchor: new GPoint(16.0, 16.0)
			},					
			'pushpin':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/pushpin_icon:label.png',
				shadow:"http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/pushpin_shadow.png",
				iconSize: new GSize(32.0, 32.0),
				shadowSize: new GSize(49.0, 32.0),
				iconAnchor: new GPoint(6, 32.0),
				infoWindowAnchor: new GPoint(16.0, 16.0)
			},
			'green-pushpin':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/green-pushpin_icon:label.png',
				shadow:"http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/pushpin_shadow.png",
				iconSize: new GSize(32.0, 32.0),
				shadowSize: new GSize(49.0, 32.0),
				iconAnchor: new GPoint(6, 32.0),
				infoWindowAnchor: new GPoint(16.0, 16.0)
			},		
			'red-pushpin':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/red-pushpin_icon:label.png',
				shadow:"http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/pushpin_shadow.png",
				iconSize: new GSize(32.0, 32.0),
				shadowSize: new GSize(49.0, 32.0),
				iconAnchor: new GPoint(6, 32.0),
				infoWindowAnchor: new GPoint(16.0, 16.0)
			},			
			'custom':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/red-pushpin.png',
				shadow:"http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/pushpin_shadow.png",
				iconSize: new GSize(32.0, 32.0),
				shadowSize: new GSize(49.0, 32.0),
				iconAnchor: new GPoint(6, 32.0),
				infoWindowAnchor: new GPoint(16.0, 16.0)
			},			
			'hotels':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/hotels_0.png',
				shadow:"http://www.google.com/mapfiles/shadow50.png",
				iconSize: new GSize(26, 22),
				shadowSize: new GSize(26, 22),
				iconAnchor: new GPoint(26, 22),
				infoWindowAnchor: new GPoint(9, 2),
				infoShadowAnchor: new GPoint(18, 25)
			},
			'attractions':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/attractions_0.png',
				shadow:"http://www.google.com/mapfiles/shadow50.png",
				iconSize: new GSize(26, 22),
				shadowSize: new GSize(26, 22),
				iconAnchor: new GPoint(26, 22),
				infoWindowAnchor: new GPoint(9, 2),
				infoShadowAnchor: new GPoint(18, 25)
			},
			'dining':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/dining_0.png',
				shadow:"http://www.google.com/mapfiles/shadow50.png",
				iconSize: new GSize(26, 22),
				shadowSize: new GSize(26, 22),
				iconAnchor: new GPoint(26, 22),
				infoWindowAnchor: new GPoint(9, 2),
				infoShadowAnchor: new GPoint(18, 25)
			},
			'shopping':{
				image:'http://dev1.simpleviewinc.com/fairfax/web/includes/images/shell/google/other_0.png',
				shadow:"http://www.google.com/mapfiles/shadow50.png",
				iconSize: new GSize(26, 22),
				shadowSize: new GSize(26, 22),
				iconAnchor: new GPoint(26, 22),
				infoWindowAnchor: new GPoint(9, 2),
				infoShadowAnchor: new GPoint(18, 25)
			}
		};
	}

	//Initialize Map
	this.create = function(){
		this.initCustomIcons();
		map.div = $(divname);
		map.gmap = new GMap2(map.div);

		if(!this.cancelCentering){
			map.gmap.setCenter(map.settings.defaultPoint);
			map.gmap.setZoom(map.settings.defaultZoom);
		}

		map.control = new GSmallMapControl();
		map.gmap.addControl(map.control);
		map.typeControl  = new GMapTypeControl();
		map.gmap.addControl(map.typeControl);
		map.gmap.addMapType(G_PHYSICAL_MAP);

		//Register Map with main array
		maps[map.name] = map;
	}
	
	
	this.addCollection = function(oc,isDefault){
		this.collections[oc.name] = oc;
		if(isDefault || this.defaultCollection == null)
			this.defaultCollection = oc;
		oc.map = this;
		return oc;
	}

	//Set Current Maps Control
	this.setControl = function(control){
		if(map.settings.control)
			map.gmap.removeControl(map.settings.control);

		if(control)
			map.gmap.addControl(control);
		this.settings.control = control;
	}

	this.setCenter = function(){
		map.bounds = new GLatLngBounds();
		var p;		
		for (var i in this.collections){
			var c = this.collections[i];
			map.bounds = addBounds(map.bounds,c.calcBounds());
		}
		if(map.bounds.isEmpty()){
			p = map.settings.defaultPoint;
		}
		else{
			p = map.bounds.getCenter();
		}		
		map.gmap.setCenter(p);
	}
	
	this.getBounds = function(){
		var bounds = new GLatLngBounds();
		for (var i in this.collections){
			var c = this.collections[i];
			var cbounds = c.calcBounds();		
			bounds = addBounds(bounds,cbounds);
		}
		if(this.additionalBounds != null)
			bounds = addBounds(bounds,this.additionalBounds);
		return bounds;
	}
	
	this.setBoundsCenterAndZoom = function(){
		map.bounds = this.getBounds();
		if(!map.bounds.isEmpty()){
			var p = map.bounds.getCenter();
			var z = map.gmap.getBoundsZoomLevel(map.bounds);
		}
		else{
			var p = map.settings.defaultPoint;
			var z = map.settings.defaultZoom;
		}
		map.gmap.setCenter(p);
		map.gmap.setZoom(z + this.zoomAdjust);
	}

	this.removeOverlays = function(collection){
		for(var i in collection.data){
			var p = collection.data[i];
			if(p.marker){
				map.gmap.removeOverlay(p.marker);
				delete p.marker;
			}			
		}
	}

	//Remove all placemarks from the map
	this.removePlacemarks = function(collection,cancelHandlers){
		this.removeOverlays(collection);
		collection.clearAll();
		if(!cancelHandlers)
			collection.execHandler('addremove','removeplacemarks');
	}

	this.removePlacemark = function(placemark,collection,cancelHandlers){
		if(!collection)
			collection = this.defaultCollection;

		if(placemark.marker){
			placemark.marker.closeInfoWindow();
			this.gmap.removeOverlay(placemark.marker);
		}
		collection.clear(placemark);
		if(placemark.marker)
			delete placemark.marker;
		if(!cancelHandlers){
			collection.execHandler('addremove','removeplacemark');
		}
	}

	//Add a Simple Marker
	this.addPlacemark = function(placemark,collection,cancelHandlers){
		if(!collection)
			collection = map.defaultCollection;

		//If there is no preexisting marker, create marker and add a reference in the placemark
		if(!placemark.marker){
			placemark.marker = new GMarker(placemark.point);
			placemark.marker.placemark = placemark;
		}

		collection.set(placemark);	

		if(!cancelHandlers){
			collection.execHandler('addremove','addplacemark');
		}
	}


	this.initPlacemark = function(oc,placemark){
		var labelType = oc.labelType;
		placemark.label = '';
		placemark.icon = this.createCustomIcon(oc.getIconStyle(placemark),placemark.label);
		var p = new GLatLng(placemark.latitude,placemark.longitude);
		var m = new GMarker(p,{icon:placemark.icon});
		m.placemark = placemark;
		placemark.marker = m;
		placemark.marker.myInfoHTML = oc.getInfoHTML(placemark);
		placemark.collection = oc;
	}

	this.showPlacemark = function(placemark,cancelHandlers){
		var marker = placemark.marker;
		var collection = placemark.collection;
		map.bounds.extend(marker.getPoint());
		map.gmap.addOverlay(marker);
		if(marker.myInfoHTML){
			GEvent.addListener(marker, "click", function() { 
				marker.openInfoWindowHtml(marker.myInfoHTML);
				collection.execHandler('openinfobubble',placemark);
			});
		}
		if(!cancelHandlers)
			collection.execHandler('showhide','showplacemark');
	}

	this.showPlacemarks = function(oc,page,cancelHandlers){
		this.removeOverlays(oc);
		if(!page)
			page = 1;

		oc.currPage = page;

		var placemarks = oc.getPage(page);
		for (var i = 0; i < placemarks.length; i++){
			var labelType = oc.labelType;
			var placemark = placemarks[i];
			if(oc.useLabels){
				placemark.label = (oc.labelType == 'Alpha' ? chr(i + asc('A')) :  i + 1);
			}
			else{
				placemark.label = '';
			}
			var p = new GLatLng(placemark.latitude,placemark.longitude);
			placemark.icon = this.createCustomIcon(oc.getIconStyle(placemark),placemark.label);
			var m = new GMarker(p,{icon:placemark.icon});
			//Add Reverse Lookups
			m.placemark = placemark;
			placemark.marker = m;
			placemark.marker.myInfoHTML = oc.getInfoHTML(placemark);
			this.showPlacemark(placemark,true);
		}
		if(!this.cancelCentering){
			map.setBoundsCenterAndZoom();
		}
		if(!cancelHandlers)
			oc.execHandler('showhide','showplacemarks');
	}

	this.addPlacemarks = function(placemarks,collection,cancelHandlers){
		for (var i = 0; i < placemarks.length; i++){
			var g = placemarks[i];
			var p = new GLatLng(g.latitude,g.longitude);
			//Add Reverse Lookups
			map.addPlacemark(g,collection,true);
		}
		if(!cancelHandlers)
			collection.execHandler('addremove','addplacemarks');
	}

	this.createCustomIcon = function (style,label){
		
		var iconStyle = clone(this.iconStyles[style]);
		iconStyle.image = iconStyle.image.replace('icon:label',label);

		var icon = new GIcon(iconStyle);
		return icon;
	}
	
	this.registerFilter = function(name,filter){
		this.allFilters[name] = filter;
	}
	
	this.initFilters = function(){
		for(var i in this.allFilters){
			this.allFilters[i].run();
		}
	}
	
	this.getVisiblePlacemarks = function(){
		var arr = new Array();
		for (var i in this.collections){
			var p = this.collections[i].getPage(this.collections[i].currPage);
			for(var j = 0; j < p.length; j++){
				arr.push({name:p[j].name,collection:this.collections[i].name,prikey:p[j].prikey});
			}
		}
		return arr;
	}
	//Finds the edges of the icons and sets an adjust zoom level flag if the icon will get cut off
	this.adjustForIcons = function(marker){
		var container = this.gmap.getContainer();
		var containerY = container.scrollHeight;
		var containerX = container.scrollWidth;

		//LatLng of Marker
		var latlng = marker.getLatLng();

		//Convert to Pixel Object
		var divpixels = this.gmap.fromLatLngToContainerPixel(latlng);

		//Placement of icon (in pixels)
		var y = divpixels.y;
		var x = divpixels.x;

		//Width and Height of icon
		var iconWidth = marker.getIcon().iconSize.width;
		var iconHeight = marker.getIcon().iconSize.height;

		//Offset of icon from plotted point
		var anchorWidth = marker.getIcon().iconAnchor.x;
		var anchorHeight = marker.getIcon().iconAnchor.y;

		//Location of top of image (in pixels)
		var iconTop = y - anchorHeight;	
		//Location of bottom of image (in pixels)
		var iconBottom = y + iconHeight - anchorHeight;

		//Location of left edge of icon
		var iconLeft = x - anchorWidth;
		//Location of right edge of icon		
		var iconRight = x + iconWidth + anchorWidth;
		var zoomOut = (iconTop < 0 || iconBottom > containerY || iconLeft < 0 || iconRight > containerX);
		if(zoomOut)
			this.zoomAdjust = -1;
		return zoomOut;
	}
}

/*************************************************
	General Utility Functions
**************************************************/

function addBounds(b1,b2){
	if (b1.isEmpty())
		return b2;
		
	if(b2.isEmpty())
		return b1;

	var southWest = b1.getSouthWest();  
	var northEast = b1.getNorthEast();
	var b3 = new GLatLngBounds();
	b3.extend(southWest);
	b3.extend(northEast);
	var southWest = b2.getSouthWest();  
	var northEast = b2.getNorthEast();
	b3.extend(southWest);
	b3.extend(northEast);
	return b3;
}

function placemarkDistance(p1,p2){
	return distance(parseFloat(p1.latitude),parseFloat(p1.longitude),parseFloat(p2.latitude),parseFloat(p2.longitude));
}

function distance(lat1,lon1,lat2,lon2){
	var R = 6371; // km
	var kpm = 1.609344;  //km per mile
	var dLat = (lat2-lat1).toRad();
	var dLon = (lon2-lon1).toRad(); 
	var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
			Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
			Math.sin(dLon/2) * Math.sin(dLon/2); 
	var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
	var d = (R * c) / kpm;
	return d;
}

function parsePlacemarkData(str,p){
	var fieldlist = ['name','prikey','description','weburl','addr1','addr2','city','state','zip'];
	for (var i = 0; i < fieldlist.length; i++){
		var searchstr = 'placemark:' + fieldlist[i];
		var replacewith = p[fieldlist[i]].length > 300 ? (String(p[fieldlist[i]]).substr(0,300) + '...') : p[fieldlist[i]];
		while (str.indexOf(searchstr) > 0 && searchstr != replacewith){
			str = str.replace(searchstr,replacewith);
		}
	}
	
	if(p.logofile){
		str = str.replace('placemark:logofile', p.logofile.length > 0 ? p.logofile  : 'no_photo.jpg');
	}
	else
		str = str.replace('placemark:logofile', 'no_photo.jpg');
	
	//Only available when the marker is visible on the map
	if(p.icon){
		str = str.replace('placemark:iconimage',p.icon.image);
	}
	if(p.distance){
		str = str.replace('placemark:distance',p.distance.toFixed(2));
	}
	
	if(p.itinerary == true){
		str = str.replace('placemark:itinerary','<b class="itin_added">Added to Backpack</b>');
	}
	else
		str = str.replace('placemark:itinerary','<a href=\"javascript:void(itin_add(' + p.prikey + ', \'cbListing\',\'1\'));\">Add to Backpack</a>');
	
	var addr = new Address();
	try{
		addr.loadFromObject(p);
		str = str.replace('placemark:address',addr.toHTMLString());
	}
	catch(ex){
		alert(ex);
	}


	return str;
}

function chr(num){
	return String.fromCharCode(num);
}

function asc(str){
	return str.charCodeAt(0);
}

function clone(obj){
    if(obj == null || typeof(obj) != 'object')
        return obj;

    var temp = new obj.constructor(); // changed (twice)
    for(var key in obj)
        temp[key] = clone(obj[key]);

    return temp;
}

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}

//Itinerary Add Function
function itin_add(listingid)
{
	var thisUrl  = imgroot+'/itinerary/index.cfm';
	var thisData = 'action=ajax_addItin&listingid='+listingid; 

	new Ajax.Request(thisUrl,
		{
			method: 'post',
			parameters: thisData,
			onSuccess: function (response){
					updatePlacemarkItinerary(listingid);
					return true;
				},
		   onFailure: function(response){
			   alert('Could not add to itinerary');
		   }
		}
	);
}

//Itinerary Function
function updatePlacemarkItinerary(prikey){
	for (var i in placemarks){
		var p = findPlacemark(i,prikey);
		if(p != null){
			var tmp = $('placemark_itinerary_' + prikey);
			if(tmp){
				//tmp.innerHTML = 'Added to Backpack';
			}
			p.itinerary = true;
			if(p.marker && p.collection){
				p.marker.myInfoHTML = p.collection.getInfoHTML(p);
			}
		}
	}
	transferFromOverlays(prikey,itineraryOverlays);
	goToPlacemark(prikey);
}