ICL.ui.Map = function() {
	
	return {
		
		options: {
			container: 'map_canvas',
			width: 500,
			height: 500,
			icons: {},
			mapControl: 'small',
			enableOverviewMapControl: false,
			addEventClick: true,
			selectMarkerDraggable: true,
			dragend: null,
			markerDragend: null,
			form: {
				enable: true,
				useInfoWindow: false,
				field: {
					fullAddress: {id: 'full_address', type: 'text'},
					country: {id: 'country', type: 'text'},
					city: {id: 'city', type: 'text'},
					zipCode: {id: 'zip_code', type: 'text'},
					address: {id: 'address', type: 'text'},
					latitude: {id: 'latitude', type: 'text'},
					longitude: {id: 'longitude', type: 'text'}
				}
			},
			objReport: null,
			zoomAccuracy: [3, 4, 5, 6, 10, 14, 17, 18, 19, 20]
		},
		
		mapContainer: {},
		map: null,
		geocoder: null,
		formContainer: {},
		baseIcon: {},
		
		newMarker: null,
		markerList: [],
		country: {iso3: '', name: ''},
		address: '',
		
		moveendEvent: true,
		redrawMap: true,
		
		init: function(option) {
			if (typeof(this.options.container) != 'object') {
				jQuery.extend(this.options, option);
			} else {
				alert('we need object as init options, so we just use the default options.');
			}
			
			if (typeof(this.options.container) == 'string') {
				this.mapContainer = jQuery('#' + this.options.container);
			} else {
				this.mapContainer = jQuery(this.options.container);
			}
			
			if (this.mapContainer[0] == null) {
				alert('please define the id of map html container in the init function');
				return false;
			}
			
			this.mapContainer.css({width: this.options.width + 'px', height: this.options.height + 'px'});
			
			this.baseIcon = new GIcon();
			this.baseIcon.iconAnchor = new GPoint(12,32);
			this.baseIcon.infoWindowAnchor = new GPoint(16,0);
			
			this.drawMap();
		},
		
		drawMap: function() {
			if (GBrowserIsCompatible()) {
				if (this.geocoder == null) {
					this.geocoder = new GClientGeocoder();
				}
				
				//if (this.map == null) {
					this.map = new GMap2(this.mapContainer[0]);
				//}
				
				this.map.setCenter(this.getPoint(this.options.defaultLocationLatLng[0], this.options.defaultLocationLatLng[1]), this.options.defaultZoomSize);
				
				this.map.disableDoubleClickZoom();
				
				if (this.options.mapControl != null) {
					switch(this.options.mapControl) {
						case 'small':
							this.map.addControl(new GSmallMapControl());
						break;
						case 'large':
							this.map.addControl( new GLargeMapControl());
						break;
					}
				} else {
					this.map.addControl(new GSmallMapControl());
				}
				
				this.map.addControl(new GMapTypeControl());
				
				if (this.options.enableOverviewMapControl) {
					this.map.addControl(new GOverviewMapControl());
				}
				
				if (this.options.addEventClick) {
					GEvent.addListener(this.map, "click", function(overlay, point){
						if (overlay == null) {
							ICL.ui.Map.createSelectMarker(point, ICL.ui.Map.setIcon(ICL.ui.Map.options.icons.pin_point));
						}
					});
				}
				
				if (this.options.moveend != null) {
					if (typeof(this.options.moveend) != 'string') {
						GEvent.addListener(this.map, "moveend", this.options.moveend);
					}
				}
				
				if (this.options.zoomend != null) {
					if (typeof(this.options.zoomend) != 'string') {
						GEvent.addListener(this.map, "zoomend", this.options.zoomend);
					}
				}
				
				if (this.options.dragend != null) {
					if (typeof(this.options.dragend) != 'string') {
						GEvent.addListener(this.map, "dragend", this.options.dragend);
					}
				}
			}
		},
		
		redrawMapWithAddress: function(address, zoomSize, addSelectMarker, callback, country) {
			if (country != null) {
				if (country != '') {
					this.geocoder.setBaseCountryCode(country);	
				}
			}
			
			this.geocoder.getLocations(address, function (result){
				if (result.Status.code == G_GEO_SUCCESS){
					var coordinates = result.Placemark[0].Point.coordinates;
					var gLatLng = new GLatLng(coordinates[1], coordinates[0]);
					
					if (zoomSize == 0) {
						zoomSize = ICL.ui.Map.options.zoomAccuracy[result.Placemark[0].AddressDetails.Accuracy];
					}
					
					ICL.ui.Map.map.setCenter(gLatLng, zoomSize);
					
					if (addSelectMarker) {
						ICL.ui.Map.createSelectMarker(gLatLng, ICL.ui.Map.setIcon(ICL.ui.Map.options.icons.pin_point));
					}
					
					if (callback != null) {
						callback();
					}
					
					delete coordinates;
					delete gLatLng;
					
					if (ICL.ui.Map.options.objReport != null) {
						ICL.ui.Map.options.objReport.html('');
					}
				} else {
					if (ICL.ui.Map.options.objReport != null) {
						ICL.ui.Map.options.objReport.html('We are sorry,\nthere was a problem while getting the address location from Google Maps, or the Country is different from your address.\nPlease try again or check your internet connection.');
					} else {
						alert('We are sorry,\nthere was a problem while getting the address location from Google Maps, or the Country is different from your address.\nPlease try again or check your internet connection.');
					}
				}
				
				ICL.ui.Map.moveendEvent = true;
			});
		},
		
		redrawMapWithLatLng: function(point, zoom) {
			ICL.ui.Map.map.setCenter(point, zoom);
		},
		
		setCoordinates: function(options) {
			if (options != null) {
				if (options.latitude != '' && options.longitude != '') {
					var zoom = this.options.defaultZoomSize;
					if (options.zoomSize != null && options.zoomSize != 0) {
						zoom = options.zoomSize;
					}
					this.redrawMapWithLatLng(this.getPoint(options.latitude, options.longitude), zoom);
					
					if (options.addSelectMarker != null && options.addSelectMarker === true) {
						ICL.ui.Map.createSelectMarker(this.getPoint(options.latitude, options.longitude), ICL.ui.Map.setIcon(ICL.ui.Map.options.icons.pin_point));
					}
						
					delete zoom;
				}
			}
		},
		
		setAddress: function(options) {
			this.moveendEvent = false;
			
			if (options.country == null) {
				options.country = this.country.name;
			} else {
				this.country.name = options.country;
			}
			
			this.address = (options.address == null || options.address == '' ? "": ", " + options.address)+
				(options.city == null || options.city == '' ? "": ", " + options.city)+
				(options.state == null || options.state == ''  ? "": ", " + options.state)+
				(options.country == null ? "" : ", " + options.country)+
				(options.zip == null || options.zip == ''  ? "" : ", " + options.zip);
			
			var zoomSize = 0;
			if (options.zoomSize != null) {
				zoomSize = options.zoomSize;
			}
			
			var addSelectMarker = false;
			if (options.addSelectMarker != null) {
				addSelectMarker = options.addSelectMarker;
			}
			
			this.redrawMapWithAddress(this.address, zoomSize, addSelectMarker, options.callback, options.countryiso3);
			
			delete zoomSize;
			delete addSelectMarker;
		},
		
		clearMap: function(options) {
			if (this.map.isLoaded()) {
				this.map.clearOverlays();
				if (options != null) {
					if (options.markerInfoClassIdentifier != null) {
						jQuery('.' + options.markerInfoClassIdentifier).remove();
					}
				}
			}
		},
		
		getLatLangRectangular: function() {
			var data = {southWest: {lat: 0, lng: 0}, northEast : {lat: 0, lng: 0}};
			
			var bounds = this.map.getBounds();
			
			if (!bounds.isEmpty()) {
				var southWest = bounds.getSouthWest();
				var northEast = bounds.getNorthEast();
				
				data = {southWest: {lat: southWest.lat(), lng: southWest.lng()}, northEast: {lat: northEast.lat(), lng: northEast.lng()}};
				
				delete southWest;
				delete northEast;
			}
			
			delete bounds;
			
			return data;
		},
		
		getPoint: function(latitude, longitude) {
			return new GLatLng(latitude, longitude, true);
		},
		
		createSelectMarker: function(point, icon) {
			if(this.newMarker != null) {
				this.map.removeOverlay(this.newMarker);
			}
			
			if (this.options.selectMarkerDraggable) {
				this.createMarker(point, {
					draggable: true,
					icon: icon
				});
				
				GEvent.addListener(this.newMarker, "dragend", function(GLatLng) {
					ICL.ui.Map.fillForm(ICL.ui.Map.newMarker, GLatLng);
					if (ICL.ui.Map.options.markerDragend != null) {
						if (typeof(ICL.ui.Map.options.markerDragend) != 'string') {
							ICL.ui.Map.options.markerDragend(GLatLng);
						}
					}
				});
			} else {
				this.createMarker(point, {icon: icon});
			}
			
			ICL.ui.Map.fillForm(ICL.ui.Map.newMarker, ICL.ui.Map.newMarker.getLatLng());
		},
		
		createShowMarker: function(latitude, longitude, options, markerInfo, dialogInfo) {
			var marker = this.createMarker(this.getPoint(latitude, longitude), options);
			
			if (markerInfo != null) {
				if (markerInfo.enable) {
					this.addMarkerInfo(marker, markerInfo.options);
				}
			}
			
			if (dialogInfo != null) {
				if (dialogInfo.enable) {
					this.addDialogInfo(marker, dialogInfo.options);
				}
			}
			
			this.newMarker = {}
		},
		
		createMarker: function(point, options) {
			this.newMarker = new GMarker(point, options);
			this.map.addOverlay(this.newMarker);
			return this.newMarker;
		},
		
		fillForm: function(marker, GLatLng) {
			if (this.options.form.enable) {
				ICL.loadingFull();
				this.geocoder.getLocations(GLatLng, function(data){
					var item;
					var fullAddress = '';
					var country = 'Country is not identified';
					var regions = '';
					var region = 'Region is not identified';
					var zipCode = 'Zip Code is not identified';
					var city = 'City is not identified';
					var address = 'Address is not identified';
					var countryDone = false;
					var regionDone = false;
					var zipCodeDone = false;
					var cityDone = false;
					var addressDone = false;
					
					if (data.Status.code == G_GEO_SUCCESS) {
						fullAddress = data.Placemark[0].address;
						
						if (ICL.ui.Map.options.objReport != null) {
							ICL.ui.Map.options.objReport.html('');
						}
					} else {
						if (ICL.ui.Map.options.objReport != null) {
							ICL.ui.Map.options.objReport.html('We are sorry,\nthere was a problem while getting the address location from Google Maps, or the Country is different from your address.\nPlease try again or check your internet connection.');
						} else {
							alert('We are sorry,\nthere was a problem while getting the address location from Google Maps, or the Country is different from your address.\nPlease try again or check your internet connection.');
						}
					}
					
					if (ICL.ui.Map.options.form.field != null) {
						if (ICL.ui.Map.options.form.field.fullAddress != null) {
							for(item in ICL.ui.Map.options.form.field.fullAddress) {
								jQuery('#' + ICL.ui.Map.options.form.field.fullAddress[item].id).val(fullAddress);
							}
						}
					}
					
					if (fullAddress != '') {
						fullAddress = fullAddress.split(', ');
						if (fullAddress.length > 0) {
							country
							var i = 0;
							for(i = (fullAddress.length - 1); i > -1; --i) {
								if (cityDone && !addressDone) {
									address = fullAddress[i];
									addressDone = true;
								}
								if (zipCodeDone && !cityDone) {
									city = fullAddress[i];
									cityDone = true;
								}
								if (regionDone && !zipCodeDone) {
									zipCode = fullAddress[i];
									zipCodeDone = true;
								}
								if (countryDone && !regionDone) {
									regions = fullAddress[i].split(' ');
									if (regions.length == 1) {
										city = regions[0];
										cityDone = true;
										zipCodeDone = true;
										regionDone = true;
									} else {
										zipCode = regions[1];
										zipCodeDone = true;

										region = regions[0];
										regionDone = true;
									}
								}
								if (!countryDone) {
									country = fullAddress[i];
									countryDone = true;
								}
							}
						}
					}
					
					if (ICL.ui.Map.options.form.field != null) {
						if (ICL.ui.Map.options.form.field.latitude != null) {
							for(item in ICL.ui.Map.options.form.field.latitude) {
								jQuery('#' + ICL.ui.Map.options.form.field.latitude[item].id).val(GLatLng.lat());
							}
						}
						if (ICL.ui.Map.options.form.field.longitude != null) {
							for(item in ICL.ui.Map.options.form.field.longitude) {
								jQuery('#' + ICL.ui.Map.options.form.field.longitude[item].id).val(GLatLng.lng());
							}
						}
						if (ICL.ui.Map.options.form.field.country != null) {
							for(item in ICL.ui.Map.options.form.field.country) {
								jQuery('#' + ICL.ui.Map.options.form.field.country[item].id).val(country);
							}
						}
						if (ICL.ui.Map.options.form.field.region != null) {
							for(item in ICL.ui.Map.options.form.field.region) {
								jQuery('#' + ICL.ui.Map.options.form.field.region[item].id).val(region);
							}
						}
						if (ICL.ui.Map.options.form.field.zipCode != null) {
							for(item in ICL.ui.Map.options.form.field.zipCode) {
								jQuery('#' + ICL.ui.Map.options.form.field.zipCode[item].id).val(zipCode);
							}
						}
						if (ICL.ui.Map.options.form.field.city != null) {
							for(item in ICL.ui.Map.options.form.field.city) {
								jQuery('#' + ICL.ui.Map.options.form.field.city[item].id).val(city);
							}
						}
						if (ICL.ui.Map.options.form.field.address != null) {
							for(item in ICL.ui.Map.options.form.field.address) {
								jQuery('#' + ICL.ui.Map.options.form.field.address[item].id).val(address);
							}
						}
					}
					
					ICL.loadingFullRemove();
					
					delete fullAddress;
					delete country;
					delete regions;
					delete region;
					delete zipCode;
					delete city;
					delete address;
					delete countryDone;
					delete regionDone;
					delete zipCodeDone;
					delete cityDone;
					delete addressDone;
				});
			}
		},
		
		setIcon: function(icon) {
			var tmpIcon = icon.substr((icon.length - 30), icon.length);
			var slashs = icon.split('/');
			var icons = tmpIcon.split('.');
			var iconFile = slashs[(slashs.length) - 1].replace(icons[1], '');
			iconFile = iconFile.substr(0, (iconFile.length - 1));
			ICL.ui.Map.baseIcon.shadow = icon.substr(0, (icon.replace(slashs[(slashs.length) - 1], '').length)) + iconFile + '_shadow.' + icons[1];
			delete iconFile;
			delete icons;
			delete slashs;
			delete tmpIcon;
			return new GIcon(ICL.ui.Map.baseIcon, icon);
		},
		
		addMarkerInfo: function(marker, options) {
			options.object.appendTo(this.map.getPane(G_MAP_FLOAT_SHADOW_PANE)).css('display', 'none');
			
			GEvent.addListener(marker, options.event, function() {
				jQuery('.' + options.identifierClass, options.object.parent()).css('display', 'none');
				var markerOffset = ICL.ui.Map.getMarkerXY(marker);
				options.object.fadeIn().css({top:markerOffset.y, left:markerOffset.x, display: 'block'});
				delete markerOffset;
			});
		},
		
		addDialogInfo: function(marker, options) {
			if (options.anotherClickedObject != null) {
				options.anotherClickedObject.click(function(){
					GEvent.trigger(marker, 'click');
				});
			}
			//options.object.appendTo(this.map.getPane(G_MAP_FLOAT_SHADOW_PANE)).css('display', 'none');
			
			GEvent.addListener(marker, options.event, function() {
				ICL.ui.Map.redrawMap = false;
				ICL.ui.Map.markerClick(marker, options);
			});
		},
		
		markerClick: function(marker, options) {
			//jQuery('.' + options.identifierClass, options.object.parent()).css('display', 'none');
			ICL.ui.Map.map.openInfoWindow(marker.getLatLng(), options.object.css('display', 'block')[0], {onCloseFn: function(){
				ICL.ui.Map.enableRedrawMap();
			}});
		},
		
		getMarkerXY: function(marker) {
			return ICL.ui.Map.map.fromLatLngToDivPixel(marker.getLatLng());
		},
		
		enableRedrawMap: function() {
			this.redrawMap = true;
		},
		
		allowRedrawMap: function() {
			return this.redrawMap;
		},
		
		allowMoveendEvent: function() {
			return this.moveendEvent;
		},
		
		drawCircle: function (centrePt, rangeValue) {
			if (this.options.imageRoundOverlay != '' && this.map != null) {
				if (this.circleOverlay != null) {
					this.map.removeOverlay(this.circleOverlay);
				}
				
				var boundaries = this.getBoundaries(centrePt, rangeValue);
				this.circleOverlay = new GGroundOverlay(IMG_PATH + 'circle.png', boundaries);
				this.map.addOverlay(this.circleOverlay);
				delete boundaries;
			}
		},
		
		getBoundaries: function (centrePt, radius) {
			var hypotenuse = Math.sqrt(2 * radius * radius);
			var sw = this.getDestLatLng(centrePt, 225, hypotenuse);
			var ne = this.getDestLatLng(centrePt, 45, hypotenuse);
			return new GLatLngBounds(sw, ne);
		},
		
		getDestLatLng: function (latLng, bearing, distance) {
			var lat1 = latLng.latRadians();
			var lng1 = latLng.lngRadians();
			var brng = bearing*Math.PI/180; 
			var dDivR = distance/6378.137;
			var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dDivR) + Math.cos(lat1)*Math.sin(dDivR)*Math.cos(brng) );
			var lng2 = lng1 + Math.atan2(Math.sin(brng)*Math.sin(dDivR)*Math.cos(lat1), Math.cos(dDivR)-Math.sin(lat1)*Math.sin(lat2));
			return new GLatLng(lat2/ Math.PI * 180, lng2/ Math.PI * 180);
		}
		
	}
	
}();