ZipCityHint = function(config) {
	$.extend(this, config);
	$(document).ready(this.init.createDelegate(this));
}

ZipCityHint.prototype = {
	zipEl: "#MailingPostalCode"
	, cityEl: "#MailingCity"
	, url: "/zipCityHint?zip={0}&city={1}&focus={2}"
	, loadingHintText: "Loading..."
	, emptyHintText: "No results"
	, init: function() {
		if (!$(this.zipEl)[0]) return;
		var that = this;
		this.zipPopup = new PopupInput(
		{
			inputEl: this.zipEl
			, loadingText: this.loadingHintText
			, emptyText: this.emptyHintText
			, onTime: function(text) { this.showLoading(); that.update("zip"); }
			, onSelect: function(text) { that.update("zipExact"); }
		});
		this.cityPopup = new PopupInput(
		{
			inputEl: this.cityEl
			, loadingText: this.loadingHintText
			, emptyText: this.emptyHintText
			, onTime: function(text) { this.showLoading(); that.update("city"); }
			, onSelect: function(text) { that.update("cityExact"); }
		});
		if (this.zipPopup.getValue())
			this.update("zip");
	}
	, update: function(focus) {
		var zip = this.zipPopup.getValue();
		var city = this.cityPopup.getValue();
		var url = this.url.format(zip, encodeURIComponent(city), focus);
		$.getJSON(url, function(data) {
			if (data.focus == "zip")
				$(this.zipPopup.inputEl).focus();
			else
				$(this.cityPopup.inputEl).focus();
			if (data.validated)
				this.zipPopup.validatedValue = data.zip;
			if (data.zip)
				this.zipPopup.setValue(data.zip);
			if (data.city)
				this.cityPopup.setValue(data.city);
			if (data.zipList)
				this.zipPopup.showPopup(data.zipList);
			else if (data.cityList)
				this.cityPopup.showPopup(data.cityList);
		} .createDelegate(this));
	}
	, validate: function() {
		// NB: check only ZIP validity, empty field validation is done in vconfig.js
		var zip = this.zipPopup.getValue();
		if (zip && zip != this.zipPopup.validatedValue) {
			return false;
		}
		return true;
	}
}

PopupInput = function(sett) {
	$.extend(this, sett);
	$(document).ready(this.init.createDelegate(this));
}

PopupInput.prototype = {
	inputEl: null
	, height: 200
	, interval: 500
	, minLength: 3
	, loadingText: "Loading..."
	, emptyText: "No results"
	, init: function() {
		if (!$(this.inputEl)[0]) return;
		$(document).click(function(e) {
			this.hideContainer();
		} .createDelegate(this));
		$(this.inputEl).keydown(this.inputDown.createDelegate(this));
		$(this.inputEl).keyup(this.inputUp.createDelegate(this));
		$(this.inputEl).keypress(this.inputPress.createDelegate(this));
		$(this.inputEl).blur(this.inputBlur.createDelegate(this));
		$(this.inputEl).focus(this.inputFocus.createDelegate(this));
	}
	, getInput: function() { return $(this.inputEl); }
	, getPopup: function() { this.createContainer(); return $("#" + this.popupId); }
	, getPopupBody: function() { this.createContainer(); return $("#" + this.popupId + " .rel"); }
	, getValue: function() { return $(this.inputEl).val(); }
	, setValue: function(v) { return $(this.inputEl).val(v); }
	, validatedValue: null
	, timer: null
	, onSelect: null
	, jsonReader: function(data) { return data; }
	, inputBlur: function(e) { }
	, inputFocus: function(e) { $(".popupinput").hide(); }
	, inputPress: function(e) {
		var key = (e.which) ? e.which : e.keyCode;
		if (key == 13) {
			e.preventDefault();
			return false;
		}
	}
	, inputDown: function(e) {
		var key = (e.which) ? e.which : e.keyCode;
		if (key == 13) {
			e.preventDefault();
			return false;
		}
	}
	, inputUp: function(e) {
		clearTimeout(this.timer);
		e.preventDefault();

		if (this.validatedValue == this.getValue()) return;

		if (this.keyup(e)) return false;

		if (this.getValue().length < this.minLength) {
			if (!this.items) this.hideContainer();
			return;
		}

		this.timer = setTimeout(this.timeoutEnd.createDelegate(this), this.interval);
	}

	, showLoading: function() {
		this.getPopupBody().html('<div style="clear:left;background:gray;color:white;display:block;padding:3px;">' + this.loadingText + '</div>');
		this.getPopup().css({ height: "auto" }).show();
		this.activeIndex = -1;
		this.items = null;
		this.posContainer();
	}
	, timeoutEnd: function() { this.onTime(this.getValue()); }
	, renderNode: function(item) { return item; }
	, getWidth: function() { return this.getInput().outerWidth() - 2; }
	, htmlNode: function(item) {
		return '<div style="clear:left;display:block;padding:3px;width:' + (this.getWidth() - 6) + 'px;cursor:pointer;">' + this.renderNode(item) + '</div>'; //height:'+(this.nodeHeight+6)+'px;
	}
	, showPopup: function(items, notSetOne) {
		$(".popupinput").hide();
		this.validatedValue = null;
		this.activeIndex = -1;
		this.renderNodes(items);
		this.getPopup().slideDown("slow");
	}
	, showContainer: function() {
		this.getPopup().slideDown("slow");
	}
	, hideByBody: function(ev) {
		if ($(ev.target).parents("#" + this.popupId).size() || ev.target == this.getInput()[0]) return;
		this.hideContainer();
	}
	, hideContainer: function() {
		this.getPopup().slideUp();
	}
	, selectNode: function(ev) {
		this.setValue($(ev.currentTarget).html());
		if (this.onSelect) this.onSelect(this.getValue());
		this.hideContainer();
	}
	, mouseOverNode: function(ev) { $(ev.currentTarget).css({ "background-color": "#F0F0F0" }); }
	, mouseOutNode: function(ev) { $(ev.currentTarget).css({ background: "" }); }
	, activeIndex: -1
	, keyup: function(e) {
		e.preventDefault();
		if (!this.items) return false;

		var key = (e.which) ? e.which : e.keyCode;

		if (!this.getPopup().is(":visible") && key != 27) return false;

		switch (key) {
			case 40: //down
				if (this.items.length - 1 > this.activeIndex) this.activeIndex++;
				//d(this.items.length)
				break;
			case 38: //up
				if (this.activeIndex > 0) this.activeIndex--;
				break;
			case 13: //enter
				this.selectNode({ currentTarget: this.getPopup().find("div.item")[this.activeIndex] });
				return true;
				break;
			case 27: //esc
			case 9: //tab
				clearTimeout(this.timer);
				this.hideContainer();
				return true;
				break;
			default:
				return false;
		}

		if (this.activeIndex > -1) {
			var items = this.getPopupBody().find("> div.item");
			items.css({ background: "" });
			$(items[this.activeIndex]).css({ "background-color": "#F0F0F0" });

			var top = $(items[this.activeIndex]).position()["top"]; //  - this.getPopup().position()["top"];
			this.getPopup()[0].scrollTop = top;
			return true;
		}
		return false;
	}
	, renderNodes: function(items) {
		this.getPopupBody().html("");
		this.items = items;

		if (!this.items || !this.items.length) {
			this.getPopupBody().css({ height: "auto" }).html('<div style="clear:left;background:gray;color:white;display:block;padding:3px;">' + this.emptyText + '</div>').show();
			return;
		}
		var html = "";
		$.each(items, function(i, v) {
			var e = $(this.htmlNode(v));

			e.click(this.selectNode.createDelegate(this));
			e.mouseover(this.mouseOverNode.createDelegate(this));
			e.mouseout(this.mouseOutNode.createDelegate(this));

			this.getPopupBody().append(e);

		} .createDelegate(this));
		this.getPopup().css({ height: "auto" });
		this.posContainer();
	}
	, posContainer: function() {
		var pos = this.getInput().offset();
		var height = this.getInput().outerHeight();
		var width = this.getInput().outerWidth();
		this.getPopup().css({ top: pos.top + height, left: pos.left });
	}
	, createContainer: function() {
		if (this.popupId) return;
		var pos = this.getInput().offset();
		var height = this.getInput().outerHeight();
		var width = this.getWidth();

		var id = "popup" + this.inputEl.replace('#','');
		this.popupId = id;

		$(document).click(this.hideByBody.createDelegate(this));
		$("body").append(
			$.format(
				'<div id="{3}" class="popupinput" style="display:none;position:absolute;top:{0}px;left:{1}px;width:{2}px;border:1px solid #B8B8B8;overflow:auto;background:white;">\
				<div class="rel" style="position:relative;"></div></div>'
					, pos.top + height
					, pos.left
					, width
					, id
					));
	}
};
	
	
try { d = (console ? console.debug : function(v){
	$(document.body).append(v+"<br>");
	}); } catch(e) {}
	
rand = function() {return Math.floor(Math.random()*11);}

Function.prototype.createDelegate = function(scope) {
    var fn = this;
    return function() {
        return fn.apply(scope, arguments);
    }
}

jQuery.format = function jQuery_dotnet_string_format(text) {
  if (arguments.length <= 1) {
    return text;
  }
  var tokenCount = arguments.length - 2;
  for (var token = 0; token <= tokenCount; ++token) {    
    text = text.replace(new RegExp("\\{" + token + "\\}", "gi"), arguments[token + 1]);
  }
  return text;
};

timestamp = function() {return Math.round(((new Date()).getTime()-Date.UTC(1970,0,1))/1000);}

String.prototype.format = function() {
	var pattern = /\{\d+\}/g;
	var args = arguments;
	return this.replace(pattern, function(capture) { return args[capture.match(/\d+/)]; }); 
}	

