/**
 * 
 */

	/*
$(document).ready(function () {
	$('body *').each(function () {
		this.normalize();
	});
});
	*/

function WimMap(opts) {
	opts = opts ? opts : {};
	opts.boundsChangedSmoothTimeout = opts.boundsChangedSmoothTimeout ?
		opts.boundsChangedSmoothTimeout :
		300
		;
	
	if (opts.mobileIcons) {
		var __icons = {
				a:	new google.maps.MarkerImage(
					'/images/wvga/markers/a.png', 
					new google.maps.Size(36,42), 
					new google.maps.Point(0, 0),
					new google.maps.Point(32, 38)
					),
				b:	new google.maps.MarkerImage(
					'/images/wvga/markers/b.png', 
					new google.maps.Size(42,33), 
					new google.maps.Point(0, 0),
					new google.maps.Point(38, 17)
					),
				c:	new google.maps.MarkerImage(
					'/images/wvga/markers/c.png', 
					new google.maps.Size(36,42), 
					new google.maps.Point(0, 0),
					new google.maps.Point(32, 5)
					),
				d:	new google.maps.MarkerImage(
					'/images/wvga/markers/d.png', 
					new google.maps.Size(36,42), 
					new google.maps.Point(0, 0),
					new google.maps.Point(5, 5)
					),
				e:	new google.maps.MarkerImage(
					'/images/wvga/markers/e.png', 
					new google.maps.Size(42,33), 
					new google.maps.Point(0, 0),
					new google.maps.Point(5, 17)
					),
				f:	new google.maps.MarkerImage(
					'/images/wvga/markers/f.png', 
					new google.maps.Size(36,42), 
					new google.maps.Point(0, 0),
					new google.maps.Point(5, 38)
					)
				};
			
			var __singleIcons = {
				a:	new google.maps.MarkerImage(
					'/images/wvga/markers/single-a.png', 
					new google.maps.Size(33, 40), 
					new google.maps.Point(0, 0),
					new google.maps.Point(11, 37)
					),
				b:	new google.maps.MarkerImage(
					'/images/wvga/markers/single-b.png', 
					new google.maps.Size(33, 40), 
					new google.maps.Point(0, 0),
					new google.maps.Point(11, 37)
					),
				c:	new google.maps.MarkerImage(
					'/images/wvga/markers/single-c.png', 
					new google.maps.Size(33, 40), 
					new google.maps.Point(0, 0),
					new google.maps.Point(11, 37)
					),
				d:	new google.maps.MarkerImage(
					'/images/wvga/markers/single-d.png', 
					new google.maps.Size(33, 40), 
					new google.maps.Point(0, 0),
					new google.maps.Point(11, 37)
					),
				e:	new google.maps.MarkerImage(
					'/images/wvga/markers/single-e.png', 
					new google.maps.Size(33, 40), 
					new google.maps.Point(0, 0),
					new google.maps.Point(11, 37)
					),
				f:	new google.maps.MarkerImage(
					'/images/wvga/markers/single-f.png', 
					new google.maps.Size(33, 40), 
					new google.maps.Point(0, 0),
					new google.maps.Point(11, 37)
					)
				};
	
	} else {
		var __icons = {
			a:	new google.maps.MarkerImage(
				'/images/markers/a.png', 
				new google.maps.Size(19,22), 
				new google.maps.Point(0, 0),
				new google.maps.Point(16, 19)
				),
			b:	new google.maps.MarkerImage(
				'/images/markers/b.png', 
				new google.maps.Size(22,18), 
				new google.maps.Point(0, 0),
				new google.maps.Point(19, 8)
				),
			c:	new google.maps.MarkerImage(
				'/images/markers/c.png', 
				new google.maps.Size(19,22), 
				new google.maps.Point(0, 0),
				new google.maps.Point(16, 2)
				),
			d:	new google.maps.MarkerImage(
				'/images/markers/d.png', 
				new google.maps.Size(19,22), 
				new google.maps.Point(0, 0),
				new google.maps.Point(2, 2)
				),
			e:	new google.maps.MarkerImage(
				'/images/markers/e.png', 
				new google.maps.Size(22,18), 
				new google.maps.Point(0, 0),
				new google.maps.Point(2, 8)
				),
			f:	new google.maps.MarkerImage(
				'/images/markers/f.png', 
				new google.maps.Size(19,22), 
				new google.maps.Point(0, 0),
				new google.maps.Point(2, 19)
				)
			};
		
		var __singleIcons = {
			a:	new google.maps.MarkerImage(
				'/images/markers/single-a.png', 
				new google.maps.Size(15, 21), 
				new google.maps.Point(0, 0),
				new google.maps.Point(5, 18)
				),
			b:	new google.maps.MarkerImage(
				'/images/markers/single-b.png', 
				new google.maps.Size(15, 21), 
				new google.maps.Point(0, 0),
				new google.maps.Point(5, 18)
				),
			c:	new google.maps.MarkerImage(
				'/images/markers/single-c.png', 
				new google.maps.Size(15, 21), 
				new google.maps.Point(0, 0),
				new google.maps.Point(5, 18)
				),
			d:	new google.maps.MarkerImage(
				'/images/markers/single-d.png', 
				new google.maps.Size(15, 21), 
				new google.maps.Point(0, 0),
				new google.maps.Point(5, 18)
				),
			e:	new google.maps.MarkerImage(
				'/images/markers/single-e.png', 
				new google.maps.Size(15, 21), 
				new google.maps.Point(0, 0),
				new google.maps.Point(5, 18)
				),
			f:	new google.maps.MarkerImage(
				'/images/markers/single-f.png', 
				new google.maps.Size(15, 21), 
				new google.maps.Point(0, 0),
				new google.maps.Point(5, 18)
				)
			};
	}
	
	var __instance = this;
	
	var map = new google.maps.Map(opts.container, {
		mapTypeId: opts.type ? opts.type : google.maps.MapTypeId.ROADMAP,
		center: new google.maps.LatLng(
			opts.center ? opts.center.lat : 53.73859603422922, 
			opts.center ? opts.center.lng : 21.37001157812506
			),
		zoom: opts.zoom ? opts.zoom : 8
		});
	
	this.getGMap = function () {
		return map;
	};
	
	this.logLocation = function () {
		console.log('%s, %s', map.getCenter(), map.getZoom());
	};

	var __noReloadOnViewportChange = false;
	
	var __titles = {
		a:	'Atrakcje turystyczne',
		b:	'Żeglarstwo',
		c:	'Jachty motorowe',
		d:	'Noclegi',
		e:	'Aktywny wypoczynek',
		f:	'Gastronomia'
	};
	
	var __prevInfoWindow;

	var __itemsPerPage = opts.itemsPerPage ?
		opts.itemsPerPage :
		10
		;
	
	var __pagerWidth = opts.pagerWidth ?
		opts.pagerWidth :
		3
		;
	
	var __markers = [];
	var __results = [];
	
	var __buildListItem = function (id, imgSize, opts) {
		var li = document.createElement('li');
		var item = objects [id];
		opts || (opts = {});
		
		if (item !== undefined) {
			item.getAddress = function () {
				return item.address ?
					item.loc + (item.address.match(/^\d+[a-z]?$/i) ? ' ' : ', ') + item.address :
					item.loc
					;
			};
			
			switch (item.promo) {
				case 1:
					$(li).addClass('silver premium');
					break;
				case 2:
					$(li).addClass('gold premium');
					break;
			}
			
			var info = document.createElement('div');
				$(info).addClass('info');
				
			if (item.imgId) {
				var photo = document.createElement('div');
					$(photo).addClass('photo');
					li.appendChild(photo);
					
				var imgA = document.createElement('a');
					photo.appendChild(imgA);
					imgA.href=item.url;
					
				var img = document.createElement('img');
					img.src = '/images/photos/' + item.imgId + '.' + imgSize + '.jpg';
					imgA.appendChild(img);
					
			} else {
				$(info).css('max-width', 'none');
			}
				
			var title = document.createElement('h4');
				info.appendChild(title);
				var a = document.createElement('a');
					title.appendChild(a);
					a.innerHTML = item.label;
					a.href=item.url;
					
				if (item.podbicie) {
					var podbicie = document.createElement('span');
						podbicie.innerHTML = '<span>' + item.podbicie + '</span>';
						podbicie.setAttribute('title', 'Punkty podbicia');
						$(podbicie).addClass('podbij-score');
						title.appendChild(podbicie);
				}
				
			var desc = document.createElement('p');
				desc.innerHTML = item.getAddress();
				info.appendChild(desc);
				
			var genres = document.createElement('ul');
				for (var productId in item.genres) {
					var genre = window.genres [item.genres [productId]];
					
					genre.getUrl = function (objectId, productId) {
						return '/produkty-i-uslugi/' + productId + '-' + objectId + objects [objectId].url.replace(/.*\/([^\/]*)$/, '/$1/') + this.simpleUrl;
					};
					
					var genreLi = document.createElement('li');
						genres.appendChild(genreLi);
						
					var a = document.createElement('a');
						a.innerHTML = genre.label.replace(/\s+/, '&nbsp;');
						a.href = genre.getUrl(id, productId);
						genreLi.appendChild(a);

				}
				info.appendChild(genres);

			li.appendChild(info);
			
			if (opts.showOnTheMapButton) {
				var tools = document.createElement('div');
					$(tools).addClass('tools');
					
				var showOnTheMap = document.createElement('span');
					showOnTheMap.__marker = __markersByObjectId [id];
					$(showOnTheMap).addClass('show-on-the-map');
					tools.appendChild(showOnTheMap);
					
					$(showOnTheMap).click(function () {
						__markerClickHandler.call(this.__marker);
					});
					
					
				li.appendChild(tools);
			}
		}
				
		return li;
	};
	
	
	var __pagerSpanClick = function (event) {
		__instance.fillResultsPage(this.__pageNo);
	};
	
	var __createPagerSpan = function (label, pageNo, className) {
		var span = document.createElement('span');
			span.innerHTML = label;
			span.__pageNo = pageNo;
			
			if (className) {
				$(span).addClass(className);
			}
			
			$(span).click(__pagerSpanClick);
		
		return span;
	};
	
	var __refreshPager = function (pager, pagerBox) {
		pagerBox.innerHTML = '';
		
		if (pager.getPrev()) {
			pagerBox.appendChild(__createPagerSpan('&laquo; poprzednia', pager.getPrev(), 'nav'));
		}

		
		if (pager.getFirst()) {
			pagerBox.appendChild(__createPagerSpan('1' + pager.getLeftDots(' ...'), pager.getFirst()));
		}
		
		var pages = pager.getPages();
		for (var i in pages) {
			pagerBox.appendChild(__createPagerSpan(pages [i], pages [i], (pager.getCurrentPage() == pages [i]) ? 'current' : undefined));
		}
		
		if (pager.getLast()) {
			pagerBox.appendChild(__createPagerSpan(pager.getRightDots('... ') + pager.getPagesCount(), pager.getLast(), (pager.getCurrentPage() == pager.getLast()) ? 'current' : undefined));
		}
		
		if (pager.getNext()) {
			pagerBox.appendChild(__createPagerSpan('następna &raquo;', pager.getNext(), 'nav'));
		}

	};
	
	this.fillResultsPage = function (pageNo) {
		var start = (pageNo - 1) * __itemsPerPage;
		var end = start + __itemsPerPage;
		
		var pageItems = __results.slice(start,end);
		
		if (__results.length == 0) {
			opts.resultsList.innerHTML = '<div class="no-results"><p>Nic nie znaleziono.</p></div>';
			
		} else {
			
			new (function (ids) { 
				opts.resultsList.innerHTML = '<div class="ajax-loader"><img src="/images/map/ajax-loader.gif" /></div>';
				
				var __requestIds = [];
				for (var i in ids) {
					if (typeof objects [ids [i]] == 'undefined') {
						__requestIds.push(ids [i]);
					}
				}
				
				var __displayResults = function () {
					opts.resultsList.innerHTML = '';
					
					for (var i in ids) {
						var li = __buildListItem(ids [i], 'results', {showOnTheMapButton: true});
						
						opts.resultsList.appendChild(li);
					}
				};
				
				if (__requestIds.length == 0) {
					__displayResults();
					
				} else {
					$.ajax({
						url: '/feed-me/get-objects',
						type: 'post',
						data: {
							ids: __requestIds
							},
							
						success: function (response, status) {
							for (var i in response.objects) {
								objects [i] = response.objects [i];
							}
							
							__displayResults();							
							},
							
						error: function () {
							opts.resultsList.innerHTML = '<div class="error"><p>Błąd serwera. Odczekaj chwilę i spróbuj ponownie.</div>';
							}
						});
				}
				
			}) 
				(pageItems)
				;
			
			
		}
		
		var pager = new PBPager({
			itemsCount: __results.length,
			pagerWidth: __pagerWidth,
			itemsPerPage: __itemsPerPage,
			page: pageNo
			});
		
		if (opts.pagerTop) {
			__refreshPager(pager, opts.pagerTop);
		}
		
		if (opts.pagerBottom) {
			__refreshPager(pager, opts.pagerBottom);
		}
		
		return this;
	};
	
	var __markerClickHandler = function (event) {
		if (!this.__infoWindow) {
			var wrapper = document.createElement('div');
				$(wrapper).addClass('map-info-window-wrapper');
				
			var container = document.createElement('div');
				$(container).addClass('map-info-window');
				wrapper.appendChild(container);
				
			var header = document.createElement('h3');
				header.innerHTML = __titles [this.__genre];
				//container.appendChild(header);
				
			var list = document.createElement('ul');
				container.appendChild(list);

			new (function (list, ids) { 
				var __requestIds = [];
				for (var i in ids) {
					if (typeof objects [ids [i]] == 'undefined') {
						__requestIds.push(ids [i]);
					}
				}

				var __displayResults = function () {
					for (var i in ids) {
						var li = __buildListItem(ids [i], 'map');
							$(li).addClass((i % 2) ? 'even' : 'odd');
							list.appendChild(li);
					}
				};
				
				if (__requestIds.length == 0) {
					__displayResults();
					
				} else {
					$.ajax({
						url: '/feed-me/get-objects',
						type: 'post',
						data: {
							ids: __requestIds
							},
							
						success: function (response, status) {
							for (var i in response.objects) {
								objects [i] = response.objects [i];
							}
							
							__displayResults();							
							}
						});
				}
				
			})
				(list, this.__items)
				;
			
			this.__infoWindow = new google.maps.InfoWindow({
				content: wrapper
			});
		}
		
		if (__prevInfoWindow !== undefined) {
			__prevInfoWindow.close();
		}
		__prevInfoWindow = this.__infoWindow;
			
		__noReloadOnViewportChange = true;
		this.__infoWindow.open(map, this);
		setTimeout(function () {
			__noReloadOnViewportChange = false;
		}, 1000);
		
	};
	
	var __markersByObjectId = {};
	var __populate = function (response) {
		if (response === null) {
			opts.resultsList.innerHTML = '<div class="error"><p>Błąd serwera. Odczekaj chwilę i spróbuj ponownie.</div>';
			response = {
				markers: [],
				results: []
			};
		}
		
		__markersByObjectId = {};
		for (var i in response.markers) {
			var group = response.markers [i];
				
			var _icons = (group.locationCount == 1) ?
				__singleIcons : 
				__icons
				;
		
			for (var g in group ['genres']) {
				var genre = group ['genres'] [g];
				
				if (genre.length > 0) {
					var marker;
					
					__markers.push(
						marker = new google.maps.Marker({
							map: map,
							position: new google.maps.LatLng(group.lat, group.lng, true),
							icon: _icons [g],
							title: 'ilość ogłoszeń: ' + genre.length
						}));
					
					marker.__items = genre;
					marker.__genre = g;
					
					for (var i in genre) {
						__markersByObjectId [genre [i]] = marker;
					}
					
					google.maps.event.addListener(marker, 'click', __markerClickHandler);
				}
			}
		}
		
		__results = response.results;
		objects = response.firstPage;
		
		__instance.fillResultsPage(1);
	};

	var __filter = opts.filters;
	this.setFilter = function (genreIds) {
		__filter = genreIds;
		return this;
	};
	
	this.populate = function () {
		for (var i in __markers) {
			__markers [i].setMap(null);
		}
		__markers = [];
		
		var data = {
			neLat:	map.getBounds().getNorthEast().lat(),
			neLng:	map.getBounds().getNorthEast().lng(),
			swLat:	map.getBounds().getSouthWest().lat(),
			swLng:	map.getBounds().getSouthWest().lng(),

			zoom: map.getZoom()
			};
		
		if (opts.groupRadius) {
			data ['group-radius'] = opts.groupRadius;
		}
		
		if (__filter && __filter.length > 0) {
			data.filter = __filter;
		}
		
		$.ajax({
			url: 		opts.populateFeedUrl,
			success: 	__populate,
			dataType:	'json',
			type:		'POST',
			data: 		data
			});
		
		opts.resultsList.innerHTML = '<div class="ajax-loader"><img src="/images/map/ajax-loader.gif" /></div>';
		if (opts.pagerTop) {
			opts.pagerTop.innerHTML = '';
		}
		
		if (opts.pagerBottom) {
			opts.pagerBottom.innerHTML = '';
		}
		
		return this;
	};
		
	var __boundsChangedCallback = opts.boundsChangedCallback ?
		opts.boundsChangedCallback :
		undefined
		;
	
		this.setBoundsChangedCallback = function (handler) {
			__boundsChangedCallback = handler;
		};
		
		var __boundsChanged = function (e) {
			if (!__noReloadOnViewportChange) {
				__instance.populate();				
			}
			
			if (typeof __boundsChangedCallback == 'function') {
				__boundsChangedCallback.call(__instance, e);
			}
		};
	
	var __boundsChangedTimerId;
		var __boundsChangedHandler = function () {
			clearTimeout(__boundsChangedTimerId);
			__boundsChangedTimerId = setTimeout(__boundsChanged, 
				opts.boundsChangedSmoothTimeout
				);
		};
		google.maps.event.addListener(map, 'bounds_changed', __boundsChangedHandler);

	var __userChangedMapBounds = function (event) {
		if (opts.areaSelector) {
			__customArea.selected = true;
		}
	};
	google.maps.event.addListener(map, 'dragend', __userChangedMapBounds);
		
	this.setCenter = function (lat, lng) {
		map.setCenter(new google.maps.LatLng(lat, lng, true));
		
		return this;
	};
	
	this.setZoom = function (n) {
		map.setZoom(n);
		
		return this;
	};

	var __appendArea = function (areaInfo) {
		var area = document.createElement('option');
			area.innerHTML = areaInfo.label;
			area.__center = areaInfo.center;
			area.__zoom = areaInfo.zoom;
			
		opts.areaSelector.appendChild(area);
		
		if (areaInfo.selected) {
			map.setCenter(new google.maps.LatLng(areaInfo.center.lat, areaInfo.center.lng, true));
			map.setZoom(areaInfo.zoom);
			area.selected = true;
		}
		
		return area;
	};
	
	if (opts.areaSelector) {
		opts.areas = opts.areas ? opts.areas : [];
		
		var __customArea = document.createElement('option');
			__customArea.setAttribute('disabled', 'disabled');
			__customArea.innerHTML = 'Szukaj w pobliżu...';
			opts.areaSelector.appendChild(__customArea);

		if (opts.zoom && opts.center.lat && opts.center.lng) {
			opts.areas.push({
				label:	'* Obszar z linka *',
				zoom:	opts.zoom,
				center: {
					lat:	opts.center.lat,
					lng:	opts.center.lng
					},
				selected: true
				});
		}			
			
		for (var i in opts.areas) {
			__appendArea(opts.areas [i]);
		}
		
		$(opts.areaSelector).change(function (event) {
			var opt = this.item(this.selectedIndex);
			
			if (opt.__center && opt.__zoom) {
				__instance.setCenter(opt.__center.lat, opt.__center.lng);
				__instance.setZoom(opt.__zoom);
			}
		});
	}
}







function SubjectLocationMap(opts) {
	opts = opts ? opts : {};
	
	var map = new google.maps.Map(opts.container, {
		mapTypeId: opts.type ? opts.type : google.maps.MapTypeId.ROADMAP,
		center: new google.maps.LatLng(
			opts.center ? opts.center.lat : 53.778422, 
			opts.center ? opts.center.lng : 20.480119
			),
		zoom: opts.zoom ? opts.zoom : 4
		});

	var geoCoder = new google.maps.Geocoder()
		;

	var __markerMouseUpCallback;
	this.setMarkerMouseUpCallback = function (callback) {
		__markerMouseUpCallback = callback;
		
		return this;
	};

	var __geoCoderAddressCallback;
	this.setGeoCoderAddressCallback = function (callback) {
		__geoCoderAddressCallback = callback;

		return this;
	};
	
	var __resolveMarkerAddress = function (event) {
		geoCoder.geocode({latLng: this.position}, function (results, status) {
			if (status == google.maps.GeocoderStatus.OK) {
				__geoCoderAddressCallback(results [1]);
				
			} else {
				// silent ooops
			}
		});
	};

	var __attachMarkerCallbacks = function (marker) {
		if (typeof __markerMouseUpCallback == 'function') {
			google.maps.event.addListener(marker, 'mouseup', __markerMouseUpCallback);
		}

		if (typeof __geoCoderAddressCallback == 'function') {
			google.maps.event.addListener(marker, 'dblclick', __resolveMarkerAddress);
		}
	};
	
	var __createdMarker; 
	this.enableMarkerCreationByClick = function (opts) {
		new (function (opts) {
			google.maps.event.addListener(map, 'click', function (event) {
				if (__createdMarker) {
					__createdMarker.setMap(null);
				}
				
				opts || (opts = {});
				opts.position = event.latLng;
				opts.map = map;
				opts.draggable = (typeof opts.draggable != 'undefined') ?
						opts.draggable :
						true
						;
				__createdMarker = new google.maps.Marker(opts);
				
				__attachMarkerCallbacks(__createdMarker);
				google.maps.event.trigger(__createdMarker, 'mouseup', {latLng: __createdMarker.getPosition()});
			});
		})
			(opts)
			;
		
		return this;
	};

	var __addressFoundCallback;
	this.setAddressFoundCallback = function (callback) {
		__addressFoundCallback = callback;
		
		return this;
	};

	var __noAddressFoundCallback;
	this.setNoAddressFoundCallback = function (callback) {
		__noAddressFoundCallback = callback;
		
		return this;
	};
	
	var __addressMarkers = [];
	this.findAddress = function (address, callback) {
		geoCoder.geocode({address: address}, function (results, status) {
			if (status == google.maps.GeocoderStatus.OK) {
			    map.setCenter(results [0].geometry.location);
			    
			    for (var i in __addressMarkers) {
			    	__addressMarkers [i].setMap(null);
			    }
			    __addressMarkers = [];
			    
				for (var i in results) {
					var marker = new google.maps.Marker({
						position: results [i].geometry.location,
						title: results [i].formatted_address,
						draggable: true,
						map: map
						});
					
					__attachMarkerCallbacks(marker);
					__addressMarkers.push(marker);
				}

				if (typeof __addressFoundCallback == 'function') {
					__addressFoundCallback(results);
				}
					
			} else if (status == google.maps.GeocoderStatus.ZERO_RESULTS) {
				if (typeof __noAddressFoundCallback == 'function') {
					__noAddressFoundCallback();
				}					
				
			} else {
				// silent ooops
			}
		});

		return this;
	};
	
	this.addMarkerAt = function (lat, lng, data) {
		var marker = new google.maps.Marker({
			position: new google.maps.LatLng(lat, lng),
			draggable: false,
			map: map
			});
		
		__attachMarkerCallbacks(marker);
		marker.__data = data;		
		return this;
	};
	
	
	var __neLat = -400;
	var __neLng = -400;
	var __swLat = 400;
	var __swLng = 400;
	this.addMBRPoint= function (lat, lng) {
		if (lat < __swLat) {
			__swLat = lat;
		}
		
		if (lat > __neLat) {
			__neLat = lat;
		}
		
		if (lng < __swLng) {
			__swLng = lng;
		}
		
		if (lng > __neLng) {
			__neLng = lng;
		}
		
		return this;
	};
	
	this.centerAtMBR = function (padding) {
		var pos = new google.maps.LatLng((parseFloat(__swLat) + parseFloat(__neLat)) / 2, (parseFloat(__swLng) + parseFloat(__neLng)) / 2, true);
		
		map.setCenter(pos);
		map.setZoom(8);
		
		return this;
	};
	
	this.addMarker = function (opts, center) {
		opts.map = map;
		
		var marker = new google.maps.Marker(opts);
		__attachMarkerCallbacks(marker);
		
		if (center) {
			map.setCenter(marker.position);
		}
		
		return marker;
	};
	
	this.setCenter = function (lat, lng) {
		map.setCenter(new google.maps.LatLng(lat, lng, true));
		
		return this;
	};
	
	this.setZoom = function (n) {
		map.setZoom(n);
		
		return this;
	};
}

function SelectionBox(opts) {
	var __box = document.createElement('div');
	opts.container.appendChild(__box);
		
	var __label = document.createElement('label');
		__box.appendChild(__label);
	
	var __input = document.createElement('input');
		__box.appendChild(__input);
		__input.name = opts.fieldName;
		__input.type = 'hidden';
	
	var __span = document.createElement('span');
		__box.appendChild(__span);
		var __textInput = document.createElement('input');
			__textInput.setAttribute('autocomplete', 'off');
			__span.appendChild(__textInput);

	var __mapMarker = {
			setMap: function () {}
	};
			
	if (opts.delBtn) {
		var __delBtn = document.createElement('input');
			$(__delBtn).addClass('deleteBtn');
			__delBtn.type = 'button';
			__delBtn.value = '';
			__box.appendChild(__delBtn);
			$(__delBtn).click(function () {
				opts.container.removeChild(__box);
				__mapMarker.setMap(null);
			});
	}
			
	var __desc = document.createElement('p');
	__box.appendChild(__desc);
	
	switch (opts.boxType) {
		case SelectionBox.BOX_TYPE_PRODUCT:
			__label.innerHTML = 'Produkt';
			break;
			
		case SelectionBox.BOX_TYPE_SUBJECT:
			__label.innerHTML = 'Właściciel';
			break;
			
		case SelectionBox.BOX_TYPE_PLACE:
			__label.innerHTML = 'Miejsce';
			break;
			
		default:
			__label.innerHTML = opts.label ?
				opts.label :
				''
				;
	}
	
	var __ajaxSuggest = $(__span).ajaxSuggest({
		listClassName:	'ajax-suggestion',
		actionUrl:		opts.actionUrl,
		input:			__textInput,
		
		itemSelectedCallback: function (result) {
			if (result.desc) {
				__desc.innerHTML = result.desc;
			}
			
			__input.value = result.id;
			
			var latLng = new google.maps.LatLng(
				result.latLng.lat,
				result.latLng.lng
				);
			
			
			if (opts.map) {
				__mapMarker.setMap(null);
				
				__mapMarker = opts.map.addMarker({
					position: latLng,
					title: result.desc ? result.desc : '',
					draggable: false,
					label: result.desc ? result.desc : '',
					icon: opts.icon ? opts.icon : undefined
					}, true);
			}
			
		},
		
		submitCallback: function () {
			return false;
		} 
	});
	
	this.hide = function () {
		__ajaxSuggest.hideList();
	};
}

SelectionBox.BOX_TYPE_PRODUCT = 1;
SelectionBox.BOX_TYPE_SUBJECT = 2;
SelectionBox.BOX_TYPE_PLACE = 3;


function GeoLocation(opts) {
	opts = opts ? opts : {};
	var __instance = this;
	
	
	var __successCallback = opts.success ?
		opts.success :
		function () {}
		;
		
	var __errorCallback = opts.error ?
		opts.error :
		function () {}
		;
				
	var __geoNotAvailableCallback = opts.geoNotAvailable ?
		opts.geoNotAvailable :
		function () {}
		;
				
	/**
	 * @param {function (Position)} callback
	 * @this {GeoLocation}
	 * @return {GeoLocation}
	 */
	this.setSuccessCallback = function (callback) {
		__successCallback = callback;
		
		return this;
	};
		
	/**
	 * @param {function (PositionError)} callback
	 * @this {GeoLocation}
	 * @return {GeoLocation}
	 */
	this.setErrorCallback = function (callback) {
		__errorCallback = callback;
		
		return this;
	};
			
	/**
	 * @param {function ()} callback
	 * @this {GeoLocation}
	 * @return {GeoLocation}
	 */
	this.setGeoNotAvailableCallback = function (callback) {
		__geoNotAvailableCallback = callback;
		
		return this;
	};
	
	var __foundLocation = function (position) {
		__successCallback.call(__instance, position);
	};
	
	var __errorHandler = function (error) {
		__errorCallback.call(__instance, error);
	};
	
	var __geoNotAvailable = function () {
		__geoNotAvailableCallback.call(__instance);
	};
	
	var __locator = function (opts, tryHighAccuracy) {
		if (tryHighAccuracy) {
			var __highErrorAccuHandler = function (error) {
				if (error.code == error.POSITION_UNAVAILABLE) {
					navigator.geolocation.getCurrentPosition(__foundLocation, __errorHandler, opts ? opts : {});
					//console.log('high resolution failed, trying standard.');
					
				} else {
					__errorHandler(error);
				}
			};
			
			navigator.geolocation.getCurrentPosition(__foundLocation, __highErrorAccuHandler, {
				maximumAge: opts.maximumAge,
				enableHighAccuracy: true,
				timeout: opts.timeout
				});
			
		} else {
			navigator.geolocation.getCurrentPosition(__foundLocation, __errorHandler, opts);
		}
	};
	
	/**
	 * @param {enableHighAccuracy, timeout, maximumAge} opts
	 * @param {bool} tryHighAccuracy will try to obtain high accuracy position and fallback to low accuracy if necessary
	 * @this {GeoLocation}
	 * @return {GeoLocation}
	 */
	this.geoLocate = function (opts, tryHighAccuracy) {
		if (navigator.geolocation) {
			new __locator(
				opts ? opts : {}, 
				tryHighAccuracy
				);
			
		} else {
			__geoNotAvailable();
		}
		
		return this;
	};
}

