/*
=============================================================
						 COPY RIGHTS			
			-------------------------------------
			Przedsiebiorstwo Informatyczne WTSOFT
			-------------------------------------
=============================================================
*/

/**
 * ---------
 * WYMAGANIA
 * ---------
 * - jquery.js
 * 
 * ------------------------------------
 * OPCJE DLA ELEMENTOW HTML - NAVIGACJA
 * ------------------------------------
 * 
 * 
 * --------------------------------------
 * OPCJE DLA FUNKCJI $().googlemap({...})
 * --------------------------------------
 * - width - szerokosc mapy google - domyslnie 100%, podajemy z jednostkami (%, px, em)
 * - height - wysokosc mapy google - domyslnie 350px, podajmey z jednostkami (%, px, em)
 * - lat, lng - dlugosc i szerokosc geograficzna poczatkowego ustawienia mapy
 * - zoom - poczatkowy zoom mapy
 * - startPoint - zaznacz poczatkowy punkt (true/false), gdy ustawiony zosatnie zaznaczony punkt poczatkowy zgodnie z startLat,startLng i startZoom, domyslnie false
 * - startLat, startLng - dlugosc i szerokosc geograficzna punktu poczatkowego
 * - startZoom - przyblizenie dla punktu poczatkowego
 * ----------- KONTROLKI -------------------------
 * - navigationControl - kontrolka z navigacja [default / small / zoomPan / android]
 * - scaleCongrol - kontrolka ze skala - domyslnie true
 * - mapTypesControl - kontrolka z typami map - domyslnie true
 * - mapTypeRoadmap - typ mapy - roadmap - domyslne true
 * - mapTypeSatellite - typ mapy - satellite - domyslne true
 * - mapTypeHybrida - typ mapy - hybryda - domyslne true
 * - mapTypeTerrain - typ mapy - teren - domyslne true
 * - mapTypeStart - startowy typ mapy (normal, satelita, hybryda, teren) - domyslnie normal
 * - dbcZoom - po podwojnym kliku przybliza true / false - domyslnie true
 * - scrollZoom - po scrolowaniu przybliza true / false - domyslnie true
 * - clickCallback - funkcja do wywolania po kliknieciu - parametry function(gMap, overlay, point)
 * --------- WYZNACZANIE TRASY --------------------
 * - directions - mozliwosc wyznaczenia trasy dojazdu do miejsca - domyslnie false
 * - directionsFromText - tekst dla inputa w wyznaczaniu trasy
 * - directionsInfoElement - selektor jquery warstwy odpowiadajacej za informacje o trasie dojazdu
 * - directionsInfoClearElement - selektro jquery do elementu po kliekniecu ktorego wyczyszczone zostana podpowiedzi dojazdu
 * - directionsInfoShowAnimation - efekt pojawiania sie podpowiedzi - domyslnie "show"
 * - directionsInfoShowSpeed - szybkosc wykonywania efektu
 * - directionsFormTemplate - temlpate formularza
 * --------- WYZNACZANIE TRASY END ----------------
 * - defIcon - ustawienia domyslnej ikony markera {image : 'link', width : x, height : y, iconAnchorX : x, iconAnchorY : Y, infoWindowAnchorX : x, infoWindowAnchorY : y}
 * - defShadow - ustawienie domyslnego cienia ikony markaera {image : 'link', width : x, height : y, iconAnchorX : x, iconAnchorY : Y, infoWindowAnchorX : x, infoWindowAnchorY : y}
 * - zoomArea - ustaw jezeli zoom ma byc dostosowany do wszystkich markerow - domyslanie true
 * - markers - lista poczatkowych marekrow na mapie [cords : 'lat,lng', title : 'tytul', desc : 'opis', icon : {image : 'link_do_ikony', shadow : 'link_do_cienia', iconSize : 'x,y', shadowSize : 'x,y', iconAnchor : 'x,y', infoWindowAnchor : 'x,y'}]
 * - markersList - jqSelector gdzie ma byc wyswietlona lista markerow
 * - draggableMarkers - jezeli true mozna przeciagac markery - domyslnie false
 * ........ FUNKCJE ZDARZENIOWE MARKERA .........
 * - markerDragstartCallback - funkcja wykonywna przy starcie przesuwania markera
 * - markerDragCallback - funkcja wykonywna podczas przesuwania markera
 * - markerDragendCallback - funkcja wykonywna po przeciagnieciu markera
 * - markerAddCallback - funkcja wykonywana po dodaniu markera
 * ---------- GEOLOKALIZACJA --------------
 * - defCountry - domyslne panstwo dla geolokalizacji
 * - noLocationText - tekst w przypadku braku lokalizacji
 * ---------- NAVIGACJA -------------------
 * - navigation - tablica elementow navigacji i opcji dla nich
 * 		- opcje navigacji:
 * 			- action : po jakim zdarzeniu wykonac akcje (click, keyup, keydown, submit, dbclick),
 * 			- type : typ akcji do wykonania
 * 					- find - znajdz adres na mapie
 * 			- locationtype - okreslenie typ lokalizacji jaki bedzie przekazywany przez to pole, rozne pola moga przekazywac inne zmienne
 * 					- country	- panstwo [domyslnie Polska]
 * 					- state		- wojewodztwo
 * 					- city		- miasto
 * 					- address	- adres
 * 					---------
 * 					- full/all	- szukaj po podanej wartosci
 * 
 */
(function($){
	$.fn.googlemap = function(settings){
		var sets = jQuery.extend({
			// Szerokosc mapy
			width : '100%',
			// Wysokosc mapy
			height : '350px',
			// Szerokosc i dlugosc geograficzna obszaru domyslnego
			lat: 52.173931692568,
			lng: 18.8525390625,
			// Przyblizenie domyslnego obszaru
			zoom : 6,
			// Punkt poczatkowy - jezeli ustawiony to zostanie wskazay punktu wedlug podanych lat, lng i zoom
			startPoint : false,
			// Szerokosc i dlugosc geograficzna dla punktu poczatkowego
			startLat : null,
			startLng : null,
			// Zoom dla punktu poczatkowego
			startZoom : 17,
			// Kontrolki
			navigationControl : true,
			navigationControlStyle : 'default',
			scaleControl : true,
			mapTypeControl : true,
			streetViewControl : false,
			// Typy map
			mapTypeRoadmap : true,
			mapTypeSatellite : true,
			mapTypeHybrid : true,
			mapTypeTerrain : true,
			// Startowy typ mapy
			mapTypeId : 'roadmap',
			// Kontrola myszy
			dbcZoom : true,
			scrollZoom : true,
			// Funkcja do wykonania po kliku na mape
			clickCallback : null,
			// Trasa dojazdu
			directions : false,
			directionsFromText : 'Pokaż trasę do tego miejsca z:',
			directionsInfoElement : null,
			directionsInfoClearElement : null,
			directionsInfoShowAnimation : "show",
			directionsInfoShowSpeed : 300,
			directionsFormTemplate : '<div style="border-top: solid 1px #000000; padding: 5px 10px; font-size: 10px; background-color: #F8F8F8;"><span style="font-weight: bold;">{directionsFormText/}</span><br /><form id="{uniqDirectionsFormId/}" style="display: block; position: relative; width: 100%; padding: 3px 0; margin: 0;" onsubmit="return false;"><input type="hidden" name="to" class="to" value="{toValue/}" /><input type="text" class="from" value="" name="from" class="form-inp" style="display: block; position: relative; width: 100%; font-family: Verdana;" /></form></div>',
			// Obsluga bledow
			directionsError : {
				'invalidRequest': 'Błąd zapytania.',
				'notFound'		: 'Nie odneleziono punktu startowego lub docelowego.',
				'zeroResult'	: 'Nie można wyznaczyć trasy dla wybranych punktów.',
				'requestDenied'	: 'Serwis nie ma możliwości obsługi tego zdażenia.',
				'unknowError'	: 'Napotkanio nieznany błąd.'
			},
			// Domyslna ikona
			defIcon : null,	// {image : 'link', width : x, height : y, iconAnchorX : x, iconAnchorY : y, infoWindowAnchorX : x, infoWindowAnchorY : y}
			defShadow : null, // {image : 'link', width : x, height : y, iconAnchorX : x, iconAnchorY : y, infoWindowAnchorX : x, infoWindowAnchorY : y}
			// Ustaw zoom aby byly widoczne wszystkie markery
			bounds : true,
			// Poczatkowe markery
			markers : null,
			// JqSelector dla listy markerow
			markersList : null,
			// Mozliwosc przeciagania markerow
			draggableMarkers : false,
			// Mozliwaoc klikania w markery
			clickableMarkers : true,
			// Funkcje zdarzeniowe dla markerow
			markerDragstartCallback : null,
			markerDragCallback : null,
			markerDragendCallback : null,
			markerAddCallback : null,
			// Ustawianie markera po kliknieciu
			setMarkerOnClick : false,
			// GEOLOKALIZACJA
			defCountry : 'Polska',
			// Zewnetrzna nawigacja
			navigation : {}
		},settings);
		
		// Przepisanie pasujacych elementow
		var self = this;
		// Zmienna przechowujaca obiekt(y) mapy
		var gMap = null;
		// Geokodowanie
		var geocoder = null;
		// Dojazd
		var directionsService = null;
		var directionsDisplay = null;
		// Dostosuj zoom uwzgledniajac wszystkie markery widoczne
		var bounds = null;
		// Tablica markerow
		var markers = [];
		// Tablica okien
		var infoWindows = [];
		// Ustawienia nawigacji
		var nav = {};
		
		// LOKALIZACJA
		var _location = {};
		
		//---------------------------------
		// Ustaw widok - parametry warstwy
		//---------------------------------
		function setView(obj){
			if(!obj || obj.length == 0) return false;
			// Ustaw rozmiar warstwy na mape
			obj.css({
				width : sets.width,
				height : sets.height
			});
			return true;
		}
		
		// Pokaz
		function show(obj){
			if(!obj || typeof(obj) != 'object') return false;
			if(obj.is(':visible')) return true;
			switch(sets.accessInfoShowAnimation){
				case 'slide':
					obj.slideDown(sets.accessInfoShowSpeed);
					break;
				case 'show':
					obj.show(sets.accessInfoShowSpeed);
					break;
				case 'fade':
				default:
					obj.fadeIn(sets.accessInfoShowSpeed);
					break;
			}
		}
		// Schowaj
		function hide(obj){
			if(!obj || typeof(obj) != 'object') return false;
			if(obj.is(':hidden')) return true;
			switch(sets.accessInfoShowAnimation){
				case 'slide':
					obj.slideUp(sets.accessInfoShowSpeed);
					break;
				case 'fade':
					obj.fadeOut(sets.accessInfoShowSpeed);
					break;
				case 'hide':
				default:
					obj.hide(sets.accessInfoShowSpeed);
				break;
			}
		}
		
		//----------------------------------
		// -- Pobierz / ustaw id elementu --
		//----------------------------------
		function elementId(obj){
			if(typeof(obj) != 'object' || obj.length == 0) return false;
			// Ustaw unikalny id
			var uniqId = 'wts-googlemap-nav-'+(Math.floor(Math.random() * 100000));
			var objId = obj.attr('id');
			if(!objId){
				objId = uniqId;
				obj.attr('id',uniqId);
			}
			return objId;
		}
		
		//-----------------------------------
		// Funkcje generuje ikone dla markera
		//-----------------------------------
		function getMarkerIcon(opt){
			if(!opt || typeof(opt.image) != 'string' || !opt.width || !opt.height) return false;
			
			// Ustaw icon anchor
			if(!opt.iconAnchorX){
				opt.iconAnchorX = opt.width / 2;
			}
			if(!opt.iconAnchorY){
				opt.iconAnchorY = opt.height;
			}
			
			// Ustaw info window anchor
			if(!opt.infoWindowAnchorX){
				opt.infoWindowAnchorX = opt.width / 2;
			}
			if(!opt.infoWindowAnchorY){
				opt.infoWindowAnchorY = 0;
			}
			
			// Generuj ikone
			var icon = new google.maps.MarkerImage(
				opt.image,
				new google.maps.Size(opt.width,opt.height),
				new google.maps.Point(0,0),
				new google.maps.Point(opt.iconAnchorX,opt.iconAnchorY)
			);
			// Zwroc obiekt ikony
			return icon;
		}
		
		//----------------------
		// Funkcja dodaje marker
		//----------------------
		function addMarker(point, title, desc, iconSets, shadowSets){
			if(!point || !gMap) return false;
			
			// Opcje markera
			var markerOptions = {};
			// Mapa
			markerOptions.map = gMap;
			// Polozenia markera
			markerOptions.position = point;
			// Mozna przeciagac markery
			markerOptions.draggable = sets.draggableMarkers;
			// Mozna kliknac markery
			markerOptions.clickable = sets.clickableMarkers;
			// Tytul markera
			markerOptions.title = title;
			// Ikona markera
			if(!iconSets) iconSets = sets.defIcon;
			var iconMarker = getMarkerIcon(iconSets);
			if(iconMarker)
				markerOptions.icon = iconMarker;
			// Cien markera
			if(!shadowSets) shadowSets = sets.defShadow;
			var shadowIcon = getMarkerIcon(shadowSets);
			if(shadowIcon)
				markerOptions.shadow = shadowIcon;
			
			// Dodaj markera
			var marker = new google.maps.Marker(markerOptions)
			
			if(!desc) desc = title;
			
			// Zapisz zmienne do dymka
			marker.desc = desc
			
			// Zapisz marker
			markers[markers.length] = marker;
			
			//-----------------------
			// Dodaj dymek do markera
			//-----------------------
			var uniqDirectionsFormId = '_wts-form-google-directions_'+String(Math.floor(Math.random()*10000));
			var infoWindow = new google.maps.InfoWindow();
			// Zapisz okon
			infoWindows[infoWindows.length] = infoWindow;
			google.maps.event.addListener(marker,'click',function(){
				info = '<div style="position: relative;">';
				if(marker.desc){
					info += '<div style="padding: 0 0 10px;">';
					info += marker.desc;
					info += '</div>';
				}
				// Dodaj formularz wyznaczajacy trase dojazdu jezeli wlaczona opcja
				if(sets.directions && directionsDisplay && directionsService && sets.directionsFormTemplate){
					var rep = {
						'{directionsFormText/}' 	: sets.directionsFromText,
						'{uniqDirectionsFormId/}'	: uniqDirectionsFormId,
						'{toValue/}'				: marker.getPosition().lat()+','+marker.getPosition().lng()
					};
					var formTemp = sets.directionsFormTemplate;
					for(i in rep){
						formTemp = formTemp.replace(i,rep[i]);
					}
					info += formTemp;
				}
				info += '</div>';
				infoWindow.setContent(info);
				// Otworz okno dla markera
				infoWindow.open(gMap,marker);
				
			});
			
			//------------------------------------------
			// Ustawienie nawigacj dla wyznaczania trasy
			//------------------------------------------
			if(sets.directions && directionsDisplay && directionsService && sets.directionsFormTemplate && infoWindow){
				// Wyznaczanie trasy
				google.maps.event.addListener(infoWindow,'domready',function(){
					$('#'+uniqDirectionsFormId).submit(function(){
						var to 		= $(':input.to', this).val();
						var from 	= $(':input.from', this).val();
						if(!to || to.length == 0 || !from || from.length == 0)
							return false;
						
						to = to.split(',');
						if(typeof(to) != 'object' || to.length != 2)
							return false;
						
						// Ustaw punkt na podstawie pwsolzednych
						var toPoint = new google.maps.LatLng(to[0],to[1]);
						directionsService.route({
							origin : from,
							destination : toPoint,
							travelMode: google.maps.DirectionsTravelMode.DRIVING
						}, function(response,status){
							// Jezeli wygenerowal droge pokaz wskazowki
							if(status == google.maps.DirectionsStatus.OK){
								directionsDisplay.setMap(gMap);
								directionsDisplay.setDirections(response);
								// Pokaz panel z podpowiedziami
								show($(sets.directionsInfoElement));
								// Schowaj dymek
								infoWindow.close();
							}else{
								// Obsluga bledow
								switch(status){
								case google.maps.DirectionsStatus.INVALID_REQUEST:
									alert(sets.directionsError.invalidRequest);
									break;
								case google.maps.DirectionsStatus.NOT_FOUND:
									alert(sets.directionsError.notFound);
									break;
								case google.maps.DirectionsStatus.ZERO_RESULTS:
									alert(sets.directionsError.zeroResult);
									break;
								case google.maps.DirectionsStatus.REQUEST_DENIED:
									alert(sets.directionsError.requestDenied);
									break;
								case google.maps.DirectionsStatus.UNKNOWN_ERROR:
									alert(sets.directionsError.unknowError);
									break;
								}
							}
						});
						return false;
					});
				});
				
			}
			
			//--------------------------------
			// FUNKCJE ZDARZENIOWE DLA MARKERA
			//--------------------------------
			if(sets.draggableMarkers){
				// Wykonaj funkcje przed przesunieciem markera
				if(typeof(sets.markerDragstartCallback) == 'function'){
					google.maps.event.addListener(marker, 'dragstart', function(){
						// Wykonaj funkcje po przesunieciu
						sets.markerDragstartCallback(marker);
					});
				}
				// Wykonaj funkcje podczas przesuwania markera
				if(typeof(sets.markerDragCallback) == 'function'){
					google.maps.event.addListener(marker, 'drag', function(){
						// Wykonaj funkcje po przesunieciu
						sets.markerDragCallback(marker);
					});
				}
				// Wykonaj funkcje po przesunieciu markera
				if(typeof(sets.markerDragendCallback) == 'function'){
					google.maps.event.addListener(marker, 'dragend', function(){
						// Wykonaj funkcje po przesunieciu
						sets.markerDragendCallback(marker);
					});
				}
			}
			
			// Wykonaj funkjce po dodaniu markera
			if(typeof(sets.markerAddCallback) == 'function'){
				sets.markerAddCallback(marker);
			}
			
			return true;
		}
		
		//----------------------
		// FUNKCJA USUWA MARKERY
		//----------------------
		function clearMarkers(){
			// Wyczysc markery
			if(markers && markers.length > 0 && typeof markers == 'object'){
				for(i in markers){
					var marker = markers[i];
					marker.setMap(null);
				}
			}
			markers = [];
			// Wyczysc okna
			if(infoWindows && infoWindows.length > 0 && typeof infoWindows == 'object'){
				for(i in infoWindows){
					var infoWindow = infoWindows[i];
					infoWindow.close();
				}
			}
			infoWindows = [];
		}
		
		
		//----------------------------------------
		// Funkcja generuje mape google w obiekcie
		//----------------------------------------
		function generate(obj){
			if(!obj || obj.length == 0) return false;
			// Ustaw widok mapy
			setView(obj);
			
			//-----------------
			// USTAW OPCJE MAPY
			//-----------------
			var mapOptions = {};
			// Ustaw wspolzedne centrowania mapy
			mapOptions.center = new google.maps.LatLng(sets.lat,sets.lng);
			// Przyblizenie mapy
			mapOptions.zoom = sets.zoom;
			// Ustaw startowy typ mapy
			switch(sets.mapTypeId){
				case 'satellite':
					mapOptions.mapTypeId = google.maps.MapTypeId.SATELLITE;
					break;
				case 'hybrid':
					mapOptions.mapTypeId = google.maps.MapTypeId.HYBRID;
					break;
				case 'terrain':
					mapOptions.mapTypeId = google.maps.MapTypeId.TERRAIN;
					break;
				default:
					mapOptions.mapTypeId = google.maps.MapTypeId.ROADMAP;
					break;
			}
			// 
			mapOptions.disableDefaultUI = true;
			
			// KONTROLKI
			// Navigation / zoom
			if(sets.navigationControl){
				// Wlacz kontrolke nawigacji
				mapOptions.navigationControl = true;
				if(sets.navigationControlStyle == 'small'){
					mapOptions.navigationControlOptions = {
						style : google.maps.NavigationControlStyle.SMALL
					}
				}else if(sets.navigationControlStyle == 'android'){
					mapOptions.navigationControlOptions = {
						style : google.maps.NavigationControlStyle.ANDROID
					}
				}else if(sets.navigationControlStyle == 'zoomPan'){
					mapOptions.navigationControlOptions = {
						style : google.maps.NavigationControlStyle.ZOOM_PAN
					}
				}else{
					mapOptions.navigationControlOptions = {
						style : google.maps.NavigationControlStyle.DEFAULT
					}
				}
			}
			// Skala
			if(sets.scaleControl){
				mapOptions.scaleControl = true;
			}
			// StreetView
			if(sets.streetViewControl){
				mapOptions.streetViewControl = true;
			}
			
			// Wlacz kontrolke typow map
			if(sets.mapTypeControl == true){
				var mapTypeIds = [];
				// NORMAL
				if(sets.mapTypeRoadmap){
					mapTypeIds[mapTypeIds.length] = google.maps.MapTypeId.ROADMAP;
				}
				// SATELITE
				if(sets.mapTypeSatellite){
					mapTypeIds[mapTypeIds.length] = google.maps.MapTypeId.SATELLITE;
				}
				// HYBRID
				if(sets.mapTypeHybrid){
					mapTypeIds[mapTypeIds.length] = google.maps.MapTypeId.HYBRID;
				}
				// TERENOWA
				if(sets.mapTypeTerrain){
					mapTypeIds[mapTypeIds.length] = google.maps.MapTypeId.TERRAIN;
				}
				// Wlacz kontrolke jezeli sa ustawione jakies typy map
				if(mapTypeIds.length > 0){
					mapOptions.mapTypeControl = true;
					mapOptions.mapTypeControlOptions = {
						mapTypeIds : mapTypeIds
					}
				}
			}
			
			// Obsluga myszy
			// Przyblizanie po podwojnym kliknieciu
			if(!sets.dbcZoom)
				mapOptions.disableDoubleClickZoom = sets.dbcZoom;
			// Przyblizanie za pomoca scrolla
			if(!sets.scrollZoom)
				mapOptions.scrollwheel = false;
			
			//------------
			// Stworz mape
			//------------
			gMap = new google.maps.Map(obj.get(0),mapOptions);
			
			// Obsluga dojazdu
			if(sets.directions){
				directionsService = new google.maps.DirectionsService()
				directionsDisplay = new google.maps.DirectionsRenderer({
					panel : $(sets.directionsInfoElement).get(0)
				});
			}
			
			// Dodaj markery
			if(typeof(sets.markers) == 'object' && sets.markers != null){
				// Dostosowanie przyblizenia do ilosci markerow
				if(sets.bounds)
					bounds = new google.maps.LatLngBounds();
				for(i in sets.markers){
					// Pobierz opcje markera
					var marker = sets.markers[i];
					// Jezeli sa wsystkie opcje dodaj marker
					if(typeof(marker['cords']) == 'string' && marker['cords'].length > 0){
						// Pobierz wspolrzedne markera
						var cords = marker['cords'].split(',');
						cords[0] = $.trim(cords[0]);
						cords[1] = $.trim(cords[1]);
						var point = new google.maps.LatLng(cords[0],cords[1]);
						// Dodaj marker
						addMarker(point,marker['title'],marker['description'],marker['icon'],marker['shadow']);
						// Jezeli jest wlaczona opca dostosowania zoom
						if(bounds && sets.bounds){
							bounds.extend(point);
						}
					}
				}
				// Dopasuj
				if(bounds && sets.bounds){
					gMap.fitBounds(bounds);
				}
			}
			
			
			//---------------------------
			// FUNKCJE DODATKOWE DLA MAPY
			//---------------------------
			// Ustawienie markera po kliknieciu
			if(sets.setMarkerOnClick){
				google.maps.event.addListener(gMap, 'click', function(point){
					// wyczysc markery
					clearMarkers();
					// Pobierz nazwe geograficzna kliknietego punktu
					var title = '';
					if(geocoder){
						geocoder.geocode({
							'latLng' : point.latLng
						}, function(result,status){
							// Geokodowanie zakonczylo sie sukcesem - znaleziono lokalizacje
							if(status = google.maps.GeocoderStatus.OK){
								if(result != null){
									var res = result[0];
									title = res.formatted_address;
								}
							}
							// Dodaj marker
							addMarker(point.latLng,title);
							// Wycentruj mape
							gMap.setCenter(point.latLng);
						});
					}else{
						// Dodaj marker
						addMarker(point.latLng,title);
						// Wycentruj mape
						gMap.setCenter(point.latLng);
					}
				});
			}
			
			// Wykonaj funkcje po kliknieciu na mape
			if(typeof(sets.clickCallback) == 'function'){
				google.maps.event.addListener(gMap, 'click', function(point){
					// Wykonaj funkcje po kliknieciu
					sets.clickCallback(point);
				});
			}
			
			// Obiekt geokodowania
			geocoder = new google.maps.Geocoder();
		}
		
		// WYSZUKAJ ADRES NA MAPIE
		function setLocationByAddress(address, zoom, precision){
			if(!address || typeof(address) != 'string' || address.length == 0) return false;
			if(typeof(zoom) != 'number') zoom = 15;
			
			
			geocoder.geocode({
				'address' : address
			}, function(result,status){
				// Geokodowanie zakonczylo sie sukcesem - znaleziono lokalizacje
				if(status = google.maps.GeocoderStatus.OK){
					if(result != null && result.length == 1){
						var res = result[0];
						// Usun markery
						clearMarkers();
						// Dodaj marker
						addMarker(res.geometry.location,res.formatted_address);
						// Centruj mape
						if(res.geometry.bounds)
							gMap.fitBounds(res.geometry.bounds);
					}
				}
			});
			
			return true;
		}
		
		// POBIERZ WARTOSC DO ODSWIERZENIA
//		function getValue(obj,attr,type){
//			if(!obj || typeof(obj) != 'object' || !attr || typeof(attr) != 'string') return false;
//			
//			var value = null;
//			if(attr.indexOf('val-field') != -1){
//				switch(type){
//					case 'select':
//						$('option',obj).each(function(){
//							if($(this).get(0).selected == true){
//								value = $(this).html();
//							}
//						});
//						break;
//					default:
//						value = obj.html();
//					break;
//				}
//			}else value = obj.val();
//			
//			return value;
//		}
		// USTAW ADRES NA PODSTAWIE LOKALIZACJI
		/*
		 * PRECISION
		 * 1 - panstwo, wojewodztwo
		 * 2 - panstwo, wojewodztwo, miasto
		 * 3 - panstwo, wojewodztwo, miasto, adres
		 */
//		function getAddress(location, precision){
//			if(typeof(location) != 'object') return false;
//			
//			// Zoom
//			var zoom = 5;
//			var adr = typeof(location['country']) != 'undefined'? location['country'] : sets.defCountry;
//			
//			if(!precision || (precision && precision >= 1)){
//				if(typeof(location['state']) != 'undefined' && location['state'].length > 0){
//					adr += ' '+location['state'];
//					zoom = 6;
//				}
//			}
//			if(!precision || (precision && precision >= 2)){
//				if(typeof(location['city']) != 'undefined' && location['city'].length > 0){
//					adr += ' '+location['city'];
//					zoom = 11;
//				}
//			}
//			if(!precision || (precision && precision >= 3)){
//				if(typeof(location['address']) != 'undefined' && location['address'].length > 0){
//					adr += ' '+location['address'];
//					zoom = 15;
//				}
//			}
//			
//			return {
//				'address' : adr,
//				'zoom' : zoom
//			};
//		}
		
		//------------------------------
		// Akcja znajdowania lokalizacji
		//------------------------------
		function findAction(obj,opt){
			if(!obj || !opt) return false;
			
			//----------------
			// Pobierz wartosc
			//----------------
			var value = obj.val();
			
			//------------------------------
			// Sprawdz ograniczenie dlugosci
			//------------------------------
			if(value.length == 0) return false;
			if(opt.minlength && opt.minlength > value.length) return false;
			if(opt.maxlength && opt.maxlength < value.length) return false;
			
			//-------------------------------
			// Sprawdz powiazania lokalizacji
			//-------------------------------
			
			// USTAW LOKALIZACJE
			setLocationByAddress(value,opt['zoom']);
		}
		
		//--------------------------------------------
		// Akcja resetuje mape do wysciowego polozenia
		//--------------------------------------------
		function resetAction(){
			// Wroc do poczatkowego polozenia mapy
			if(bounds && sets.bounds){
				gMap.fitBounds(bounds);
			}else if(sets.startPoint){
				// Wycentruj mape
				gMap.setCenter(new google.maps.LatLng(parseFloat(sets.startLat),parseFloat(sets.startLng)));
				gMap.setZoom(sets.startZoom);
			}else{
				// Wycentruj mape
				gMap.setCenter(new google.maps.LatLng(sets.lat,sets.lng));
				gMap.setZoom(sets.zoom);
			}
		}
		
		//--------------
		// WYKONAJ AKCJE 
		//--------------
		function action(obj, type){
			if(typeof(obj) != 'object' || obj.length == 0) return false;
			// Pobierz id obiektu
			var objId = elementId(obj);
			
			// Pobierz ustawienia dla obiektu
			var opt = nav[objId];
			if(!opt || opt.length == 0) return false;
			
			switch(opt.type){
				case 'find':
					findAction(obj,opt);
					break;
				case 'reset':
					resetAction();
					if(opt.clearBefore)
						clearMarkers();
					break;
				case 'showOnMap':
					// Pokaz adres po wsolzednych
					if(opt.cords){
						var cords = opt.cords;
						if(typeof cords == 'string'){
							// Pobierz wsplzedne z parametru elementu
							cords = obj.attr(cords);
							if(cords && typeof cords == 'string' && cords.length > 0)
								cords = cords.split(',');
						}
						if(typeof cords != 'object' || cords.length != 2 || !cords[0] || !cords[1]) 
							return false;
						// Wyznacz punkt
						var point = new google.maps.LatLng(cords[0],cords[1]);
						// Wyczysc markery
						if(opt.clearBefore)
							clearMarkers();
						// Ustaw marker
						addMarker(point);
						// Wycentruj mape
						gMap.setCenter(point);
						// Wyzumuj mape
						var bounds = new google.maps.LatLngBounds();
						if(bounds){
							bounds.extend(point);
							gMap.fitBounds(bounds)
						}
						// 
					}else if(opt.address && opt.address.length > 0){
					
					}
					break;
				case 'panMap':
					var cords = opt.cords;
					if(typeof cords == 'string'){
						// Pobierz wsplzedne z parametru elementu
						cords = obj.attr(cords);
						if(cords && typeof cords == 'string' && cords.length > 0)
							cords = cords.split(',');
					}
					if(typeof cords != 'object' || cords.length != 2 || !cords[0] || !cords[1]) 
						return false;
					// Wyznacz punkt
					var point = new google.maps.LatLng(cords[0],cords[1]);
					// Wyczysc markery
					if(opt.clearBefore)
						clearMarkers();
					// Wycentruj mape
					gMap.setCenter(point);
					break;
			}
			
			// Callkack function
			if(typeof opt.callback == 'function'){
				opt.callback(obj);
			}
			
			return (opt.ret === true? true : false);
		}
		
		//---------------------------------------------
		// -- Ustaw opcje dla elementow do nawigacji --
		//---------------------------------------------
		function setNavigationOptions(){
			// Sprawdz czy jest zapisana jakas nawigacja
			if(sets.navigation == null || typeof(sets.navigation) != 'object') return false;
			
			// Ustaw nawigacje
			for(var i in sets.navigation){
				// Pobierz obiekt/y
				var obj = $(i);
				// Jezeli obiekt nie istnieje przejdz do kolejnego
				if(obj.length == 0) continue;
				// Pobierz opcje dla nawigacji
				var opt = sets.navigation[i];
				// Ustaw dla kazdego pasujacego elementu
				obj.each(function(){
					// Pobierz / ustaw unikalny id dla obiektu
					var objId = elementId($(this));
					// Zapisz opcje do pamieci
					nav[objId] = opt;
				});
			}
			
			return true;
		}
		
		//----------------
		// Ustaw nawigacje
		//----------------
		function setNavigation(){
			//------------------
			// Czyszczenie trasy
			//------------------
			if(sets.directionsInfoClearElement && sets.directions && directionsService && directionsDisplay){
				$(sets.directionsInfoClearElement).click(function(){
					// Wyczysc trase
					directionsDisplay.setMap();
					resetAction();
					// Schowaj warstwe
					hide($(sets.directionsInfoElement));
					return false;
				});
			}
			
			
			//---------------------------
			// Ustaw zewnetrzna nawigacje
			//---------------------------
			if(sets.navigation && typeof(sets.navigation) == 'object'){
				// ustaw opcje elementow nawigacji
				setNavigationOptions();
				
				for(var i in sets.navigation){
					// Pobierz obiekt/y
					var obj = $(i);
					
					// Pobierz opcje dla nawigacji
					var opt = sets.navigation[i];
					
					switch(opt['action']){
					case 'submit':
						if(opt['live']){
							$(':submit',obj).live('click',function(){
								var form = $(this).parents('form');
								var formId = elementId(form);
								nav[formId]['submit'] = $(this);
							});
							obj.live('submit',function(){
								return action($(this));
							});
						}else{
							$(':submit',obj).click(function(){
								var form = $(this).parents('form');
								var formId = elementId(form);
								nav[formId]['submit'] = $(this);
							});
							obj.submit(function(){
								return action($(this));
							});
						}
						break;
					default:
						if(opt['live']){
							obj.live(opt['action'],function(){
								if(typeof(wts_confirm_result) != 'undefined' && wts_confirm_result === false){
									wts_confirm_result = undefined;
									return false;
								}else{
									setNavigationOptions();
									return action($(this));
								}
							});
						}else{
							obj.bind(opt['action'],function(){
								if(typeof(wts_confirm_result) != 'undefined' && wts_confirm_result === false){
									wts_confirm_result = undefined;
									return false;
								}else{
									return action($(this));
								}
							});
						}
						break;
					}
				}
			}
		}
		
		//-----------------------
		// USTAW POCZATKOWY ADRES
		//-----------------------
//		function setStartAddress(){
//			// Dla select
//			$('select['+sets.navi+'*="loc-country"], select['+sets.navi+'*="loc-state"], select['+sets.navi+'*="loc-city"], select['+sets.navi+'*="loc-address"]').each(function(){
//				// Pobierz atrybuty
//				var attributes = $(this).attr(sets.navi);
//				// Pobierz typ lokalizacji
//				var locType = getLocType(attributes);
//				// Pobierz wartosc typu
//				_location[locType] = getValue($(this),attributes,'select');
//			});
//			$(':text['+sets.navi+'*="loc-country"], :text['+sets.navi+'*="loc-state"], :text['+sets.navi+'*="loc-city"], :text['+sets.navi+'*="loc-address"], textarea['+sets.navi+'*="loc-country"], textarea['+sets.navi+'*="loc-state"], textarea['+sets.navi+'*="loc-city"], textarea['+sets.navi+'*="loc-address"], :checkbox['+sets.navi+'*="loc-country"], :checkbox['+sets.navi+'*="loc-state"], :checkbox['+sets.navi+'*="loc-city"], :checkbox['+sets.navi+'*="loc-address"], :radio['+sets.navi+'*="loc-country"], :radio['+sets.navi+'*="loc-state"], :radio['+sets.navi+'*="loc-city"], :radio['+sets.navi+'*="loc-address"],').each(function(){
//				// Pobierz atrybuty
//				var attributes = $(this).attr(sets.navi);
//				// Pobierz typ lokalizacji
//				var locType = getLocType(attributes);
//				// Pobierz wartosc typu
//				_location[locType] = getValue($(this),attributes);
//			});
//			
//			// Sprawdz czy jest ustawiony punkut poczatkowy
//			if(sets.startPoint == true){
//				// Wyczysc markery
//				clearMarkers();
//				// Wycentruj mape
//				gMap.setCenter(new GLatLng(parseFloat(sets.startLat),parseFloat(sets.startLng)), sets.startZoom);
//				// Dodaj marker dla punktu poczatkowego
//				addMarker(parseFloat(sets.startLat),parseFloat(sets.startLng));
//			}else if(_location['country'] || _location['city'] || _location['state'] || _location['address']){
//				// Nie ma punktu poczatkowego, wyznacz lokalizacje zgodnie z ustawieniami formularza
//				// Pobierz adres
//				var addData = getAddress(_location);
//				// Wyczysc markery
//				clearMarkers();
//				// Ustaw marker wedlug adresu
//				getLocationsByAddress(addData['address'], addData['zoom']);
//			}
//		}
		
		// Funkcja ustawiajaca dane poczatkowe
		function initialize(){
			// Jezeli nie ma obiektow to wyjdz z funkcji
			if(!self) return false;
			if(!self.is(':visible')){
				var intervalId = setInterval(function(){
					if(self.is(':visible')){
						// Wyczysc interval
						clearInterval(intervalId);
						// Generuj mape google
						generate(self);
						// Ustaw nawigacje
						setNavigation();
						// Ustaw poczatkowa lokalizacje
//						setStartAddress();
					}
				},500);
			}else{
				// Generuj mape google
				generate(self);
				// Ustaw nawigacje
				setNavigation();
				// Ustaw poczatkowa lokalizacje
//				setStartAddress();
			}
		}
		initialize();
	}
})(jQuery);
