/**

Google Map JS Class V.1 
Author: Giordano Vicari

Use: create a new Gmap object
	 pass an object to that function 

example:

var obj = {
	markers:[
		{
			lat: 41.903964,
			lng: 12.477293
		},
		{
			lat: 41.91695,
			lng: 12.49856
		}
	],
	lat: 41.91695,
	lng: 41.91695,
	ico: '/path/ico.png'
},
gmap = new Gmap(obj);

you can omit same keys (lat && lng OR markers are required)

the gmap object now contain all accesible functions

**/


function Gmap (config, canvas, options) {
	
	var debug = false;
	this.howto = (debug) ? new Man() : function(fn){ return alert('error in fn: ' + fn) };
	
	if(arguments.length === 0){
		return this.howto.man('Gmap');
	}
	
	this.conf = {
		ico: '/img/marker.png',
		canvas: (arguments[1] !== undefined && arguments[1] !== null) ? canvas : 'mapcanvas'
	};
	
	if(document.getElementById(this.conf.canvas) === null || document.getElementById(this.conf.canvas) === undefined){
		return alert('element with id "' + this.conf.canvas + '" doesn\'t exits in document!\ncreate it first please.');
	}
	
	this.map = null;
	this.markers = [];
	
	this.options = {
		
		/*
panControl: false,
		panControlOptions: {
			position: google.maps.ControlPosition.RIGHT_CENTER
		},
		overviewMapControl: false,
*/
		
		zoom:15,
		navigationControl: true,
		mapTypeControl: false,
		scrollwheel: false,
		streetViewControl: true,
		backgroundColor: '#ffffff',
		mapTypeControlOptions: {
			style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
			position: google.maps.ControlPosition.TOP_RIGHT
		},
		navigationControlOptions: {
			style: google.maps.NavigationControlStyle.DEFAULTS,
			position: google.maps.ControlPosition.RIGHT_CENTER
		},
		mapTypeId: google.maps.MapTypeId.ROADMAP
	}

	
	/**
	
	init:
	initialize the Gmap object.
	is the real constructor. delegate same other function the create the required
	object, parse the marker's array if exist and create the map.
	
	**/
	
	this.init = function(obj, canvas){
		var config = this.parse_config(obj),
			Map = this.create_map(config, this.options, canvas),
			markers = [];
		
		this.map = Map;
		this.conf = config;
	
		if(config.hasOwnProperty('markers')){
			for(var m = 0; m < config.markers.length; m++){
				markers.push( this.add_marker(config.markers[m]) ); //{lat, lng}
			}	
		}
		
		this.markers = markers;
		
		var result = [Map.map, markers];
		return result;
	}
	
	
	/**
	
	parse_config:
	read the obj from the constructor and create the initial latlng and optionaly markers
	
	**/
	
	this.parse_config = function(obj){
		var config = {}, marks = [], icon;
		if(obj.hasOwnProperty('markers')){
			for(var m = 0; m < obj.markers.length; m++){
				if(obj.markers.hasOwnProperty(m)){
					marks.push(obj.markers[m]);
				}
			}
			config.markers = marks;
		}
		
		if(obj.hasOwnProperty('lat') && obj.hasOwnProperty('lng')){
			config.latlng = {lat:obj.lat, lng: obj.lng};
			if(!marks.length){
				//config.markers = [config.latlng];
			}
		}else if(marks.length){
			config.latlng = {lat: marks[0].lat, lng: marks[0].lng};
		}else{
			return false;
		}
		
		config.ico = obj.hasOwnProperty('ico') ? obj.ico : null;
		
		return config;
	}
	
	/**
	
	extend:
	extend the google map options or update it
	example: "scrollwheel:true"
	
	**/
	
	this.extend = function(opt){
		for(var o in opt){
			this.options[o] = opt[o];
		}
	}
	
	
	/**
	
	make_marker:
	create the marker and append to the map
	
	**/
	
	var make_marker = function(conf, ico){
		
		var i = {
			map: conf.m,
			position: conf.mark,
			animation: google.maps.Animation.NULL,
			optimized: true,
			draggable: false
		}
		
		if(ico !== null) i.icon = ico

		var spriteMarker = new google.maps.Marker(i);
		return spriteMarker;
	}
	
	
	/**
	
	add_marker:
	create the latlng object check if an icon image is passed and create the image marker object
	then invoke the make_marker private method
	
	**/
	
	this.add_marker = function(marker, icon){
	
		if(arguments.length === 0){
			return this.howto.man('addMarker');
		}
		
		var MarkerIcon = null,
			MarkerLatlng = null,
			marks = {m: this.map};
		
		if(marker.hasOwnProperty('lat')){
			MarkerLatlng = new google.maps.LatLng(marker.lat, marker.lng);
		}else if(marker.hasOwnProperty('Ha')){
			MarkerLatlng = marker;
		}
		
		marks.mark= MarkerLatlng;
		
		if(arguments.length === 2){
			this.conf.ico = icon;
		}
		
		if(this.conf.ico !== null){
			
			var ico = this.conf.ico,
				key = ['size', 'origin', 'anchor'],
				path = ( ico.hasOwnProperty('path') ) ? ico.path : ico;
			
			if(typeof path !== 'string'){
				return 'Invalid icon path!';
			}
			
			MarkerIcon = new google.maps.MarkerImage(path);
			
			if(typeof ico !== 'string'){
			
				for(var i = 0; i < key.length; i++){
					if(!ico.hasOwnProperty(key[i])){
						return 'Invalid icon properties!';
					}else if (ico[key[i]].length !== 2){
						return 'Invalid icon properties!';
					}
				}
				
				MarkerIcon.size = new google.maps.Size(ico.size[0], ico.size[1]); 			/* dimensioni dell'img */
				MarkerIcon.origin = new google.maps.Point(ico.origin[0], ico.origin[1]); 	/* l'origine dell'img 0,0 */
				MarkerIcon.anchor = new google.maps.Point(ico.anchor[0], ico.anchor[1]); 	/* l'ancora per l'img 49,65 */
			}
		}
		return make_marker(marks, MarkerIcon);
	}
	
	
	/**
	
	create_map:
	create the map object and append it to the canvas id from the document
	
	**/
	
	this.create_map = function(config, Options, canvas){
		
		var Map = null,
			rendererOptions = { draggable: true },
			Latlng = new google.maps.LatLng(config.latlng.lat, config.latlng.lng);
		Options.center = Latlng;
		Map = new google.maps.Map(document.getElementById(canvas), Options);
		return Map;
	}
	
	
/**

Action functions 

**/
	
	
	/**
	
	geocode:
	geocode an address in the map, create an info window and add a marker
	usage:
		geocoding from a string:
		example:
		gmap.geocode('via trionfale roma', 'address');
		
		geocoding from a latlng:
		example:
		
		var latlng = new google.maps.LatLng(51.5, 12.1);
		gmap.geocode(latlng, 'latLng');
	
	**/
	
	this.geocode = function (address, type) {
		
		if(arguments.length === 0){
			return this.howto.man('geocode');
		}
		
		var geocoder = new google.maps.Geocoder(),
			query = {},
			gmap = this,
			result,
			infowindow = new google.maps.InfoWindow();
			query[type] = address;
			
			
		var callback = function (results, status){
			if (status == google.maps.GeocoderStatus.OK) {
				
				result = results[0].geometry.location;

				var mark = gmap.add_marker(result);
				gmap.map.panTo(result);
				infowindow.setContent(results[0].formatted_address + '<br />' + address);
				infowindow.open(gmap.map, mark);
				
				return result;
				
			} else {
				result = "Geocode was not successful for the following reason: " + status;
				alert(result);
				
				return result;
			}
		}
		
		geocoder.geocode( query, callback );
		
	}
	
	
	/**
	
	zoom:
	zoom the map the a specified zoom level
	
	**/
	
	this.zoom = function (level){
		if(arguments.length === 0){
			return this.howto.man('zoom');
		}
		
		if(typeof level !== 'number'){
			return 'NaN';
		}
		this.map.setZoom( parseInt(level, 10) );
		return 'zoom level is ' + parseInt(level, 10);
	}
	
	
	/**
	
	map_type:
	change the map type of the current map
	accepted type are:
	HYBRID		This map type displays a transparent layer of major streets on satellite images.
	ROADMAP		This map type displays a normal street map.
	SATELLITE	This map type displays satellite images.
	TERRAIN		This map type displays maps with physical features such as terrain and vegetation.
	
	**/
	
	this.map_type = function (mapType){
		if(arguments.length === 0){
			return this.howto.man('mapType');
		}
		
		if(google.maps.MapTypeId.hasOwnProperty(mapType)){
			this.map.setMapTypeId(google.maps.MapTypeId[mapType]);
			return 'current mapTypeID is ' + google.maps.MapTypeId[mapType];
		}
		
		return false;
	}
	
	
	/**
	
	Constructor to initalize the map
	
	**/
	
	if(arguments[2] !== undefined && arguments[2] !== null){
		this.extend(options);
		//console.info('extending options');
	}
	
	this.init(config, this.conf['canvas']);
}

