
var ParkingFinder = new Class({
	Implements: [Options, Events],
	options: {
		urlGetList: "/find-parking/list",
		urlGetLocation: "/find-parking/get-location",
		urlGetIntersection: "/find-parking/get-location",
		urlGetVenue: "/find-parking/get-location",
		urlGetResults: "/find-parking/find",
		urlStreetKML: '/find-parking/street-parking',
		imgPm: '/images/map/gp_placemark.png',
		imgPmHigh: '/images/map/gp_placemark_hover.png',
		imgPmShd: '/images/map/gp_placemark_shadow.png',
		imgSearch: '/images/map/gp_searchicon.png',
		imgSearchShd: '/images/map/gp_searchicon_shadow.png',
		elmap: 'map-canvas',
		elmapstreet: 'map-street',
		elmapstreetclose: 'map-street-close',
		elmapcont: 'map-container',
		elmapscr: 'map-screen',
		elres: 'results',
		elresnr: 'search-no-results',
		elrescnt: 'search-results',
		elresitems: 'results-items',
		elmsg: 'map-message',
		elloader: 'map-loader',
		elmsgnr: 'no-results',
		elmsgfe: 'form-empty',
		elmsgdym: 'dym',
		btnPrevResults: 'a.go-back-results',
		btnNextResults: 'a.see-more-results',
		btnSortDistance: '#sort-dist a',
		btnSortRate: '#sort-price a',
		btnStreet: '#street-parking-button a',
		btnClose: '.but-close a',
		resultsToList: 5
	},
	initialize: function(form, options){
	
		this.form = form;
		this.setOptions(options);
	
		// blocks
		this.elmap = $(this.options.elmap);
		this.elmapstreet = $(this.options.elmapstreet);
		this.elmapstreetclose = $(this.options.elmapstreetclose);
		this.elmapcont = $(this.options.elmapcont);
		this.elmapscr = $(this.options.elmapscr);
		this.elres = $(this.options.elres);
		this.elresnr = $(this.options.elresnr);
		this.elrescnt = $(this.options.elrescnt);
		this.elresitems = $(this.options.elresitems);
		this.elmsg = $(this.options.elmsg);
		this.elloader = $(this.options.elloader);
		this.elmsgnr = $(this.options.elmsgnr);
		this.elmsgdym = $(this.options.elmsgdym);
		this.elmsgfe = $(this.options.elmsgfe);
		
		
		
		// create the map
		this.map = new GMap2(document.getElementById(this.options.elmap));
		this.mapCenter = new GLatLng("43.670233","-79.386755");
		this.mapZoom = 12;
		this.map.setCenter(this.mapCenter, this.mapZoom);
		this.map.addControl(new GLargeMapControl3D());
		
		this.pmIcon = new GIcon(G_DEFAULT_ICON);
		this.pmIcon.image = this.options.imgPm;
		this.pmIcon.shadow = this.options.imgPmShd;
		this.pmIcon.highlight =  this.options.imgPmHigh;
		this.pmIcon.iconSize = new GSize(32, 32);
		this.pmIcon.shadowSize = new GSize(55, 32);
		this.pmIcon.iconAnchor = new GPoint(32, 32);
		this.pmIcon.imageMap = [0,0, 32,0, 32,32, 0,32];
		
		this.searchIcon = new GIcon(G_DEFAULT_ICON);
		this.searchIcon.image = this.options.imgSearch;
		this.searchIcon.shadow = this.options.imgPmShd;
		this.searchIcon.iconSize = new GSize(32, 32);
		this.searchIcon.shadowSize = new GSize(55, 32);
		this.searchIcon.iconAnchor = new GPoint(32, 32);
		this.searchIcon.imageMap = [15,15, 16,15, 15,15, 15,16];
		
		
		// Set up our GMarkerOptions object
		this.cpMarker = { icon:this.pmIcon };
		this.searchMarkerOpt = { icon:this.searchIcon };
			
		// create manager
		this.mgr = new MarkerManager(this.map);
			
		// set loaded false (will flip to true on load)
		this.cpLoaded = false;
		
		// load  the points
		var jsonRequest = new Request.JSON({
			url: this.options.urlGetList, 
			onRequest: function() {},
			onComplete: this.loadCarparks.bind(this)
		}).get();
		
		
		
		// bind the address button
		this.form.aform.addEvent('submit', function(event) {
			this.formsrc = 'a';
			this.findLocation(event);
		}.bind(this));
		this.form.iform.addEvent('submit', function(event) {
			this.formsrc = 'i';
			this.findLocation(event);
		}.bind(this));
		this.form.vform.addEvent('submit', function(event) {
			this.formsrc = 'v';
			this.findLocation(event);
		}.bind(this));
		
		
		
		
		// init the street parking 
		this.initStreet();
		
		
		// init the street view 
		this.initStreetView();
		
		
		// init close buttons
		$(document).getElements(this.options.btnClose).each(function (button, index) {
			button.addEvent('click', function(event) {
				event.preventDefault();
				this.msgClear();
			}.bind(this));		
		}, this);
		
		// init prev/next result buttons
		this.btnPrevResults = $(document).getElement(this.options.btnPrevResults);
		this.btnNextResults =  $(document).getElement(this.options.btnNextResults);
		this.btnPrevResults.addEvent('click', function(event) {
			event.preventDefault();
			this.showPrevResults();
		}.bind(this));
		this.btnNextResults.addEvent('click', function(event) {
			event.preventDefault();
			this.showNextResults();
		}.bind(this));
		
		
		// init sort result buttons
		this.btnSortDistance = $(document).getElement(this.options.btnSortDistance);
		this.btnSortRate = $(document).getElement(this.options.btnSortRate);
		
		this.btnSortDistance.addEvent('click', function(event) {
			event.preventDefault();
			if (!this.btnSortDistance.hasClass('current')) {
				this.btnSortDistance.addClass('current');
				this.btnSortRate.removeClass('current');
				this.queryResults('distance');
			}
		}.bind(this));
		this.btnSortRate.addEvent('click', function(event) {
			event.preventDefault();
			if (!this.btnSortRate.hasClass('current')) {
				this.btnSortDistance.removeClass('current');
				this.btnSortRate.addClass('current');
				this.queryResults('rate');
			}
		}.bind(this));
		
		
		// if address is loaded, fire right away
		
		// initial query?
		// lat/lng passed in, load it!
		this.direct_query = location.search.substr(1).parseQueryString();
		if (this.direct_query.lat && this.direct_query.lng) {
			this.showScreen();
			this.directLocation();
		}
		else if (this.form.aValue()) {
			this.formsrc = 'a';
			this.showScreen();
			this.findLocation();
		} 
		else if (this.form.iValue()) {
			this.formsrc = 'i';
			this.showScreen();
			this.findLocation();
		} 
		else if (this.form.vValue()) {
			this.formsrc = 'v';
			this.showScreen();
			this.findLocation();
		} 
		
		
	},
	
	
	initStreet: function() {
		
		// get the street button
		this.btnStreet = $(document).getElement(this.options.btnStreet);
		this.streetOverlay = new GGeoXml(this.options.urlStreetKML);
		this.streetsShowing = false;
		
		// create the event toggle
		this.btnStreet.addEvent('click', this.clickStreet.bindWithEvent(this));
	},
	
	clickStreet: function(e) {
		e.preventDefault();
		if (this.streetsShowing) {
			this.map.removeOverlay(this.streetOverlay);
			this.streetsShowing = false;
			this.btnStreet.removeClass('current');
		} else {
			this.map.addOverlay(this.streetOverlay);
			this.streetsShowing = true;
			this.btnStreet.addClass('current');
		}
		
	},
		
	resetMapView: function() {
		
		this.elres.setStyle('display', 'none');
		this.elmapcont.addClass("map-wide");	
		this.map.checkResize();
		this.map.setCenter(this.mapCenter, this.mapZoom);
		this.map.savePosition();
		
		if (this.searchMarker) {
			this.mgr.removeMarker(this.searchMarker);
		}				
	},
	
	msgClear: function() {
		this.clearScreen();
		this.elmsg.setStyle('display', 'none');
		this.elmsg.getElements('.message').setStyle('display', 'none');
	},
	
	msgNoResults: function() {		
		this.showScreen();
		this.clearLoader();
		this.elmsgnr.getElement('span').set('html', this.query);
		this.elmsg.setStyle('display', 'block');
		this.elmsgnr.setStyle('display', 'block');		
		this.elmapscr.addEvent('click', this.msgClear.bind(this));
	},
	
	msgFormEmpty: function() {		
		this.showScreen();
		this.clearLoader();
		this.elmsg.setStyle('display', 'block');
		this.elmsgfe.setStyle('display', 'block');		
		this.elmapscr.addEvent('click', this.msgClear.bind(this));
	},
	
	showScreen: function () {
		if (!this.screenState) {
			this.elmapscr.setStyles({
				'display': 'block',
				'opacity': 0.7
			});
			this.elloader.setStyle('display', 'block');
		}
		this.screenState = true;
		
	}, 
	
	clearLoader: function() {
		this.elloader.setStyle('display', 'none');		
	},
	
	clearScreen: function() {
		this.elmapscr.setStyles({
			'opacity': 1,
			'display': 'none'
		});
		this.screenState = false;
		
		this.elmapscr.removeEvents();		
	},
	
	/*
	 * Load location directly via query string lat/lng
	 * 
	 */
	directLocation: function() {
		
		// block until cpLoaded
		if (!this.cpLoaded) {
			this.directLocation.delay(100, this);
			return;
		}
		
		var address =  this.direct_query.v.replace(/\+/g, " ");
		this.form.clear_v = address;
		
		this.loadLocation({
			latitude: this.direct_query.lat,
			longitude: this.direct_query.lng,
			address: address
		});
			
	},

	
	/*
	 * Handle the form input
	 * 
	 */
	findLocation: function(e) {
		
		// prevent form submit
		if (e) {
			var event = new Event(e);
			event.preventDefault();
		}
		
		// block until cpLoaded
		if (!this.cpLoaded) {
			this.findLocation.delay(100, this);
			return;
		}
		
		
		
		// reset the map view
		this.resetMapView();
		
		// reset locations cacche
		this.locations = new Array();
		
		// clear the message, show the screen
		this.msgClear();
		this.showScreen();
		
		// what type of input?
		var getUrl;
		if (this.formsrc == 'a') {
			getUrl = this.options.urlGetLocation;
			this.query = this.form.aValue();
		}
		if (this.formsrc == 'i') {
			getUrl = this.options.urlGetIntersection;
			this.query = this.form.iValue();
		}
		if (this.formsrc == 'v') {
			getUrl = this.options.urlGetVenue;
			this.query = this.form.vValue();
		}
		
		// error if no input		
		if (!this.query) {
			return this.msgFormEmpty();
		}		
	
						
		
		// load  the points
		var jsonRequest = new Request.JSON({
			url: getUrl, 
			onRequest: function() {},
			onComplete: this.loadLocations.bind(this)
		}).post({
			'address': this.query,
			'cb': parseInt(Math.random()*99999999)
		});
	},
	
	
	/*
	 * Handle the Locations response
	 *  
	 */
	loadLocations: function(response, text){
						
		if (!response) {
			return;
		}
		if (response.error && response.error == 'no_result') {
			this.msgNoResults();
			return;
		}			
		
		this.locations = response.results;
		
		if (this.locations.length == 1) {
			this.loadLocation(this.locations[0]);
		} else {
			this.msgDYM();			
		}
		
	},
	
	
	msgDYM: function() {
		
		this.clearLoader();
		
		var ellocs = this.elmsgdym.getElement('ul');
		ellocs.set('html', '');
		
		ellocs.setStyles({
			'list-style': 'none'
		});
		
		for (i = 0; i <this.locations.length; i++) {
			var location = this.locations[i];
			
			var inhtml = '<strong>' + location.address + '</strong>';
			
			var el = new Element('li', {'html': inhtml});
			el.setStyles({
				'cursor': 'pointer'
			});
			
			el.addEvent('click', this.clickLocation.bindWithEvent(this,i));
						
			// inject id
			el.inject(ellocs);
			
		}	
		
		this.elmsg.setStyle('display', 'block');
		this.elmsgdym.setStyle('display', 'block');		
		this.elmapscr.addEvent('click', this.msgClear.bind(this));
	},
	
	clickLocation: function(event, i) {		
		this.loadLocation(this.locations[i]);		
	},
	
	
	loadLocation: function(location) {
		
		// clear the screen if showing
		this.msgClear();
		
		// save the location marker
		this.location = location;
		
		
		// narrow the map
		this.elmapcont.removeClass("map-wide");
		this.map.checkResize();
		
		// expose results (but empty)
		this.elres.setStyle('display', 'block');
		this.elresnr.setStyle('display', 'none');
		this.elrescnt.setStyle('display', 'none');
		this.elresitems.getChildren().dispose();
		
		// reset the page
		this.resultsPage = 0;
		
		// add the address to the results pane
		this.elres.getElement('#search-input').set('html', location.address);
						
						
		// center the map
		this.searchPoint = new GLatLng(this.location.latitude, this.location.longitude);
		this.map.setCenter(this.searchPoint, 15);
		this.map.savePosition();
		
		// add center marker
		this.searchMarker = new GMarker(this.searchPoint, this.searchMarkerOpt);
		this.mgr.addMarker(this.searchMarker, 1);
				
		// query for the results
		this.queryResults('distance');
		
	},
	
	queryResults: function(sort) {
		// load the results pane
		var jsonRequest = new Request.JSON({
			url: this.options.urlGetResults, 
			onRequest: function() {},
			onComplete: this.loadResults.bind(this)
		}).post({
			'lat': this.location.latitude,
			'long': this.location.longitude,
			'sort': sort,
			'cb': parseInt(Math.random()*99999999)
		});
	},

	loadResults: function(response, text) {
		
		this.numResults = 0;
		if (response.carparks) {
			this.results = [];
			this.resultsIdx = [];
			this.resultSelected = null;

			var results = response.carparks;
			this.numResults = results.length;
			
			for (i = 0; i < this.numResults; i++) {
				var carpark_id = results[i].id;
				var distance = results[i].distance;

				var inhtml = '<h2 class="unit">' + distance + '<span>km</span></h2>';

				inhtml += '<h3 class="result-address">' +  this.carparks[carpark_id].address + '</h3>';
				if (this.carparks[carpark_id].rate)
					inhtml += '<h4 class="result-price">Rate: ' +  this.carparks[carpark_id].rate ;
				inhtml += '<div class="clear"><!-- --></div>';

				var el = new Element('div', {'class':'results-item','html': inhtml});
				
				
				// inject id
				//el.inject(this.elresitems);
				this.resultsIdx[i] = carpark_id;
				this.results[carpark_id] = el;
				
				el.addEvent('click', this.clickResult.bindWithEvent(this,carpark_id));
				el.addEvent('mouseenter', this.mouseEnterResult.bindWithEvent(this,carpark_id));
				el.addEvent('mouseleave', this.mouseLeaveResult.bindWithEvent(this,carpark_id));
				
				//el.addEvent('mouseenter', function() { this.addClass('hover')});
				//el.addEvent('mouseleave', function() { this.removeClass('hover')});
				
			}		
			
			// if there are results, show them
			if (this.numResults) {
				this.page = 0;
				this.showResults();
			} else {
				this.noResults();
			}
		} 
	},
	
	showResults: function() {
		
		this.elrescnt.setStyle('display', 'block');
		this.elresitems.getChildren().dispose();
		
		var start_pos = this.page * this.options.resultsToList;
		if (start_pos > this.results.length) 
			start_pos = 0;
		
		var end_pos = start_pos + this.options.resultsToList;
		if (end_pos > this.results.length) 
			end_pos = this.results.length;
		
		for (i = start_pos; i < end_pos; i++) {
			var el = this.results[this.resultsIdx[i]];
			if (el)
				el.inject(this.elresitems);
		}
		
		var next_pos = (this.page + 1) * this.options.resultsToList;
		if (next_pos < this.numResults) {
			this.hasNextResults = true;
			this.showNextButton(true);
		} else {
			this.hasNextResults = false;
			this.showNextButton(false);
		}
		
		if (this.page > 0) {	
			this.hasPrevResults = true;
			this.showPrevButton(true);
		} else {
			this.hasPrevResults = false;
			this.showPrevButton(false);
		}
		
	},
	
	showNextButton: function(state) {
		if (state == true) {
			this.btnNextResults.setStyle('display', 'block');
		} else {
			this.btnNextResults.setStyle('display', 'none');
		}
	},
	
	showNextResults: function() {
		if (this.hasNextResults) {
			this.page++;
			this.showResults();
		}	
	},
	
	showPrevButton: function(state) {
		if (state == true) {
			this.btnPrevResults.setStyle('display', 'block');
		} else {
			this.btnPrevResults.setStyle('display', 'none');
		}
	},
	
	showPrevResults: function() {
		if (this.hasPrevResults) {
			this.page--;
			this.showResults();
		}		
	},
	
	
	noResults: function() {
		this.elresnr.setStyle('display', 'block');	
	},
	
	clickResult: function (event, carpark_id) {		
		this.closeResult();
		this.resultSelected = carpark_id;
		this.results[carpark_id].addClass('selected');		
		GEvent.trigger(this.carparks[carpark_id].placemark, 'click');		
	},
	
	mouseEnterResult: function (event, carpark_id) {		
		this.results[carpark_id].addClass('hover');
		GEvent.trigger(this.carparks[carpark_id].placemark, 'mouseover');		
		
	},
	mouseLeaveResult: function (event, carpark_id) {		
		this.results[carpark_id].removeClass('hover');
		GEvent.trigger(this.carparks[carpark_id].placemark, 'mouseout');	
	},
	
	mapClickResult: function (marker, point) {		
		if (marker != null) {
			var carpark_id = marker.carpark_id;
			if (carpark_id && this.results && this.results[carpark_id] && carpark_id != this.resultSelected) {
				this.clickResult(null, carpark_id);
			}		
		}
	},
	
	closeResult: function() {
		if (this.resultSelected != null) {
			this.results[this.resultSelected].removeClass('selected');
			this.resultSelected = null;
		}			
	},
	
	
	loadCarparks: function(response, text){
		carparks = response.carparks;
		if (carparks) {
			this.carparks = new Array();
			var placemarks = [];
			for (var i in carparks) {
				
				var carpark = carparks[i];
				var carpark_id = carpark.id;
				var point = new GLatLng(carpark.lat, carpark.lng);
				carpark.placemark = new GMarker(point, this.cpMarker);
				
				/*
				 * Set HTMLK
				 */				
				var overviewHtml;
				if (carpark.overviewHtml) {
					overviewHtml = carpark.overviewHtml;
				}
				else {
					overviewHtml = " ";
				}
				overviewNode = new Element("div", {
					'class': 'overview-container',
					'html': overviewHtml
				});
				
				var ratesHtml;
				if (carpark.ratesHtml) {
					ratesHtml = carpark.ratesHtml;
				}
				else {
					ratesHtml = " ";
				}
				ratesNode = new Element("div", {
					'class': 'rates-container',
					'html': ratesHtml
				});
				
				carpark.placemark.bindInfoWindowTabs([
					new GInfoWindowTab("Overview", overviewNode), 
					new GInfoWindowTab("Rates", ratesNode)
				], {
					maxWidth: 300
				});
				
				
				/* 
				 * Set Listeners
				 */
				
				carpark.placemark.carpark_id = carpark_id;
				carpark.placemark.pfImage = this.pmIcon.image;
				carpark.placemark.pfHighlight = this.pmIcon.highlight;
				
				GEvent.addListener(carpark.placemark, "mouseout", function(){
					this.setImage(this.pfImage);
				});
				GEvent.addListener(carpark.placemark, "mouseover", function(){
					this.setImage(this.pfHighlight);
				});
				GEvent.bind(this.map, "click", this, this.mapClickResult);
				GEvent.bind(carpark.placemark, "infowindowclose", this, this.closeResult);
				
				
				/*
				 * Set Events
				 * 
				 */
			
				overviewNode.getElements('.show-street').each(function(elem) {
					elem.addEvent('click', this.clickStreetView.bindWithEvent(this, carpark_id));
				}, this);
				ratesNode.getElements('.show-street').each(function(elem) {
					elem.addEvent('click', this.clickStreetView.bindWithEvent(this, carpark_id));
				}, this);
				
				/*
				 * Push
				 */
				
				this.carparks[carpark_id] = carpark;
				placemarks.push(carpark.placemark);
				
				
				
				
			}
			this.mgr.addMarkers(placemarks, 13);
			this.mgr.refresh();
			this.cpLoaded = true;
		
		}
	},
	
	
	initStreetView: function() {		
		this.elmapstreetclose.addEvent('click', this.closeStreetView.bindWithEvent(this));
	},
	
	clickStreetView: function(event, carpark_id) {
		event.stop();
		
		var carpark = this.carparks[carpark_id];
		
		var panoramaOptions = {
			features: {
				userPhotos: false
			}
		};
		
		var svlatlng = null;
		var svpov = null;
		panoramaOptions.latlng = new GLatLng(carpark.streetview_lat, carpark.streetview_long);
		panoramaOptions.pov = {
			yaw: parseFloat(carpark.streetview_yaw),
			pitch: parseFloat(carpark.streetview_pitch),
			zoom:parseFloat( carpark.streetview_zoom)
		};
		
		
		this.elmapstreet.setStyle('display', 'block');
		this.elres.setStyle('display', 'none');
		
		if (this.elmapcont.hasClass("map-wide")) {
			this.elmapcont.store('is_wide', true);
		} else {
			this.elmapcont.addClass("map-wide");
		}
				
		this.streetViewPano = new GStreetviewPanorama(this.elmapstreet, panoramaOptions);
			
		GEvent.bind(this.streetViewPano, 'initialized', this, this.handleStreetViewInit);
		GEvent.bind(this.streetViewPano, "error", this, this.handleStreetViewError);
		
	},
	
	closeStreetView: function(event) {
		event.stop();
		this.streetViewPano.remove();
		this.hideStreetView();
	},
	
	hideStreetView: function() {		
		this.elmapstreet.setStyle('display', 'none');
		this.elmapstreetclose.setStyle('display', 'none');
		
		if (this.elmapcont.retrieve('is_wide') == true) {
			this.elmapcont.eliminate('is_wide');
		} else {
			this.elmapcont.removeClass("map-wide");
			this.elres.setStyle('display', 'block');
		}
		
		
		
	},
	
	handleStreetViewInit: function(){
		this.elmapstreetclose.setStyle('display', 'block');
	},
	
	handleStreetViewError: function(errorCode){
		this.hideStreetView();
		if (errorCode == 603) {
			alert("Error: Flash doesn't appear to be supported by your browser");
		}		
		return;
	}
});