/*
Title: GMapEasy
  
About: Author
Rodrigo César Lima Pádua <http://www.rodrigopadua.com.br>
Tecnoplace - Goiânia - Brazil
  
About: Version
0.2.1
  
About: License
This file is licensed under the MIT license.
  
About: Required Libraries
Prototype JavaScript Framework 1.6.0.2 <http://prototypejs.org/download>
Google Maps API 2 <http://code.google.com/apis/maps/>
GxMarker 1 <http://code.toeat.com/> use GxMarker v1 modified by Rodrigo Pádua. Available in www.rodrigopadua.com.br
*/

var GMapEasy = Class.create();
GMapEasy.prototype = {
		
	map: '', // Objeto Google Maps
	geocoder: '', // Objeto GeoCoder. Para codificação de endereços textuais em coord. geográficas
	arMarcador: [], // Vetor que conterá todos os marcadores criados para o mapa
	contMarcador: 0, // Contador para o vetor de marcadores
	arLatLon: new Array(), // [0] = Latitude;  [1] = Longitude

		
    initialize: function (elMapa, options)
    {    		
		this.options = {
    		zoom: 13, // Zoom inicial para o mapa
    
			arGeoCoder: '', // Vetor contendo endereços e propriedades dos marcadores
			arGeoCoderCentro: '', // Vetor contendo endereços e propriedades do ponto que deverá ser o ponto central do mapa
			arCoordCentral: new Array(-15.779999, -47.909999), // Vetor com coordenadas (latitude,longitude) que serão marcadas como centro do mapa
															   // Coordenadas default para Brasília, Brasil
			
			tipoMapa: G_NORMAL_MAP, // Tipo de mapa que será inicializado. GMap CONSTANT: G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP
			cNavegacaoCompleto: false, // false = GSmallMapControl(), true = GLargeMapControl(), 
			cTipoMapa: false, //false = Não mostra tipos de mapas. true = Mostra opção para visualizar tipos de mapas
						
			draggable: false, //Se o ponto poderá ser reposicionado manualmente dentro do mapa. Objeto GMap retorna coordenadas do novo ponto
			draggableFunc: '', // Função que será executada ao final do reposicionamento do ponto
			
			desabilitarMoverMapa: false, // Se o mapa pode ser movido manualmente dentro do seu container de visualização
			autoFuncao: '', // Função que será executada ao final da movimentação do mapa dentro de seu container de visualização
			
			iconeArqExtensao: 'png',
			iconePasta: '', // Ex.: /images/
			iconeTamanho: new Array(19, 25), // Tamanho da imagem do marcador [0] = largura, [1] = altura
			iconeSombraTamanho: new Array(53, 25) // Tamanho da imagem da sombra do marcador 
        };
        
        Object.extend(this.options, options || { });         
        this.carregar(elMapa);
    },	
	
	
	// Inicializa o mapa
	carregar: function (elMapa)
	{		
		if (GBrowserIsCompatible()) {
			
			var self = this;
			var strGeocoder = ''; 
			this.geocoder = new GClientGeocoder(); //ACESSO AOS ENDERECOS TEXTUAIS	
        	this.map = new GMap2($(elMapa));		
			
			// Centraliza o mapa inicial. O mapa inicial mostrado ainda não possui nenhum marcador inserido
			this.map.setCenter(new GLatLng(this.options.arCoordCentral[0], this.options.arCoordCentral[1]), this.options.zoom, this.options.tipoMapa); 

			// Executa uma função sempre que o mapa for movimentado manualmente dentro de seu container de visualização
			if (this.options.autoFuncao != "") {	
				GEvent.addListener(this.map, "moveend", function() {
					eval(self.options.autoFuncao);	
				});
							
				// Executa a função no carregamento inicial, antes movimentar o mapa
				eval(self.options.autoFuncao);	
			}
							
			// Seta controles para navegação e zoom
			if (this.options.cNavegacaoCompleto)
				this.map.addControl(new GLargeMapControl()); // Controles de zoom e movimentos completos
			else
				this.map.addControl(new GSmallMapControl()); // Controles de zoom e movimentos reduzidos
			
			// Mosta opção para escolha do tipo de visualização (MAPA, IMAGEM, OU HIBRIDO)
			if (this.options.cTipoMapa)
				this.map.addControl(new GMapTypeControl());
				
			// Se o mapa não pode ser movido manualmente dentro de seu container de visualização
			if (this.options.desabilitarMoverMapa)
				this.map.disableDragging();
			
			// Insere os marcadores no mapa
			this.atualizarMarcadores();
      }
    },
    
	
	// Insere os marcadores no mapa
	atualizarMarcadores: function () 
	{
		var contNumeracao = 0;
		
		// Limpa todos os marcadores contidos no mapa
		this.map.clearOverlays();
		
		// Se possui endereços ou coordenadas para marcar 
		if (this.options.arGeoCoder) {		
			for (var i=0; i<this.options.arGeoCoder.length; i++) {
				this.marcarEndereco(this.options.arGeoCoder[i], contNumeracao+1, 0);
				contNumeracao++;
			}
		}
	
		// Se possui endereços ou coordenadas para marcar como centro do mapa
		if (this.options.arGeoCoderCentro) {		
			for (var i=0; i<this.options.arGeoCoderCentro.length; i++) {
				this.marcarEndereco(this.options.arGeoCoderCentro[i], contNumeracao+1, 0);
				contNumeracao++;
			}
		}
	},
	
    
	// Mostra os marcadores no mapa
	// count -> Utilizado para remover opções do endereçamento. Facilita a localização do endereço pelo GeoCoder
	// count = 1; remove bairro
	// count = 2; remove cep
	// count = 3; encerra tentativas
	marcarEndereco: function (arGeo, numeracao, count) //coordenadas PARA O CASO DE JA POSSUI O DADO GEOGRAFICO 
	{
		var strGeocoder;
		
		// Define o ícone a ser mostrado. Caso não seja um ícone específico, mostra o ícone default
		var iconeDefault = 'marcador';
		if (arGeo["icone"])
			iconeDefault = arGeo["icone"];
		
		// Se já possui coord. geográficas definidas, não utliza GeoCoder
		if (arGeo["geo_lat"] && arGeo["geo_lon"]) {
			var marcador = this.criarMarcador(new GLatLng(arGeo["geo_lat"], arGeo["geo_lon"]), unescape(arGeo["str_html"]), unescape(arGeo["link"]), numeracao, iconeDefault);
			this.map.addOverlay(marcador);
			this.map.setCenter(marcador.getPoint(), this.map.getZoom());
			
		}
		// Se possui o endereço textual a ser localizado pelo geocoder
		else if (arGeo["logradouro"]) 
		{		
			// Logradouro e localidade (município) são obrigatórios
			// Modifica a string de endereço a cada tentativa em encontrar as coord. pelo GeoCoder
			strGeocoder = unescape(arGeo["logradouro"]);
			
			if (arGeo["numero"]) 	
				strGeocoder += ', ' + unescape(arGeo["numero"]);
				
			if (count==0 && arGeo["bairro"]) 
				strGeocoder += ', ' + unescape(arGeo["bairro"]);
		
			strGeocoder += unescape(arGeo["localidade"]);	
			
			if (count==1 && arGeo["cep"]) 
				strGeocoder += ', ' + unescape(arGeo["cep"]);
			
			// Última tentativa. Insere apenas a localiza. Coordenadas sem precisão. Localiza o ponto central do município
			if (count==2 && arGeo["localidade"]) 
				strGeocoder = unescape(arGeo["localidade"]);
				
			// Após definir a string de endereço, localiza no GeoCoder as coordenadas geográficas
			this.geocoder.getLatLng(strGeocoder,
				function (point) {
					if (point) {
						
						var marcador = this.criarMarcador(point, unescape(arGeo["str_html"]), unescape(arGeo["link"]), numeracao, iconeDefault);
						this.map.addOverlay(marcador);
						this.map.setCenter(point, this.options.zoom);
						
						// Se o ponto for "draggable", seta o atributo arLatLon com as coordenadas do ponto
						if (this.draggable)
							this.setCoordenadas(point);
					}
					// Se não encontrou o ponto, nova tentativa alterando a string de endereço
					else {
						if (count<3) {
							count++;
							this.marcarEndereco(arGeo, numeracao, count);
						}
					}
				}.bind(this)
			); 
		}
    },
   
   
   // Cria o ponto e seta as propriedades dos eventos ocorridos no marcador
	criarMarcador: function (ponto, html, link, numeracao, icone) 
	{				
		if (!this.options.draggable) {
			
			var icon = this.criarIcone(icone);
			var marcador = new GxMarker(ponto, icon, html);
	
			// Adiciona o marcador no vetor de marcadores (-1 para iniciar como 0)
			this.arMarcador[numeracao-1] = marcador;
	
			// Alteração do ícone quanto ocorrer o evento mouseOver
			GEvent.addListener(marcador, "mouseover", function() {
				marcador.setImage(this.options.iconePasta + icone + '_over.' + this.options.iconeArqExtensao);
			}.bind(this)); 
			
			// Volta imagem do ícone para a imagem inicial no evento mouseOut
			GEvent.addListener(marcador, "mouseout", function() {
				marcador.setImage(this.options.iconePasta + icone + '.' + this.options.iconeArqExtensao);
			}.bind(this));
			
			// Se possui um link para o ponto, adiciona ao evento onClick
			if (link) {
				GEvent.addListener(marcador, "click", function() {
					window.open(link, '_parent');
				});
			}
		}		
		//Se o ponto for draggable (posicionamento manual do ponto)
		else {
			var marcador = new GMarker(ponto, {draggable: true});

			// Fecha todas as informações (tooltips) na janela do mapa ao se iniciar a movimentação
			GEvent.addListener(marcador, "dragstart", function() {
				this.map.closeInfoWindow();
			}.bind(this));
			
			// Executado ao final da movimentação do ponto no mapa
			GEvent.addListener(marcador, "dragend", function() {
			  	// Seta a variável arLatLon com as coordenadas do ponto
				this.setCoordenadas(marcador.getLatLng());
			  
			  	// Se possui função a ser executada
			  	if(this.options.draggableFunc) {
				  	eval(this.options.draggableFunc);
				}
			}.bind(this)); 
		}
		
		return marcador;
	},
	

   // Seta as propriedades do ícone que será criado e mostrado no marcador
   criarIcone: function (icone)
   {   
	    var icon = new GIcon(G_DEFAULT_ICON, this.options.iconePasta + icone + '.' + this.options.iconeArqExtensao); 

		icon.iconSize = new GSize(this.options.iconeTamanho[0], this.options.iconeTamanho[1]);
		icon.shadowSize = new GSize(this.options.iconeSombraTamanho[0], this.options.iconeSombraTamanho[1]);	
		icon.shadow = this.options.iconePasta . icone + '_shadow.' + this.options.iconeArqExtensao;
	
        return icon;
   },
   
   
   // Mostra o tooltip do marcador a partir de um mouseover externo (ex.: mouseover de um link)
   mostrarMarcador: function (numeracao)
   {
   		if (this.arMarcador[numeracao]) {
			// RETIRE O COMENTÁRIO DA LINHA ABAIXO SE A VISUALIZACAO CONTER PONTOS FORA DA ÁREA DO CONTAINER DO MAPA
   			//this.map.setCenter(this.arMarcador[numeracao].getPoint(), this.map.getZoom());
   			GEvent.trigger(this.arMarcador[numeracao], 'mouseover');
   		}
   },
   
   
   // Remove o tooltip do marcador a partir de um mouseover externo
   ocultarMarcador: function (numeracao)
   {
   		if (this.arMarcador[numeracao])
   			GEvent.trigger(this.arMarcador[numeracao], 'mouseout');
   },
   
 
   // O GMAPS retorna (-202.2029202029..., -34.093203902...)
   // Função separa a latitude da longitude e seta o atributo arLatLon com as coordenadas
   setCoordenadas: function (coord) 
   {
	   coord = coord + " ";
	   coord = coord . substr(1, coord.length-3);
	   
	   this.arLatLon = coord.split(",");
   },
   
   
   // Escreve coordenadas em objetos. Utlizado para o marcador manual de ponto (draggable)
   escreverCoordenadas: function(elLat, elLon) 
   {
		if(this.arLatLon!=""){
			$(elLat).value = this.arLatLon[0];
			$(elLon).value = this.arLatLon[1];
		}
		else{
			setTimeout(function(){ this.escreverCoordenadas(elLat, elLon) }.bind(this), 300);	
		}
   }
}