var FOXTONS = new Object();
FOXTONS.Mapping = new Object();
FOXTONS.Mapping.Groups = new Array();

//index
function animateFeature(){
	var left_px = parseFloat($('#feature_image').css("marginLeft"));
	var direction = left_px >= 0 ? "-" : "+";
	$('#feature_image').animate({
		"marginLeft": direction + "=900px"
	}, 20000, "linear", function(){
		animateFeature();
	});
}

function mycarousel_initCallback(carousel)	{
    // Pause autoscrolling if the user moves with the cursor over the clip.
    carousel.clip.hover(function() {
        carousel.stopAuto();
    }, function() {
        carousel.startAuto();
    });
};
	
jQuery(document).ready(function() {
    jQuery('#featured_properties').jcarousel({
        auto: 3,
        wrap: 'last',
        initCallback: mycarousel_initCallback
    });
	animateFeature();
});

//property
var close_tab_timeout;
	function sliderTabOpen(tabname) {
		if(close_tab_timeout){
			clearTimeout(close_tab_timeout);
		}
		sliderTab(tabname, 'open');
	}
	
	function sliderTabClose(tabname) {
		close_tab_timeout = setTimeout(function(){
			sliderTab(tabname, 'close');
		},520);
	}	
	function sliderTab (tabname, mode) {
		var selected_margin = tabname == "left" ? "marginLeft" : "marginRight";
		
		var animate_properties = {};
		
		// find available space to move into each side of main photo
		var slide_px = ($(window).width() - $('#container').width()) / 2;
		var max_slideout_px = 300;
		slide_px = slide_px > max_slideout_px ? max_slideout_px : slide_px;

		animate_properties[selected_margin] = mode == 'close' ? '0px' : '-'+slide_px.toString()+'px';			
		
		var animate_options = {
			duration: 250,
			queue: false
		};
		$('#feature_tab_'+tabname).animate(animate_properties, animate_options);
	}
	


	

//////////////////////////////////////////////////////////////////////////////

//BING MAPS 

//////////////////////////////////////////////////////////////////////////////
function BingGeocodeCallback(results){
	FOXTONS.Maps.processGeoResults(results);
}


////////////////// MAPPING ///////////////////////////////
var pushpinFrameHTML = '<div class="infobox"><a class="infobox_close" href="#" onclick="FOXTONS.Maps.closeInfobox();return false;"><img src="/i/close.gif"/></a><div class="infobox_content">{content}</div></div><div class="infobox_pointer"><img src="/i/infobox_pointer.png"></div>';

FOXTONS.Maps = {
	map    			: null,
	credentials 	: 'AqjLeRcQZ0cqo5WrQMs0uV9XeslBntL1jfQrdkUH4_NEQzBCnMed_doV58d9s4-w',
	infobox 		: null,
	cached : { // loads when user returns to original map after pressin back. Populated from ..getMapPrefs();
		start_location 	: null,
		zoom : null
	},
	layers : {
		pins 	  : null,
		pins_expanded : null,
		offices   : null,
		schools   : null,
		transport : null,
		infoxbox  : null,
		route	  : null,
		waypoints : null
	},
	newMap : function(config){
		// defaults to central London
		var latlon =  new Microsoft.Maps.Location(config.lat || 51.512264, config.lon || -0.157723);
		var map_options = {
				credentials 		: this.credentials,
				center 				: this.cached.start_location || latlon,
				zoom 				: this.cached.zoom || config.zoom || 14,
				mapTypeId			: Microsoft.Maps.MapTypeId[config.mapType || "collinsBart"],
				useInertia 			: true,
				inertiaIntensity 	: 0,
				tileBuffer 			: 1,
				enableSearchLogo 	: false,
				enableClickableLogo : false,
				showScalebar 		: false
			}
		// update cache
		this.cached.start_location = latlon;
		
		// store ref to map element
		this.map_id = config.element || "mapviewer";
		
		// display map
		this.map = new Microsoft.Maps.Map(document.getElementById(this.map_id), map_options);
		
		this.setUpLayers(latlon);
		
		// geoencode address (don't display marker)
		if(config.address){
			this.geoEncodeAddress(config);
			// store pin config in namespace ready for callback from Bing
			this.cached.pin_config = config;
		}else{
			// lat lon must already exist for marker
			if(config.icon){
			// create center marker
				this.createMarker(latlon, {
					id		 : config.id || 0,
					type	 : config.icon.type || "house",
					title 	 : config.icon.title || "",
					img 	 : config.icon.img || null,
					path	 : config.icon.path || null,
					no_infobox : config.icon.no_infobox || false,
					draggable  : config.icon.draggable || false
				});
			}
		}
	},
	
	setUpLayers : function(latlon){
		// SET UP LAYERS FOR ENTITIES LIKE PINS, INFOBOXES, ROUTES ETC
		// set up layer for pins
		this.layers.pins = new Microsoft.Maps.EntityCollection();
		this.map.entities.push(this.layers.pins);
		this.layers.pins.setOptions({zIndex : 10});

		// make sure expanded search icons are behind main search icons
		this.layers.pins_expanded = new Microsoft.Maps.EntityCollection();
		this.map.entities.push(this.layers.pins_expanded);
		this.layers.pins_expanded.setOptions({zIndex : 5});
		
		
		this.layers.offices = new Microsoft.Maps.EntityCollection();
		this.map.entities.push(this.layers.offices);
		this.layers.offices.setOptions({zIndex : 4});
		
		
		this.layers.transport = new Microsoft.Maps.EntityCollection();
		this.map.entities.push(this.layers.transport);
		this.layers.transport.setOptions({zIndex : 6});
		
		// set up infobox layer
		this.layers.infobox = new Microsoft.Maps.EntityCollection();
		this.map.entities.push(this.layers.infobox);
		
		// Create the info box for the pushpin
		this.infobox = new Microsoft.Maps.Infobox(latlon, {visible: false});
		this.layers.infobox.push(this.infobox);
		this.layers.infobox.setOptions({zIndex : 1000});
	},
	
	createMarker : function(latlon, config){
		// create default pin options
		var icon_options = {
			typeName : 'map_marker', // class name
			width : 20,
			height: 21 
		};
		if(config && config.icon){
			icon_options.draggable = config.icon.draggable ? true : false;
		}
		var icon_file_extra = "";
		if(config.expanded_search){
			icon_file_extra = "_inactive";
			icon_options.width = 12;
			icon_options.height = 12;
			// hide expanded icons BEHIND main search icons
			icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, 17);
		}

		// which icon
		switch (config.type){
			case "office" :
				icon_options.icon = '/i/logos/roundel_25.gif';
				icon_options.width = 25;
				icon_options.height = 25;
				icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, icon_options.height/2);
				break;
			case "tube_station" :
				icon_options.icon = '/i/icons/tube_ring.png';
				icon_options.width = 33;
				icon_options.height = 33;
				icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, icon_options.height/2);
				break;
			case "tube" :
				icon_options.icon = '/i/icons/tube_marker_pin.png';
				break;
			case "train" :
				icon_options.icon = '/i/icons/train_marker_pin.png';
				break;
			case "coach" :
				icon_options.icon = '/i/icons/coach_marker_pin.png';
				break;
			case "school" :
				icon_options.icon = '/i/icons/school_ring.png';
				icon_options.width = 33;
				icon_options.height = 33;
				icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, icon_options.height/2);
				break;
			case "site" :
			case "house" :
			case "House" :
				icon_options.icon = '/i/icons/house_marker_pin'+icon_file_extra+'.png';
				break;
			case "flat" :
			case "Flat" :
				icon_options.icon = '/i/icons/flat_marker_pin'+icon_file_extra+'.png';
				break;
			case "parking" :
			case "Garage" :
				icon_options.icon = '/i/icons/car_marker_pin'+icon_file_extra+'.png';
				break;
			case "boat" :
			case "Houseboat" :
				icon_options.icon = '/i/icons/boat_marker_pin'+icon_file_extra+'.png';
				break;
			case "brand" :
				icon_options.icon = "/i/icons/office_boundaries_marker.png";
				icon_options.width = 24;
				icon_options.height = 28;
				icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, icon_options.height/2);
				break;
			case "disc" :
				icon_options.icon = "/i/icons/pin_disc.png";
				icon_options.width = 20;
				icon_options.height = 20;
				icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, icon_options.height/2);
				break;
			default :
				icon_options.icon = '/i/marker_3.png';
				icon_options.width = 33;
				icon_options.height = 33;
				icon_options.anchor = new Microsoft.Maps.Point(icon_options.width/2, icon_options.height/2);
				break;	
		}

		var pin = new Microsoft.Maps.Pushpin(latlon, icon_options);
		// add data into each pin (to be accessed later on click for eg)
		pin.Metadata = {
			id 	  : config.id || config.prop_id || null,
			type  : config.type  || "",
			title : config.title || "",
			img	  : config.img 	 || null,
			path  : config.path  || "#",
			data  : config.data  || null,
			pc	  : config.pc    || null,
			do_route : config.do_route || false
		};
		
		// push pin into relevant entity layer
		if(config.expanded_search){
			this.layers.pins_expanded.push(pin);
		}else if(config.type == "office"){
			this.layers.offices.push(pin);
		}else if(config.type == "tube" || config.type == "train" || config.type == "coach"){
			this.layers.transport.push(pin);
		}else{
			this.layers.pins.push(pin);
		}
		
		// assign clickhandler for infobox
		if(!config.no_infobox || (config.icon && !config.icon.no_infobox) ){
			Microsoft.Maps.Events.addHandler(pin, 'click', this.openInfobox);
		}
	},
	
	// parameter 'e' can be either:
		// 1) onclick event info from BING
		// 2) force of pin data from external link (eg clicking on a train station outside map)
	openInfobox : function(e){
		var self = FOXTONS.Maps;
		
		var pin = null;
		
		if (e && e.targetType){
			 if (e.targetType == "pushpin"){
				pin = e.target;
			 }
		}else{
			pin = e;
		}
		
		// got valid pin data?
		if (pin){
			//Generate infobox content on demand rather than advance. Makes for better performance.
			var html = [];	//array used to concat string for better performance.
			
			if(pin && pin.Metadata){
				if(pin.Metadata.id){
					pin.Metadata.path = self.url_stub + "&property_id="+pin.Metadata.id;
				}
				// title
				html.push('<h3><a href="'+pin.Metadata.path+'" onclick="FOXTONS.Maps.setMapPrefs();">'+pin.Metadata.title+'</a></h3>');
				
				// image
				if(pin.Metadata.img){
					html.push('<a href="'+pin.Metadata.path+'" onclick="FOXTONS.Maps.setMapPrefs();"><img alt="" src="', pin.Metadata.img, '"/></a>');
				}
				
				// offices
				if(pin.Metadata.type == "office"){
					html.push("<p>" + pin.Metadata.data.address + "<br />Call " + pin.Metadata.data.tel +"</p>");
				}
				
				// schools
				if(pin.Metadata.title && pin.Metadata.type == "school"){
					html.push("<p class='cta'><a href='"+pin.Metadata.path+"' onclick='FOXTONS.Maps.setMapPrefs();'>School details</a></p>");
					if(pin.Metadata.do_route){
						html.push("<p class='cta'><a href='#' onclick='$(\"#map_alert\").dialog(\"open\");return false;'>Walking directions to this school</a></p>");
					}
			
					if(self.new_search_url){
						html.push("<p class='cta'><a href='"+self.new_search_url+"&center_point_name="+escape(pin.Metadata.title)+"&lat=" + self.cached.start_location.latitude + "&lon=" + self.cached.start_location.longitude + "'>Properties around this school</a></p>");
					}
				}
				
				// transport
				if(pin.Metadata.type == "tube" || pin.Metadata.type == "train" || pin.Metadata.type == "coach" || pin.Metadata.type == "airport"){
	
					if(pin.Metadata.type == "tube" && pin.Metadata.data){
						html.push("<p>"+pin.Metadata.data+"</p>");
					}
					if(pin.Metadata.type == "tube" || pin.Metadata.type == "train"){
						// can overrule walking link if needed
						if(!pin.Metadata.no_walking_link){
							html.push("<p class='cta'><a href='#' onclick='$(\"#map_alert\").dialog(\"open\");return false;'>Walking directions</a></p>");
						}
					}
					if(pin.Metadata.pc){
						html.push("<p class='cta'><a href='#' onclick='sendPC(\""+pin.Metadata.pc+"\");return false;'>Public transport directions</a></p>");
					}
					if(self.new_search_url && (pin.Metadata.type == "tube" || pin.Metadata.type == "train") ){
						html.push("<p class='cta'><a href='"+self.new_search_url+"&transport_location="+escape(pin.Metadata.title)+"'>Properties around this station</a></p>");
					}
				}
			}
			
			
			
			var infobox = self.infobox;
			infobox.setOptions({ 
				visible:true, 
				offset: new Microsoft.Maps.Point(-40, 16), 
				showPointer : true,
				htmlContent: pushpinFrameHTML.replace('{content}', html.join(''))
			});
			
			// anchor infobox to pin
			infobox.setLocation(pin.getLocation());
			
			// make sure all the open infobox fits in mapview
			self.positionInfobox(pin);
			
			
			if(pin.Metadata.do_route){
				self.createDirections(self.cached.start_location, pin.getLocation());
			}
		}
    },
	
	positionInfobox : function(pin){
		//Below logic determines if the map needs to move or not.
		var infobox = this.infobox;
		//A buffer limit to use to specify the infobox must be away from the edges of the map.
		var buffer = 25; 
		
		var infoboxOffset = infobox.getOffset();
		var infoboxAnchor = infobox.getAnchor();
		var infoboxLocation = this.map.tryLocationToPixel(pin.getLocation(), Microsoft.Maps.PixelReference.control);

		var dx = infoboxLocation.x + infoboxOffset.x - infoboxAnchor.x;
		var dy = infoboxLocation.y - buffer - infoboxAnchor.y;
		
		if(dy < buffer){	//Infobox overlaps with top of map.
			//Offset in opposite direction.
			dy *= -1;
			
			//add buffer from the top edge of the map.
			dy += buffer;
		}else{
			//If dy is greater than zero than it does not overlap.
			dy = 0;
		}
		if(dx < buffer){	//Check to see if overlapping with left side of map.
			//Offset in opposite direction.
			dx *= -1;
			//add a buffer from the left edge of the map.
			dx += buffer; 
		}else{		//Check to see if overlapping with right side of map.
			dx = this.map.getWidth() - infoboxLocation.x + infoboxAnchor.x - infobox.getWidth();
			
			//If dx is greater than zero then it does not overlap.
			if(dx > buffer){
				dx = 0;
			}else{
				//add a buffer from the right edge of the map.
				dx -= buffer;
			}
		}
		if(dx != 0 || dy != 0){
			this.map.setView({ centerOffset : new Microsoft.Maps.Point(dx,dy), center : this.map.getCenter()});
		}
		
		// get current map options so we can return to this config after route has loaded
		this.options = this.map.getOptions();
		// extend 
		this.options.zoom = this.map.getZoom();
		this.options.center = this.map.getTargetCenter();
	},
		
	closeInfobox : function(){
		this.infobox.setOptions({visible:false});
	},
	
	geoEncodeAddress : function(config){
		var address = config.address;
		var geocodeRequestPath = " http://dev.virtualearth.net/REST/v1/Locations/"+ address +"/?culture=en-GB&userLocation=51.504360719046616,-0.12600176611298197&output=json&jsonp=BingGeocodeCallback&key="+this.credentials;
		
		// is it a postcode or location, uses the regex near end of document to clean up postcode/location
		if( FOXTONS.Validation.isValidPostcode(address) ){	
			geocodeRequestPath += "&postalCode="+ address;
		}else{
			geocodeRequestPath += "&addressLine="+ address;
		}
		var script = document.createElement("script");
			script.setAttribute("type", "text/javascript");
            script.setAttribute("src", geocodeRequestPath);
            document.body.appendChild(script);
	},
	
	processGeoResults : function(results){
		var MM = Microsoft.Maps;
		var rs = results.resourceSets[0];
		var total_results = rs.resources.length;

		// if there are no matches or postcode/location is incorrect then show error message and hide map
		if (rs.estimatedTotal == 0 || rs.resources[0].name == 'United Kingdom') {		
			document.getElementById(this.map_id).style.display  = 'none';
			if(document.getElementById('error')){
				document.getElementById('error').style.display = 'block';
			}	
		} else {
			// show a list of matches
			if(total_results > 1){
				if(document.getElementById('resultspanel')){
					document.getElementById('resultspanel').style.display = 'block';
					var results_list = document.getElementById("results_list");
				}
			}
			// 1 or more results
			for (var i=0;i<total_results; i++) {
	
				// get result details and latlon
				var address = rs.resources[i].address.formattedAddress;
				var coords  = rs.resources[i].point.coordinates;
			
				// get info for marker
				var latlon  = new MM.Location(coords[0],coords[1]);

				if(this.cached.pin_config && this.cached.pin_config.icon){
					this.createMarker(latlon, this.cached.pin_config);
				}
				
				// build result list in HTML
				if(total_results > 1 && document.getElementById('resultspanel')){
					var map_link =
						['<li><a href="#" onclick="',
							'FOXTONS.Maps.map.setView(',
							'{center: new Microsoft.Maps.Location(',
							coords[0]+ ',' +coords[1],
							'), zoom: 16}',
							'); return false;">',
							''+address,
							'</a></li>'].join('');
					results_list.innerHTML += map_link;
				} else {
					this.map.setView({ center: latlon });
				}		
			}
		}
		// hide loading indicator if there
		$('#loading').hide();
	},
	
	setMapPrefs : function(){
		// get current hash
		var url_hashes = getURLHashParams();
		
		// store existing school level if present
		var school_data = "";
		if(url_hashes.school_type){
			school_data = "|school_type="+url_hashes.school_type;
		}
	
		var d = document.location;
		var core_url = "";
		// remove old params?
		if(d.href.indexOf('#') != -1){
			core_url = d.href.split("#")[0];
		}
		// append current position to map (plus existing params) for revision on back button
		d.replace(core_url+"#map="+this.map.getCenter().latitude+","+this.map.getCenter().longitude+"," + this.map.getZoom()+school_data);
	},
	
	getMapPrefs : function(){
		// reload to previous position?
		var url_hashes = getURLHashParams();
		if(url_hashes.map){
			var map_params    		 	= url_hashes.map.split(",");
			this.cached.start_location 	= new Microsoft.Maps.Location(map_params[0], map_params[1]);
			this.cached.zoom	 		= parseInt(map_params[2]);
		}
	}

}

