/*encoding: utf-8 */
/*jslint onevar: false, browser: true, white: false, passfail: false, maxerr: 10, plusplus: false */
/*global window, jQuery, RequestManager */
(function($) {
	"use strict";
	$.fn.extend({
		'prMapSearch': function(options) {
			var defaults = {
				'ns': '',
				'map': true,
				'markers': [],
				'oneMarker': true,
				'allowDragging': false,
				'google': window.google,
				'fillData': function(el, data) {
					var $el = $(el);
					var fields = {};
					
					$.each(data.address_components, function(i, v) {
						var type;
						if (0 === v.types.length && v.long_name === v.short_name && null !== v.long_name.match(/^\d+$/)) {
							type = 'descripting_number';
						} else {
							type = v.types[0];
						}
						
						fields[type] = v;
					});
					fields.lat = { 'short_name': data.geometry.location.lat(), 'long_name': data.geometry.location.lat() };
					fields.lng = { 'short_name': data.geometry.location.lng(), 'long_name': data.geometry.location.lng() };
					
					var $fields = $el.find('input.' + options.ns + 'field').val('');
					$.each(fields, function(k, v) {
						var $field = $fields.filter('.' + k);
						var value = $field.is('.short') ? v.short_name : v.long_name;
						$field.val(value).trigger('change');
					});
				}
			};
			if ('undefined' === typeof options) {
				options = {};
			}
			options = $.extend(defaults, options);
			
			return this.each(function(i, el) {
				var google = options.google;
				
				var $ul = $('#' + options.ns + 'results').hide();
				var $map = $('#' + options.ns + 'map').addClass('hidden');
				var $address = $('#' + options.ns + 'address');
				var $input = $('#' + options.ns + 'addressInput').attr('autocomplete', 'off');
				var $throbber = $('#' + options.ns + 'throbber').hide();
				
				var gmBounds = new google.maps.LatLngBounds().extend(new google.maps.LatLng(48.0, 7.0)).extend(new google.maps.LatLng(53.0, 22.0));
				var gmGeocoder = new google.maps.Geocoder();
				var gmMap = options.map;
				if (true === gmMap) {
					gmMap = new google.maps.Map($map.get(0), {
						'zoom': 7,
						'center': new google.maps.LatLng(50.0, 16.0),
						'mapTypeId': google.maps.MapTypeId.ROADMAP,
						'disableDefaultUI': true,
						'zoomControl': true,
						'zoomControlOptions': { 'style': google.maps.ZoomControlStyle.LARGE },
						'draggable': options.allowDragging,
						'scrollwheel': false,
						'disableDoubleClickZoom': true,
						'keyboardShortcuts': false
					});
				}
				
				$throbber.data('count', null === $throbber.data('count') ? 0 : $throbber.data('count'));
				var throbberShowhide = function() {
					if (0 < $throbber.data('count')) {
						$throbber.show();
					} else {
						$throbber.hide();
					}
				};
				var throbberAdd = function() {
					$throbber.data('count', $throbber.data('count') + 1);
					throbberShowhide();
				};
				var throbberRemove = function() {
					$throbber.data('count', $throbber.data('count') - 1);
					throbberShowhide();
				};
				
				$ul.bind('click', function(ev) {
					var $li = $(ev.target);
					if (!$li.is('li')) {
						return;
					}
					
					var data = $li.data('addressInfo');
					if (null === data) {
						return;
					}
					
					options.fillData($address.get(0), data);
					
					if (false !== options.map) {
						if (options.oneMarker) {
							$.each(options.markers, function(i, v) {
								v.setMap(null);
							});
						}
						options.markers.push(new google.maps.Marker({
							map: gmMap,
							position: data.geometry.location
						}));
						gmMap.panTo(data.geometry.location);
						gmMap.setCenter(data.geometry.location);
						gmMap.fitBounds(data.geometry.viewport);
						$map.removeClass('hidden');
					}
				});
				
				var keyCode = { 'ENTER': 13 };
				if ('undefined' !== typeof $.ui && 'undefined' !== typeof $.ui.keyCode && 'undefined' !== typeof $.ui.keyCode.ENTER) {
					keyCode = $.ui.keyCode;
				}
				
				var shown = false;
				var showHandler = function(ev) {
					shown = true;
					$ul.show();
				};
				var hideHandler = function(ev) {
					if ('mouseout' === ev.type.toLowerCase() && $input.is(':focused')) {
						return;
					}
					
					shown = false;
					setTimeout(function() {
						if (true === shown) {
							return;
						}
						
						$ul.hide();
					}, 300);
				};
				$ul.bind('focus mouseover', showHandler).bind('mouseout', hideHandler);
				$input.bind('focus mouseover', showHandler).bind('blur mouseout', hideHandler).bind('keypress', function(ev) {
					if (ev.which !== keyCode.ENTER) {
						return;
					}
					ev.preventDefault();
				});
				
				var manager = new RequestManager({
					'getData': function() {
						return $input.val();
					},
					'makeRequest': function(ev, data, time) {
						throbberAdd();
						gmGeocoder.geocode({
							'address': data,
							'language': 'cs-CZ',
							'bounds': gmBounds // doesn't have any effect
						}, function(results, status) {
							throbberRemove();
							if (google.maps.GeocoderStatus.OK !== status) {
								return;
							}
							
							if (!manager.checkTime(time)) {
								return;
							}
							
							$ul.empty();
							$.each(results, function(i, v) {
								if (-1 === $.inArray(v.types[0], [ 'street_address', 'route', 'locality' ])) {
									return;
								}
								
								if (!gmBounds.contains(v.geometry.location)) {
									return;
								}
								
								$ul.append($('<li/>').html(v.formatted_address).data('addressInfo', v));
							});
						});
					}
				});
				
				$input.bind('keyup change', function(ev) {
					manager.handle(ev);
				});
				
				if ('' !== $input.val()) {
					manager.handle(null, true);
				}
			});
		},
		'prMap': function(options) {
			var defaults = {
				'google': window.google,
				'map': true,
				'oneMarker': true,
				'markers': [],
				'query': ''
			};
			if ('undefined' === typeof options) {
				options = {};
			}
			options = $.extend(defaults, options);
			
			return this.each(function(i, el) {
				var google = options.google;
				
				var $map = $(el);
				var $info = $('<span/>').insertBefore($map);
				
				var gmBounds = new google.maps.LatLngBounds().extend(new google.maps.LatLng(48.0, 7.0)).extend(new google.maps.LatLng(53.0, 22.0));
				var gmGeocoder = new google.maps.Geocoder();
				var gmMap = options.map;
				if (true === gmMap) {
					gmMap = new google.maps.Map($map.get(0), {
						'zoom': 7,
						'center': new google.maps.LatLng(50.0, 16.0),
						'mapTypeId': google.maps.MapTypeId.ROADMAP,
						'disableDefaultUI': true,
						'zoomControl': true,
						'zoomControlOptions': { 'style': google.maps.ZoomControlStyle.LARGE },
						'draggable': options.allowDragging,
						'scrollwheel': false,
						'disableDoubleClickZoom': true,
						'keyboardShortcuts': false
					});
				}
				
				gmGeocoder.geocode({
					'address': options.query,
					'language': 'cs-CZ',
					'bounds': gmBounds // doesn't have any effect
				}, function(results, status) {
					if (google.maps.GeocoderStatus.ZERO_RESULTS === status) {
						$info.html('adresa nebyla nalezena');
						return;
					}
					if (google.maps.GeocoderStatus.OK !== status) {
						$info.html('chyba při nahrávání mapy');
						return;
					}
					
					var location;
					
					$.each(results, function(i, v) {
						if (-1 === $.inArray(v.types[0], [ 'street_address', 'route', 'locality' ])) {
							return;
						}
						
						if (!gmBounds.contains(v.geometry.location)) {
							return;
						}
						
						location = v.geometry.location;
						return false;
					});
					
					if ('undefined' === typeof location) {
						$info.html('adresa nebyla nalezena');
						return;
					}
					google.maps.event.trigger(gmMap, 'resize');
					gmMap.setCenter(location);
					if (options.oneMarker) {
						$.each(options.markers, function(i, v) {
							v.setMap(null);
						});
					}
					options.markers.push(new google.maps.Marker({
						map: gmMap,
						position: location
					}));
					$info.html('');
				});
			});
		}
	});
}(jQuery));
