var FormElementAddress = Class.create({
	initialize: function (id, format, numFreeLines, tabIndex, showFields)
	{
		this.id = id;
		this.format = format;
		this.numFreeLines = numFreeLines;
		this.tabIndex = tabIndex;
		this.showFields = showFields;
		this.mainElem = $(id);
		if (!this.mainElem) return false;
		this.curVals = {};
	
		this.PBAddress = new PBJSONRPCClient(PbLib.getNewURI("l/relation/rpc/address"));
	
		this.countryElem = $(id).select(".address-country").first();
		if (this.countryElem) {
			this.countryElem.observe("change", this.changeCountry.bindAsEventListener(this));
			this.countryElem.observe("pb:change", this.changeCountry.bindAsEventListener(this, true));
		}
		this.countryElemIsFocussed = false;
	},
	setCountryFocus: function ()
	{
		this.countryElemIsFocussed = true;
	},
	removeCountryFocus: function ()
	{
		this.countryElemIsFocussed = false;
	},
	cachedFormats: {},
	getFormat: function (countryCode)
	{
		if (this.cachedFormats[countryCode]) {
			return this.cachedFormats[countryCode];
		}
	
		return (this.cachedFormats[countryCode] = this.PBAddress.call("getFormat", countryCode, true));
	},
	cachedStates: {},
	getStates: function (countryCode)
	{
		if (this.cachedStates[countryCode]) {
			return this.cachedStates[countryCode];
		}
	
		return (this.cachedStates[countryCode] = this.PBAddress.call("getStates", countryCode));
	},
	changeCountry: function (event, noFocus)
	{
		var noFocus = !!(noFocus);
		var countryCode = this.countryElem.value;
		this.countryElem.stopObserving("change", this.changeCountry);
		
		// Collect current values
		this.mainElem.select('.address-field').each((function (addressField)
		{
			this.curVals[addressField.id] = $F(addressField);
		}).bind(this));
	
		// Create temporary container
		var container = new Element("div");
	
		// Get the format from the webservice
		var format = this.getFormat(countryCode);
		if (format == this.format) {
			if (format.match(/#\{state\}/i)) {
				// Just replace the states element
				var stateField = new Element("select", {"tabindex": $(this.id + "-state").getAttribute('tabindex')});
				stateField.appendChild(new Element("option"));
				$H(this.getStates(countryCode)).each(function (pair) {
					stateField.appendChild(new Element("option", {"value": pair.key})).update(pair.value);
				});
				$(this.id + "-state").parentNode.replaceChild(stateField, $(this.id + "-state"));
				stateField.id = this.id + "-state";
			}
		} else {
			this.format = format + "";
	
			var match, key, myId, label, lineKey;
			var elems = {};
			var parts = $A();
			var row = $A();
			parts.unshift(row);
			while (match = format.match(/^([\s\S]*)#\{([^\}]+)\}([\s\S]*?\n*)$/im)) {
				format = match[1];
				key = match[2].toLowerCase();
	
				if (match[3].match(/(\n)/m)) {
					delete row;
					row = $A();
					parts.unshift(row);					
				}
	
				if (key == "country_name") {
					key = "country";
				}
	
				if (elems[key] || !this.showFields[key]) {
					continue;
				}
	
				if (key == "freetext") {
					if (this.numFreeLines > 0) {
						elems[key] = true;
						var freeElem;
						for (var i = 0; i < this.numFreeLines; i++) {
							if (i > 0) {
								delete row;
								row = $A();
								parts.unshift(row);
							}
	
							freeElem = new Element("input", {"type": "text"});
							freeElem.name = "formdata[" + this.id + "][" + key + "][]";
							freeElem.addClassName("address-field address-" + key);
	
							myId = this.id + "-" + key + "-" + i;
							if (this.curVals[myId]) {
								freeElem.value = this.curVals[myId];
							}
							freeElem.id = myId;
							freeElem.writeAttribute("tabindex", this.tabIndex);
	
							row.unshift({
								'key': key,
								'id': myId,
								'elem': freeElem,
								'label': PbLib.g('Free text')
							});
							delete freeElem;
						}
					}
				} else {
					label = false;
					switch (key) {
						case "name":
							label = label || PbLib.g('Addressee'); 
						case "street":
							label = label || PbLib.g('Street');
						case "number":
							label = label || PbLib.g('Number');
						case "number_add":
							label = label || PbLib.g('Addition');
						case "postcode":
							label = label || PbLib.g('Postcode');
						case "town":
							label = label || PbLib.g('Town');
							elems[key] = new Element("input", {"type": "text"});
							break;
	
						case "state":
							label = label || PbLib.g('State');
							elems[key] = new Element("select");
							elems[key].appendChild(new Element("option"));
							$H(this.getStates(countryCode)).each(function (pair) {
								elems[key].appendChild(new Element("option", {"value": pair.key})).update(pair.value);
							});
							break;
	
						case "country":
							label = label || PbLib.g('Country');
							elems[key] = new Element("select");
							elems[key].appendChild(new Element("option"));
							$H(this.countryList).each(function (pair) {
								elems[key].appendChild(new Element("option", {"value": pair.key})).update(pair.value);
							});
							break;
					}
					elems[key].name = "formdata[" + this.id + "][" + key + "]";
					elems[key].addClassName("address-field address-" + key);
	
					myId = this.id + "-" + key;
					if (this.curVals[myId]) {
						elems[key].value = this.curVals[myId];
					}
					elems[key].id = myId;
					elems[key].writeAttribute("tabindex", this.tabIndex);
	
					row.unshift({
						'key': key,
						'id': myId,
						'elem': elems[key],
						'label': label
					});
				}
			}
			delete row;
	
			while (this.mainElem.firstChild) {
				this.mainElem.removeChild(this.mainElem.firstChild);
			}
			
			var lastKey = null;
			parts.each(function (row)
			{
				var P = this.mainElem;
				var n = row.size();
				if (n == 0) {
					return;
				} else if (n > 1) {
					P = P.appendChild(new Element('div', {'class': 'address-row'}));
				}
				row.each(function (part)
				{
					var label = P.appendChild(new Element('label', {'for': part.id}));
					if (part.key == lastKey) {
						label.addClassName('sr');
					}
					if (n != 1) {
						label.appendChild(new Element('span')).update(part.label);
						label.appendChild(document.createTextNode('\n')); // <- The newline is needed to prevent an IE 6 bug
					} else {
						label.update(part.label);
					}
					if (n == 1) {
						P.appendChild(part.elem);
					} else {
						label.appendChild(part.elem);
					}
					lastKey = part.key;
				}.bind(this));
			}.bind(this));

			this.countryElem = $(this.id + "-country");
			this.countryElem.observe("change", this.changeCountry.bindAsEventListener(this));
			this.countryElem.observe("pb:change", this.changeCountry.bindAsEventListener(this, true));
			if (!noFocus) {
				this.countryElem.focus();
			}
		}
	}
});