Application = function(elm, options) {
	var me = this;
	
	me.elm = elm;
	me.data = options.data;
	me.templates = options.templates;
	me.l10n = options.l10n;
	me.cookies = options.cookies;
	
	me.txtQuery = elm.find('#q');
	me.btnQuery = elm.find('#q-button');
	me.feedbackBox = elm.find('.feedback-box');
	me.resultCount = elm.find('#result-count').hide();
	me.resultSet = elm.find('#result-set');
	me.panDeclinations = elm.find('#declinations');
	me.selectLocale = elm.find('#select-locale');

	//me.declinationForm = new DeclinationForm(me, me.panDeclinations);
	me.declinations = {};
	me.declinationsByCode = {};
	me.tooltipParent = null;
	
	me.init = function() {
		me.txtQuery.focus().keypress(me.onTxtQueryKeyPress);
		me.btnQuery.click(me.onQueried);
		me.data.getDeclinations(me.onDeclinationsRecevied);

		me.selectLocale.change(function(e) {
			locale = $(e.target).val();
			me.l10n.setLocale(locale, me.onLocaleSet);
			me.cookies.set('locale', locale, 365);
		});
		
		me.elm.find('.locale-search').click(function(e) {
			me.cookies.set('searchLocale', $(e.target).val(), 365);
		});
		
		var locale = me.cookies.get('locale');
		var searchLocale = me.cookies.get('searchLocale');
		
		if (locale == null) {
			locale = 'en-GB';
		}

		me.l10n.setLocale(locale, me.onLocaleSet);
		
		if (searchLocale != null) {
			me.searchLocale = elm.find('.locale-search[value="' + searchLocale  + '"]').attr('checked', 'checked');
		}
	}
	
	me.destroy = function() {
	}
	
	me.onLocaleSet = function() {
		var newTitle = me.l10n.get('dictionary-title');
		
		if (newTitle != null) {
			document.title = newTitle;
		}

		me.selectLocale.val(me.l10n.locale);
	}
	
	me.onDeclinationsRecevied = function(result) {
		for (var i = 0; i < result.length; i++) {
			var item = me.templates.get('declination-item', result[i]);
			item.attr('id', 'declination-' + result[i].code);
			
			me.declinationsByCode[result[i].code] = result[i]; 
			
			for (var j = 0; j < result[i].info.length; j++) {
				me.declinations[result[i].info[j].id] = result[i].info[j]; 
				row = me.templates.get('declination-row', result[i].info[j]);
				item.append(row);
			}

			me.panDeclinations.append(item);
		}
	}
	
	me.onTxtQueryKeyPress = function(e) {
		var key = e.keyCode ? e.keyCode : e.which;
		
		if (key == 13) {
			me.onQueried(e);
			return false;
		}
	}
	
	me.onQueried = function(e) {
		var locale = me.elm.find('.locale-search[checked]').val();
		var qtext = me.txtQuery.val();
		
		me.txtQuery.removeClass('input-error');
		me.elm.find('.error-item').hide();
		me.data.query({ query: qtext, locale: locale }, me.onQueryComplete, me.onQueryError);
		
		return false;
	}
	
	me.onQueryComplete = function(result) {
		var noMatched = me.feedbackBox.find('.query-error-empty-set');
		var queryMatches = me.feedbackBox.find('.query-matches');
		
		me.resultSet.children().remove()
		
		if (result.items.length == 0) {
			noMatched.removeClass('hidden').fadeIn(500);
			queryMatches.hide();
			return;
		} else {
			noMatched.hide();
			queryMatches.removeClass('hidden').show();
		}
		
		me.resultCount.hide(function() { me.resultCount.fadeIn(500) });
		me.resultCount.find('.val-holder').html(result.count);
		
		for (var i = 0; i < result.items.length; i++) {
			var resultItem = result.items[i];
			var tpl = me.templates.get('result-item', resultItem);
			var declinationContainer = tpl.find('.declination');
			
			declinationContainer.hide();
			
			me.resultSet.append(tpl);
			
			if (resultItem.declinationid != null && me.declinations[resultItem.declinationid] != null) {
				declEntry = me.declinations[resultItem.declinationid];
				declination = me.templates.get('declination-row', declEntry);
				declinationContainer.append(declination);
			}

			me.bindResultItem(tpl, resultItem);
			
			/*tpl.find('.editable').each(function(k, obj) {
				$obj = $(obj);
				val = $obj.text();
				
				$inp = $('<input type="text">');
				$inp.val(val);
				$obj.parent().append($inp);
				$inp.offset($obj.offset());
				$inp.width($obj.width());
				$inp.css('margin', '0px');
				$inp.css('padding', '0px');
				$inp.css('border', '0px');
				$inp.css('font-family', $obj.css('font-family'));
				$inp.css('font-weight', $obj.css('font-weight'));
				$inp.css('font-size', $obj.css('font-size'));
				$inp.blur(function(e) {
					newval = $inp.val();
					$inp.replaceWith($obj);
					$obj.html(newval);
				});
				$inp.keyup(function(e) {
					$obj.text($inp.val());
					$inp.offset($obj.offset());
					$inp.width($obj.outerWidth() + 4);
				});
				$inp.keydown(function(e) {
					$obj.text($inp.val());
					$inp.offset($obj.offset());
					$inp.width($obj.width() + 4);
				});
				$inp.keypress(function(e) {
					$obj.text($inp.val());
					$inp.offset($obj.offset());
					$inp.inneridth($obj.width() + 4);
				});
			});*/
		}
	}
	
	me.onQueryError = function(result) {
		me.txtQuery.addClass('input-error');
		
		$error = me.elm.find('.status-error-' + result.status);
		
		if ($error.length == 0) {
			$error = me.elm.find('.status-error');
		}
		
		$error.hide().removeClass('hidden').fadeIn(500);
	}
	
	me.bindResultItem = function(elm, item) {
		if (item.declinationid == null && item.code != null) {
			elm.mouseover(function(e) {
				me.onResultItemMouseOver(elm, item.code);
			});
		}
	}
	
	me.onResultItemMouseOver = function(elm, code) {
		if (me.declinationsByCode[code] == null) {
			return;
		}

		if (me.tooltipParent == elm) {
			return;
		} else if (me.tooltipParent != null){
			me.tooltipParent.find('.declination').hide().children().hide();
		}

		$declination = elm.find('.declination');
		$declination.show();
		
		me.tooltipParent = elm;
		
		if ($declination.children() > 0) {
			$declination.children().fadeIn(500);
			return;
		}
		
		declinationInfo = me.declinationsByCode[code];
		
		tooltip = me.templates.get('declination-item', declinationInfo, {
			info: function(target, values) {
				var item;
				
				for (var i = 0; i < values.length; i++) {
					item = me.templates.get('declination-row', values[i]);
					target.append(item);
				}
			}
		});
		
		tooltip.hide();

		$declination.append(tooltip);
		tooltip.fadeIn(500);
		
		/*if (elm != expl.parent()) {
			elm.append(expl);
		}*/
		
		//elm.eq(0).append('<span>ok</span>');
		//expl.fadeIn(500);
	}
	
	me.init();
}