( function( $ ) {
	var SELECTORS = {
		TOWN_SELECT: '.town',
		DISTRICT_SELECT: '.district',
		STREET_NAME_INPUT: '.street-name',
		STREET_ID_INPUT: '.street-id'
	};

	// Binds on selected node location selector with city,
	// district and street (optional) fields.
	// Parameter options is optional, there are
	// default options (see below).
	$.fn.location = function( options ) {
		var $container = this;

		var settings = $.extend( true, {}, _defaultOptions, options );

		_fillTownList(
			settings.url, settings.region.selected,
			$container.find( SELECTORS.TOWN_SELECT ),
			settings
		);

		if( $container.attr( 'locationSelectorBinded' ) ) {
			_fillDefaultValues( $container, settings );
			return;
		}

		$container.attr( 'locationSelectorBinded', true );
		
		if( $container.find( SELECTORS.DISTRICT_SELECT ).length > 0 ) {
			$container.find( SELECTORS.DISTRICT_SELECT )[ 0 ].firstShow = true;
		}

		var $hiddenStreetName = null;
		if( $container.find( SELECTORS.STREET_NAME_INPUT ).length > 0 ) {
			$hiddenStreetName = $container.find( SELECTORS.STREET_NAME_INPUT ).clone();
			$hiddenStreetName.appendTo( $container );
			$hiddenStreetName.removeAttr( 'class' );
			$hiddenStreetName.hide();
			$hiddenStreetName.attr(
				'name',
				$container.find( SELECTORS.STREET_NAME_INPUT ).attr( 'name' )
			);
			$container.find( SELECTORS.STREET_NAME_INPUT ).attr( 'name', '' );
		}

		$container.find( SELECTORS.TOWN_SELECT ).change( function() {
			var $townSelect = $( this );

			if( $townSelect.val() != settings.town.selected ) {
				$container.find( SELECTORS.STREET_NAME_INPUT ).val( '' );
				$container.find( SELECTORS.STREET_NAME_ID ).val( '' );
			}

			if( $townSelect.val() != '' ) {
				$container.find( SELECTORS.STREET_NAME_INPUT )
					.attr( 'disabled', false )
					.attr( 'title', settings.street.title )
					.blur();

				$container.find( SELECTORS.DISTRICT_SELECT )
					.attr( 'disabled', false )

				$container.find( SELECTORS.STREET_ID_INPUT )
					.attr( 'disabled', false );

				if( $container.find( SELECTORS.DISTRICT_SELECT ).length > 0 ) {
					_fillDistrictsList(
						settings.url,
						$townSelect.val(),
						$container.find( SELECTORS.DISTRICT_SELECT ),
						settings
					);
				}
			} else {
				$container.find( SELECTORS.DISTRICT_SELECT )
					.attr( 'disabled', true )
					.hide();

				$container.find( SELECTORS.STREET_ID_INPUT )
					.attr( 'disabled', true );

				$container.find( SELECTORS.STREET_NAME_INPUT )
					.attr( 'disabled', true )
					.attr( 'title', settings.street.disabledTitle )
					.attr( 'value', settings.street.disabledTitle );

				if( $container.find( SELECTORS.DISTRICT_SELECT ).length > 0 ) {
					settings.district.changed( '', $container.find( SELECTORS.DISTRICT_SELECT ) )
				}
			}
		} );


		$container.find( SELECTORS.STREET_NAME_INPUT ).autocomplete(
			settings.url, {
				extraParams: {
					region_id: function() {
						return settings.region.selected;
					}, town_id: function() {
						return $container.find( SELECTORS.TOWN_SELECT ).val();
					}
				},
				scroll: false,
				cacheLength: 0
			}
		);

		$container.find( SELECTORS.STREET_NAME_INPUT ).result( function( _, data ) {
			this.autocompleteState = 0;
			$container.find( SELECTORS.STREET_ID_INPUT ).val( data[ 1 ] );
			$( this ).parents( 'form' ).next( 'input[type!=hidden]' ).focus();
		} );

		$container.find( SELECTORS.STREET_NAME_INPUT ).focus(
			function() {
				this.autocompleteState = -1;
				if( $( this ).hasClass( settings.street.defaultClass ) ) {
					$( this ).val( '' );
					$( this ).removeClass( settings.street.defaultClass );
				}
			}
		);

		$container.find( SELECTORS.STREET_NAME_INPUT ).blur(
			function() {
				if( this.autocompleteState == -1 ) {
					$container.find( SELECTORS.STREET_ID_INPUT ).val( '' );
				}

				if(
					$( this ).val() == '' ||
					$( this ).val() == settings.street.disabledTitle ||
					$( this ).val() == settings.street.title
				) {
					$( this ).val( settings.street.title );
					$( this ).addClass( settings.street.defaultClass );

					$container.find( SELECTORS.STREET_ID_INPUT ).val( '' );
					$hiddenStreetName.val( '' );
				} else {
					if( $hiddenStreetName !== null ) {
						$hiddenStreetName.val(
							$container.find( SELECTORS.STREET_NAME_INPUT ).val()
						);
						$( this ).removeClass( settings.street.defaultClass );
					}
				}
			}
		);

		_fillDefaultValues( $container, settings );
	}


	var _ajaxCache = {};


	var _fillDefaultValues = function( $container, settings ) {
		$container
			.find( SELECTORS.TOWN_SELECT )
			.val( settings.town.selected );

		$container
			.find( SELECTORS.STREET_NAME_INPUT )
			.val( settings.street.selected.name )
			.blur();
			/*
			.change()
			.blur();*/

		$container
			.find( SELECTORS.STREET_ID_INPUT )
			.val( settings.street.selected.id )
			.change();

	}


	var _loadListContents = function(
		url, getParams, $listContainer, selected, options
	) {
		var processAjaxResponse = function( data ) {

			$listContainer.html( '' );
			
			if(
				data == "" ||
				$listContainer.attr( 'tagName' ).toLowerCase() == 'input'
			) {
				$listContainer.hide();
				$listContainer.change();
				options.changed( data, $listContainer );
				return;
			}

			$listContainer.show();

			if( options.defaultName != '' ) {
				$listContainer.html( options.template(
					selected, '', options.defaultName
				) );
			}

			var rowsList = [];
			$.each( data.split( "\n" ), function( _, row ) {
				$listContainer.append( options.template(
					selected,
					row.split( "|" )[ 1 ], row.split( "|" )[ 0 ]
				) );
			} );

			$listContainer.change();
			options.changed( data, $listContainer );
		}
		
		var key = url + '?' + $.param( getParams ) + '&rand=' + Math.random();
		
		if( _ajaxCache[ key ] == undefined ) {
			$.get(
				url,
				getParams,
				function( data ) {
					processAjaxResponse( data );
					_ajaxCache[ key ] = data;
				}
			);
		} else {
			processAjaxResponse( _ajaxCache[ key ] );
		}
	}


	var _fillTownList = function(
		url, regionId, $listContainer, globalOptions
	) {
		_loadListContents(
			url,
			{ region_id: regionId },
			$listContainer,
			globalOptions.town.selected,
			globalOptions.town
		);
	}


	var _fillDistrictsList = function(
		url, townId, $listContainer, globalOptions
	) {
		
		_loadListContents(
			url,
			{ town_id: townId },
			$listContainer,
			$listContainer[ 0 ].firstShow ? globalOptions.district.selected : '',
			globalOptions.district
		);

		$listContainer[ 0 ].firstShow = false;
	}


	var _defaultOptions = {
		url: '/ajax/location.php',
		region: {
			selected: 1
		},
		town: {
			selected: '',
			defaultName: 'Все города',
			changed: function() {},
			template: function( selected, id, name ) {
				if( id == selected ) {
					return '<option selected value="' + id + '">' + name + '</option>';
				} else {
					return '<option value="' + id + '">' + name + '</option>';
				}
			}
		},
		district: {
			selected: '',
			changed: function() {},
			defaultName: 'Все районы',
			template: function( selected, id, name ) {
				if( id == selected ) {
					return '<option selected value="' + id + '">' + name + '</option>';
				} else {
					return '<option value="' + id + '">' + name + '</option>';
				}
			}
		},
		street: {
			title: 'Введите улицу',
			changed: function() {},
			disabledTitle: 'Выберите город',
			defaultClass: 'enter-street',
			selected: {
				id: 0,
				name: ''
			}
		}
	};
} )( jQuery );
