var Point = new Class ({
	initialize: function (lat,lng) {
		this.lat = parseFloat(lat);
		this.lng = parseFloat(lng);
	},
	toGoogleLatLng: function() {
		return new google.maps.LatLng(this.lat, this.lng);
	}
		
});

var Polygon = new Class({
	points: [],
	layer: null,
	fillColor: 'ff0000',
	strokeColor: '000000',
	parse: function(str) {
		var points = str.split(" ");
		points.forEach(function(str) { 
			var point = str.split(",");
			if ( point[0] && point[1] ) {
				this.points.push(new Point(point[1], point[0]));
			}
		}, this);
	},
	draw: function(map) {
		if ( this.layer ) {
			this.layer.setMap(null);
			this.layer.unbindAll();
		}
		var opts = {
			strokeColor: '#'+this.strokeColor,
			fillColor: '#'+this.fillColor,
			strokeOpacity: 0.8,
			strokeWeight: 2,
			paths: []
		}
		if ( !this.strokeColor ) {
			opts.strokeColor = '';
		}
		this.points.forEach(function(point) {
			opts.paths.push(point.toGoogleLatLng());
		});
		this.layer = new google.maps.Polygon(opts);
		this.layer.setMap(map);
	},
	moveTo: function(oldPoint, newPoint) {
		var newPoints = [];
		this.points.forEach(function(point) { 
			var lngDelta = Utils.lngDelta(oldPoint.lat, newPoint.lat);
			var movedPoint = new Point(
					point.lat + ( newPoint.lat - oldPoint.lat ),
					point.lng + ( newPoint.lng - oldPoint.lng )
				//newPoint.lat + ( point.lat - oldPoint.lat),
				//newPoint.lng + ( point.lng - oldPoint.lng) * lngDelta 
			);
			//Account for projection
			var oldLng = movedPoint.lng;
			movedPoint.lng = ( movedPoint.lng - newPoint.lng ) * lngDelta + newPoint.lng;
			newPoints.push(movedPoint);
		}, this);
		this.points = newPoints;
	}
	
});

var PolyGroup = new Class({
	polys: [],
	parse: function(str) {
		var lines = str.split("%")
		lines.forEach(function(line) {
			var poly = new Polygon(line);
			poly.parse(line);
			this.polys.push(poly);
		}, this);
	},
	draw: function(map) {
		this.polys.forEach(function(poly) {
			poly.draw(map);
		});
	},
	moveTo: function(oldPoint, newPoint) {
		this.polys.forEach(function(poly) {
			poly.moveTo(oldPoint, newPoint);
		});
	},
	add: function(poly) {
		this.polys.push(poly);
	}
});

var MapBlob = new Class({
	Extends: PolyGroup,
	initialize: function() {
		this.bounds = new google.maps.LatLngBounds();
	},
	centerAndZoom: function(map) {
		map.fitBounds(this.bounds);
	},
	add: function(poly) {
		this.parent(poly);
		poly.points.forEach(function(l) {
			this.bounds.extend(l.toGoogleLatLng());
		}.bind(this));
	},
	moveTo: function(oldPoint, newPoint) {
		this.parent(oldPoint, newPoint);
		this.bounds = new google.maps.LatLngBounds();
		this.polys.forEach(function(poly) {
			poly.points.forEach(function(l) {
				this.bounds.extend(l.toGoogleLatLng());
			}.bind(this));
		}.bind(this));
	}
});


var Utils = {
	latLngDistance: function(lat1, lat2, lon1, lon2) {
		var R = 6371; // Radius of the earth in km
		var dLat = Utils.degToRad(lat2-lat1);  // Javascript functions in radians
		var dLon = Utils.degToRad(lon2-lon1); 
		var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
		        Math.cos(Utils.degToRad(lat1)) * Math.cos(Utils.degToRad(lat2)) * 
		        Math.sin(dLon/2) * Math.sin(dLon/2); 
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
		var d = R * c; // Distance in km
		return d;
	},
	degToRad: function(deg) {
		return deg * (Math.PI / 180);
	},
	lngDelta: function(lat1, lat2) {
		return Utils.latLngDistance(lat1, lat1, 1, 100) / Utils.latLngDistance(lat2, lat2, 1, 100);
	}
}

var GeoLoc = new Class({
	Implements: Events,
	loc: null,
	str: '',
	country: '',
	geocoder: new google.maps.Geocoder(),
	autoDetect: function() {
		if ( google.loader.ClientLocation ) {
			this.loc = new Point(google.loader.ClientLocation.latitude, google.loader.ClientLocation.longitude);
			this.str = google.loader.ClientLocation.address.city+", "+google.loader.ClientLocation.address.region+", "+google.loader.ClientLocation.address.country;
			this.country = google.loader.ClientLocation.address.country_code;
			this.fireEvent('ready');
		} else if(navigator.geolocation) {
			navigator.geolocation.getCurrentPosition(function(position) {
				this.loc = new Point(position.coords.latitude,position.coords.longitude);
				this.geocoder = new google.maps.Geocoder();
				this.geocoder.geocode({latLng: new google.maps.LatLng(this.loc.lat, this.loc.lng)}, this._handleGoogleGeoStr.bind(this));
			}.bind(this) )
		} else {
			this.fireEvent('ready');
		}
	},
	find: function(str) {
		if ( str ) {
			this.geocoder.geocode({address: str}, this._handleGeocoder.bind(this));
		}
	},
	_handleGeocoder: function(res, status) {
		if ( status != google.maps.GeocoderStatus.OK ) {
			alert("Unable to locate this location. Please try again.");
			return;
		}
		this.loc = new Point(res[0].geometry.location.lat(), res[0].geometry.location.lng());
		this._handleGoogleGeoStr(res);
		
	},
	_handleGoogleGeoStr: function(res) {
		for ( var i = 0; i < res.length; i++) { 
			if ( res[i].types.contains('street_address') ) {
				continue;
			}
			this.str = res[i].formatted_address;
			res[i].address_components.forEach(function(a) {
				if ( a.types.contains('country') ) {
					this.country = a.short_name;
				}
			}.bind(this));
			this.fireEvent('ready');
			break;
		}
	}
});
