// UTF-8 Teststräng: åäöÅÄÖ

var PageHelper = {}

// * CurrentTableRow *********************************************************************
// ***************************************************************************************

var CurrentTableRowBase = Class.create();
CurrentTableRowBase.prototype = {
	initialize : function(table, options) {
		table = $(table);
		if(table.tagName !== "TABLE") {
			return;
		}
		CurrentTableRowBase.register(table, Object.extend(CurrentTableRowBase.options, options || {}));
		this.id = table.id;
	}
};

Object.extend(CurrentTableRowBase, {
	e : function(event) {
		return event || window.event;
	},
	register : function(table, options) {
		if(!table.id) {
			CurrentTableRowBase.tablecount += 1;
			table.id = "currenttablerow-table-" + CurrentTableRowBase.tablecount;
		}
		var id = table.id;
		CurrentTableRowBase.tables[id] = CurrentTableRowBase.tables[id] ? Object.extend(CurrentTableRowBase.tables[id], options || {}) : Object.extend({}, options || {});
	},
	getcurrentinput : function(table) {
		if (CurrentTableRowBase.tables[table.id]) {
			return CurrentTableRowBase.tables[table.id].currentinput;
		}
	},
	setcurrentinput : function(table, input) {
		if (CurrentTableRowBase.tables[table.id]) {
			CurrentTableRowBase.tables[table.id].currentinput = input;
		}
	},
	options : {
	},	
	tablecount : 0,
	tables : {}
});

PageHelper.CurrentTableRow = {
	checkWithinTable: function(table, element) {
		var parent_element = element;
		while ((parent_element.tagName.toLowerCase() != 'form') && (parent_element.tagName.toLowerCase() != 'body')) {
			if (parent_element.tagName.toLowerCase() == 'table' && parent_element.id == table.id) {
				return true;
			} else {
				parent_element = parent_element.parentNode;
			}
    }		
		return false;
	},
	init : function(table, options) {
		table = $(table);
		if(table.tagName !== "TABLE") {
			return;
		}
		CurrentTableRowBase.register(table, Object.extend(options || {}, {currentinput: null}));

		table.getElementsBySelector('input').each(function(i) {
			i = $(i);
			if(i.type != "hidden" && i.type != "button") {
				Event.observe(i, 'focus', PageHelper.CurrentTableRow.onFocus);
			}
		});
	},
	initWithForm : function(table, form, options) {
		table = $(table);
		if(table.tagName !== "TABLE") {
			return;
		}
		CurrentTableRowBase.register(table, Object.extend(options || {}, {currentinput: null}));
	
		var form_elements = $A(form.elements);
		form_elements.each(function(s) {
			if (s.tagName.toLowerCase() == "input") {
				if(s.type != "hidden" && s.type != "button") {
					if (PageHelper.CurrentTableRow.checkWithinTable(table, s)) {
						Event.observe(s, 'focus', PageHelper.CurrentTableRow.onFocus);
					}
				}
			}
		});
	},
	currentrow : function(table) {
		table = $(table);
		if(table.tagName !== "TABLE") {
			return;
		}
		var row = 0;
		var input = CurrentTableRowBase.getcurrentinput(table);
		if (input) {
			var inputrow = input.up('tr');
			row = $A(inputrow.parentNode.rows).indexOf(inputrow);
		}
		return row;
	},
	onFocus : function(e) {
		e = CurrentTableRowBase.e(e);
		Event.stop(e);
		var input = Event.element(e);
		var table = input.up('table');
		CurrentTableRowBase.setcurrentinput(table, input);
	}
};

// * NextFocus *****************************************************************************
// ***************************************************************************************
var NextFocusBase = Class.create();
Object.extend(NextFocusBase, {
	form: null,
	focusable_elements: {},
	e : function(event) {
		return event || window.event;
	},
	checkHidden: function(element) {
		var parent_element = element;
		while ((parent_element.tagName.toLowerCase() != 'form') && (parent_element.tagName.toLowerCase() != 'body')) {
			if (parent_element.style != null && parent_element.style.display != null) {
				if (parent_element.style.display != 'none') {
					parent_element = parent_element.parentNode;
				} else {
					return false;
				}
			}
    }		
		return true;
	},
	init: function(form, next_focus_on_enter) {
		this.form = $(form);
		this.focusable_elements = $A(this.form.elements);
		if (typeof next_focus_on_enter == "undefined") {
			next_focus_on_enter = false;
		}
		if (next_focus_on_enter) {
			this.focusable_elements.each(function(s) {
				s = $(s);
				if (s.tagName.toLowerCase() == "input") {
					if(!s.hasClassName('nonextfocus') && s.type != "hidden" && s.type != "button") {
						Event.observe(s, 'keypress', PageHelper.NextFocus.onKeypress);
					}
				} else if (s.tagName.toLowerCase() == "select") {
					Event.observe(s, 'keypress', PageHelper.NextFocus.onKeypress);
				}
			});
		}
	},
	next : function(selected_element) {
		var size = this.focusable_elements.size();
		var foundindex = this.focusable_elements.indexOf(selected_element);
		
		if ( foundindex >= 0) {
			if (foundindex < (size - 1)) {
				var i = foundindex + 1;
				var found = false;
				while (!found && i < size) {
					var el = this.focusable_elements[i];
					if (el.tagName.toLowerCase() == "input") {
						if (!el.readOnly && !el.disabled && el.tabIndex != -1 && el.type != "hidden" && !el.hasClassName('skipnextfocus')) {
							if (this.checkHidden(el)) {
								found = true;
								el.activate();
							}
						}
					} else if (el.tagName.toLowerCase() == "select") {
						if (el.tabIndex != -1) {
							if (this.checkHidden(el)) {
								found = true;
								el.focus();
							}
						}
					}
					i++;
				}
			}
		}
	},
	previous : function(selected_element) {
		var foundindex = this.focusable_elements.indexOf(selected_element);
		
		if ( foundindex > 0) {
			var i = foundindex - 1;
			var found = false;
			while (!found && i > 0) {
				var el = this.focusable_elements[i];
				if (el.tagName.toLowerCase() == "input") {
					if (!el.readOnly && !el.disabled && el.tabIndex != -1 && el.type != "hidden" && !el.hasClassName('skipnextfocus')) {
						if (this.checkHidden(el)) {
							found = true;
							el.activate();
						}
					}
				} else if (el.tagName.toLowerCase() == "select") {
					if (el.tabIndex != -1) {
						if (this.checkHidden(el)) {
							found = true;
							el.focus();
						}
					}
				}
				i--;
			}
		}	
	}
});

PageHelper.NextFocus = {
	init : function(form, next_focus_on_enter) {
		NextFocusBase.init(form, next_focus_on_enter);
	},
	next : function(selected_element) {
		NextFocusBase.next(selected_element);
	},
	previous : function(selected_element) {
		NextFocusBase.previous(selected_element);
	},
	onKeypress: function(e) {
		e = NextFocusBase.e(e);
		var input = Event.element(e);
		
		switch(e.keyCode) {
			case Event.KEY_RETURN:
				if (e.shiftKey) {
					NextFocusBase.previous(input);
				} else {
					NextFocusBase.next(input);
				}
				Event.stop(e);
				break;
		}
	}
};

// * Converter *****************************************************************************
// ***************************************************************************************

PageHelper.Converter  =  {
	FloatToFixedString: function (in_value) {
		return (in_value.toFixed(2).toString().replace('.', ','));
	},
	FloatToFixedThousandString: function (n) {
		var prefix = '';
		if (n < 0) {
			prefix = '-';
		}
		var c = 2;
		var d = ',';
		var t = ' ';
		var m = ( c = Math.abs( c ) + 1 ? c : 2, d = d || ",", t = t || ".", /(\d+)(?:(\.\d+)|)/.exec( n + "" ) ), x = m[1].length % 3;
		if (m[2] == null) {
			m[2] = 0;
		}
		var out_value = ( x ? m[1].substr( 0, x ) + t : "" ) + m[1].substr( x ).replace( /(\d{3})(?=\d)/g, "$1" + t ) + ( c ? d + ( +m[2] ).toFixed( c ).substr( 2 ) : "" );
		return (prefix + out_value.replace(' ,', ','));
	},
	FloatToFixedThousandString: function (n, t_val) {
		var prefix = '';
		if (n < 0) {
			prefix = '-';
		}
		var c = 2;
		var d = ',';
		var t = t_val;
		var m = ( c = Math.abs( c ) + 1 ? c : 2, d = d || ",", t = t || ".", /(\d+)(?:(\.\d+)|)/.exec( n + "" ) ), x = m[1].length % 3;
		if (m[2] == null) {
			m[2] = 0;
		}
		var out_value = ( x ? m[1].substr( 0, x ) + t : "" ) + m[1].substr( x ).replace( /(\d{3})(?=\d)/g, "$1" + t ) + ( c ? d + ( +m[2] ).toFixed( c ).substr( 2 ) : "" );
		return (prefix + out_value.replace(' ,', ','));
	},
	FloatToString: function (in_value) {
		return (in_value.toString().replace('.', ','));
	},
	StringToFloat: function (in_string) {
		var val = 0.0;
		if (in_string) {
			in_string = in_string.replace(',', '.').replace(':', '.').replace(' ', '');
			if(!(val = parseFloat(in_string))) {
				val = 0.0;
			}
		}
		return val;
	},
	StringToMoney: function (in_string) {
		in_string = in_string+'';
		if(in_string) {
			in_string = in_string+'';
			in_string = in_string.replace(',', '.');

			while(in_string != in_string.replace(' ', '')) {
				in_string = in_string.replace(' ', '');
			}
			in_string = parseFloat(in_string);
			in_string = (Math.round(in_string*1000)/1000);
			in_string = (Math.round(in_string*100)/100);
			in_string = in_string+'';
			in_string = in_string.replace('.', ',');
			a = in_string.split(',');

			var alength = a[0].length;
			var newa0 = '';

			var i = 0;
			for(i=alength;i>0;i-=3) {
				newa0 = ' '+a[0].substring(i-3, i)+newa0;
			}
			a[0] = newa0.substr(1);

			if(!a[1])
				a[1] = '00';
			else if(a[1].length == 1)
				a[1] += '0';

			//090128 Extra replace(' ', '') för stora belopp
			if(isNaN(a[0].replace(' ', '').replace(' ', '')) || isNaN(a[1].replace(' ', '').replace(' ', ''))) {
				return '';
			}

			return a[0]+','+a[1];
		} else
			return '';
	}
}

// * fillFormData *****************************************************************************
// ***************************************************************************************

PageHelper.fillFormData = function(formdata) {
	formdata.each(function(pair) {
		var element = $(pair.key);
		if (element) {
			if (element.tagName.toLowerCase() == "input") {
				element.value = pair.value;
			} else if (element.tagName.toLowerCase() == "select") {
				// TODO
			}
		}
	}); 
}

// * isArray *****************************************************************************
// ***************************************************************************************

PageHelper.isArray = function(obj) {
	return (obj instanceof Array);
}

// * inputMoveToEnd **********************************************************************
// ***************************************************************************************
PageHelper.inputMoveToEnd = function(element) {
	if (element.setSelectionRange) {
		var length = element.value.length;
		element.setSelectionRange(length, length);
	} else if (element.createTextRange) {
     var range = element.createTextRange();
     range.move("textedit");
     range.select();
	}
};

// * stringToDate*************************************************************************
// ***************************************************************************************
PageHelper.stringToDate = function(in_string) {
	var DATE_FIELD_DELIMITER = '-';
	var YEAR_POSITION = 0;
	var MONTH_POSITION = 1;
	var DAY_POSITION = 2;
	
	var out_date = null;
	var dTemp = null;
	if (typeof(in_string) == "string") {
		//Kontrollerar om det finns - i datumet
		if (in_string.indexOf(DATE_FIELD_DELIMITER) == "-1") {
			if (in_string == "Musens birthday") {
				in_string = "1974-07-12"; 
			} else if (in_string == "Angels birthday") {
				in_string = "1975-10-26";
			} else if (in_string.length == 8) {
				in_string = in_string.substring(0,4) + "-" + in_string.substring(4,6) + '-' + in_string.substring(6,8);
			} else if (in_string.length == 6) {
				var temp_year = in_string.substring(0,2);
				if (parseInt(temp_year, 10) < (new Date().getFullYear()-1979)) {
					temp_year = "20" ;
				} else {
					temp_year = "19" ;
				}
				
				in_string = temp_year + in_string.substring(0,2) + "-" + in_string.substring(2,4) + '-' + in_string.substring(4,6);
			}
		}
		var adate = in_string.split(DATE_FIELD_DELIMITER);
		if (adate.length == 3) {
			var year = parseInt(adate[YEAR_POSITION], 10);
			var month = parseInt(adate[MONTH_POSITION], 10);
			var day = parseInt(adate[DAY_POSITION], 10);
			
			if (month > 0 && month < 13) {
				if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
					if (day > 0 && day < 32) {
						out_date = new Date(year, month - 1, day);			
					} else {
						out_date = new Date();
					}
				} else if (month == 4 || month == 6 || month == 9 || month == 11) {
					if (day > 0 && day < 31) {
						out_date = new Date(year, month - 1, day);			
					} else {
						out_date = new Date();
					}
				} else {
					if (day > 0 && day < 30) {
						out_date = new Date(year, month - 1, day);			
					} else {
						out_date = new Date();
					}
				}
			} else {
				out_date = new Date();
			}
			
		} else {
			out_date = new Date();
		}
	}
	return out_date;
}

// * validDateString *********************************************************************
// ***************************************************************************************
PageHelper.validDateString = function(in_string) {
	var DATE_FIELD_DELIMITER = '-';
	var YEAR_POSITION = 0;
	var MONTH_POSITION = 1;
	var DAY_POSITION = 2;
	
	var out_date = null;
	var dTemp = null;
	if (typeof(in_string) == "string") {
		//Kontrollerar om det finns - i datumet
		if (in_string.indexOf(DATE_FIELD_DELIMITER) == "-1") {
			if (in_string == "Musens birthday") {
				in_string = "1974-07-12"; 
			} else if (in_string == "Angels birthday") {
				in_string = "1975-10-26";
			} else if (in_string.length == 8) {
				in_string = in_string.substring(0,4) + "-" + in_string.substring(4,6) + '-' + in_string.substring(6,8);
			} else if (in_string.length == 6) {
				var temp_year = in_string.substring(0,2);
				if (parseInt(temp_year, 10) < (new Date().getFullYear()-1979)) {
					temp_year = "20" ;
				} else {
					temp_year = "19" ;
				}
				
				in_string = temp_year + in_string.substring(0,2) + "-" + in_string.substring(2,4) + '-' + in_string.substring(4,6);
			}
		}
		var adate = in_string.split(DATE_FIELD_DELIMITER);
		if (adate.length == 3) {
			var year = parseInt(adate[YEAR_POSITION], 10);
			var month = parseInt(adate[MONTH_POSITION], 10);
			var day = parseInt(adate[DAY_POSITION], 10);
			
			if (month > 0 && month < 13) {
				if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
					if (day > 0 && day < 32) {
						out_date = new Date(year, month - 1, day);			
					} else {
						return false;
					}
				} else if (month == 4 || month == 6 || month == 9 || month == 11) {
					if (day > 0 && day < 31) {
						out_date = new Date(year, month - 1, day);			
					} else {
						return false;
					}
				} else {
					if (day > 0 && day < 30) {
						out_date = new Date(year, month - 1, day);			
					} else {
						return false;
					}
				}
			} else {
				return false;
			}
			
		} else {
			return false;
		}
	}
	return true;
}

// * TimeDiff *****************************************************************************
// ***************************************************************************************

PageHelper.TimeDiff  =  {
	StartTimer: function (){
		d = new Date();
		time  = d.getTime();
	},
	GetTime: function (){
		d = new Date();
		return (d.getTime()-time);
	}
}

// * Countries *****************************************************************************
// ***************************************************************************************
PageHelper.Countries = {
	GetCountriesInsideEU: function() {
		//Lista över EU-medlemmar	
		var EUcc = new Array();
		EUcc['BE'] = 'Belgium';
		EUcc['BG'] = 'Bulgaria';
		EUcc['CY'] = 'Cyprus';
		EUcc['DK'] = 'Denmark';
		EUcc['EE'] = 'Estonia';
		EUcc['FI'] = 'Finland';
		EUcc['FR'] = 'France';
		EUcc['GR'] = 'Greece';
		EUcc['IE'] = 'Ireland';
		EUcc['IT'] = 'Italy';
		EUcc['LV'] = 'Latvia';
		EUcc['LT'] = 'Lithuania';
		EUcc['LU'] = 'Luxembourg';
		EUcc['MT'] = 'Malta';
		EUcc['NL'] = 'Netherlands';
		EUcc['PL'] = 'Poland';
		EUcc['PT'] = 'Portugal';
		EUcc['RO'] = 'Romania';
		EUcc['SK'] = 'Slovakia';
		EUcc['SI'] = 'Slovenia';
		EUcc['ES'] = 'Spain';
		EUcc['GB'] = 'United Kingdom';
		EUcc['CZ'] = 'Czech Republic';
		EUcc['DE'] = 'Germany';
		EUcc['HU'] = 'Hungary';
		EUcc['AT'] = 'Austria';
		EUcc['SE'] = 'Sverige';
		return EUcc;
	},
	
	GetCountriesOutsideEU: function() {
		//Lista över några icke EU-medlemmar
		var NOTEUcc = new Array();
		NOTEUcc['US'] = 'United States';
		NOTEUcc['AX'] = 'Åland';
		NOTEUcc['AR'] = 'Argentina';
		NOTEUcc['AU'] = 'Australia';
		NOTEUcc['BA'] = 'Bosnia and Herzegovina';
		NOTEUcc['BR'] = 'Brazil';
		NOTEUcc['CA'] = 'Canada';
		NOTEUcc['CH'] = 'Switzerland';
		NOTEUcc['CN'] = 'China';
		NOTEUcc['GI'] = 'Gibraltar';
		NOTEUcc['GL'] = 'Greenland';
		NOTEUcc['HK'] = 'Hong Kong';
		NOTEUcc['HR'] = 'Croatia';
		NOTEUcc['IS'] = 'Iceland';
		NOTEUcc['JP'] = 'Japan';
		NOTEUcc['LI'] = 'Lichtenstein';
		NOTEUcc['MC'] = 'Monaco';
		NOTEUcc['MD'] = 'Moldova';
		NOTEUcc['NO'] = 'Norway';
		NOTEUcc['NZ'] = 'New Zealand';
		NOTEUcc['RS'] = 'Serbia';
		NOTEUcc['RU'] = 'Russia';
		NOTEUcc['TH'] = 'Thailand';
		NOTEUcc['TR'] = 'Turkey';
		NOTEUcc['TW'] = 'Taiwan';
		NOTEUcc['UA'] = 'Ukraine';
		return NOTEUcc;
	},
	
	GetCountryCodes: function() {
		//Lista över alla landskoder
		return Array("  ","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR","AS","AT","AU","AW","AX","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ",
									 "BM","BN","BO","BW","BV","BR","BS","BT","BY","BZ","CA","CC","CD","CG","CF","CH","CI","CK","CL","CM","CN","CO","CR","CS","CU","CV","CX",
							 		 "CY","CZ","DE","DJ","DK","DM","DO","DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","GA","GB","GD","GE","GF","GH",
									 "GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IN","IO","IQ","IR","IS","IT",
									 "JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC",
									 "MD","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO",
									 "NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA","RE","RO","RU","RW","SA","SB","SC",
									 "SE","SG","SH","SI","SK","SL","SM","SN","SO","ST","SD","SR","SJ","SV","SZ","SY","TC","TD","TF","TG","TH","TJ","TK","TL","TM","TN","TO",
									 "TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","ZA","ZM","ZW");
	}
	
}

// * ObjTree *****************************************************************************
// ***************************************************************************************

PageHelper.ObjTree = function () {
	return this;
};

//  object prototype

PageHelper.ObjTree.prototype.attr_prefix = '-';

//  method: responseXML( responsexml )

PageHelper.ObjTree.prototype.responseXML = function ( responsexml ) {
	if ( ! responsexml ) return;
	var root = responsexml.documentElement;

	return this.parseDOM( root );
};

//  method: parseXML( xmlsource )

PageHelper.ObjTree.prototype.parseXML = function ( xml ) {
    var root;
    if ( window.DOMParser ) {
        var xmldom = new DOMParser();
//      xmldom.async = false;           // DOMParser is always sync-mode
        var dom = xmldom.parseFromString( xml, "application/xml" );
        if ( ! dom ) return;
        root = dom.documentElement;
    } else if ( window.ActiveXObject ) {
        xmldom = new ActiveXObject('Microsoft.XMLDOM');
        xmldom.async = false;
        xmldom.loadXML( xml );
        root = xmldom.documentElement;
    }
    if ( ! root ) return;
    return this.parseDOM( root );
};

//  method: parseDOM( documentroot )

PageHelper.ObjTree.prototype.parseDOM = function ( root ) {
    if ( ! root ) return;

    this.__force_array = {};
    if ( this.force_array ) {
        for( var i=0; i<this.force_array.length; i++ ) {
            this.__force_array[this.force_array[i]] = 1;
        }
    }

    var json = this.parseElement( root );   // parse root node
    if ( this.__force_array[root.nodeName] ) {
        json = [ json ];
    }
    if ( root.nodeType != 11 ) {            // DOCUMENT_FRAGMENT_NODE
        var tmp = {};
        tmp[root.nodeName] = json;          // root nodeName
        json = tmp;
    }
    return json;
};

//  method: parseElement( element )

PageHelper.ObjTree.prototype.parseElement = function ( elem ) {
    //  COMMENT_NODE
    if ( elem.nodeType == 7 ) {
        return;
    }

    //  TEXT_NODE CDATA_SECTION_NODE
    if ( elem.nodeType == 3 || elem.nodeType == 4 ) {
        var bool = elem.nodeValue.match( /[^\x00-\x20]/ );
        if ( bool == null ) return;     // ignore white spaces
        return elem.nodeValue;
    }

    var retval;
    var cnt = {};

    //  parse attributes
    if ( elem.attributes && elem.attributes.length ) {
        retval = {};
        for ( var i=0; i<elem.attributes.length; i++ ) {
            var key = elem.attributes[i].nodeName;
            if ( typeof(key) != "string" ) continue;
            var val = elem.attributes[i].nodeValue;
            if ( ! val ) continue;
            key = this.attr_prefix + key;
            if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
            cnt[key] ++;
            this.addNode( retval, key, cnt[key], val );
        }
    }

    //  parse child nodes (recursive)
    if ( elem.childNodes && elem.childNodes.length ) {
        var textonly = true;
        if ( retval ) textonly = false;        // some attributes exists
        for ( var i=0; i<elem.childNodes.length && textonly; i++ ) {
            var ntype = elem.childNodes[i].nodeType;
            if ( ntype == 3 || ntype == 4 ) continue;
            textonly = false;
        }
        if ( textonly ) {
            if ( ! retval ) retval = "";
            for ( var i=0; i<elem.childNodes.length; i++ ) {
                retval += elem.childNodes[i].nodeValue;
            }
        } else {
            if ( ! retval ) retval = {};
            for ( var i=0; i<elem.childNodes.length; i++ ) {
                var key = elem.childNodes[i].nodeName;
                if ( typeof(key) != "string" ) continue;
                var val = this.parseElement( elem.childNodes[i] );
                if ( ! val ) continue;
                if ( typeof( val ) == "string" ) val = this.xml_escape( val );
                if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
                cnt[key] ++;
                this.addNode( retval, key, cnt[key], val );
            }
        }
    }
    return retval;
};

//  method: addNode( hash, key, count, value )

PageHelper.ObjTree.prototype.addNode = function ( hash, key, cnts, val ) {
    if ( this.__force_array[key] ) {
        if ( cnts == 1 ) hash[key] = [];
        hash[key][hash[key].length] = val;      // push
    } else if ( cnts == 1 ) {                   // 1st sibling
        hash[key] = val;
    } else if ( cnts == 2 ) {                   // 2nd sibling
        hash[key] = [ hash[key], val ];
    } else {                                    // 3rd sibling and more
        hash[key][hash[key].length] = val;
    }
};

//  method: xml_escape( text )

PageHelper.ObjTree.prototype.xml_escape = function ( text ) {
	return String(text).replace('{/and/}', '&').replace('{/less/}', '<').replace('{/more/}', '>').replace('{/quote/}', '\'').replace('{/dquote/}', '\"');
};

// * Uploader ****************************************************************************
// ***************************************************************************************
PageHelper.Uploader = Class.create();
PageHelper.Uploader.prototype = {
	appendPostData: function() {
		var form_elements = [];
		var parameters = this.options.parameters;
		var i = 0;
		for (var name in parameters) {
			form_elements[i] = document.createElement('input');
			form_elements[i].type = 'hidden';
			form_elements[i].name = name;
			form_elements[i].value = parameters[name];
			this.form.appendChild(form_elements[i]);
			i++;
		}
		
		return form_elements;
	},
	createFrame: function() {
		var frame_id = 'upload-4ds-temp';
		var io;
		if (window.ActiveXObject) {
			io = document.createElement('<iframe id="' + frame_id + '" name="' + frame_id + '" />');
			io.src = 'javascript:false';
		} else {
			io = document.createElement('iframe');
			io.id = frame_id;
			io.name = frame_id;
		}

		io.style.position = 'absolute';
		io.style.top = '-1000px';
		io.style.left = '-1000px';

		document.body.appendChild(io);
	},
	getTransport: function() {
		var transport = {};
		return transport;
	},
	hasOwnProperty: function(obj, prop) {
		if (Object.prototype.hasOwnProperty) {
			return obj.hasOwnProperty(prop);
		}

		return !this.isUndefined(obj[prop]) && obj.constructor.prototype[prop] !== obj[prop];
	},
	initialize: function(form, url, options) {
		this.transport = this.getTransport();
		this.setOptions(options);
		this.form = $(form);
		this.upload(url);
	},
	isUndefined: function(obj) {
		return typeof obj === 'undefined';
	},
	setOptions: function(options) {
		this.options = {
      parameters: ''
    }
    Object.extend(this.options, options || {});

    if (typeof this.options.parameters == 'string')
      this.options.parameters = this.options.parameters.toQueryParams();
	},
	startIndicator: function() {
		if(this.options.indicator) {
			Element.show(this.options.indicator);
		}
	},
	stopIndicator: function() {
		if(this.options.indicator) {
			Element.hide(this.options.indicator);
		}
	},		
	upload: function(url) {
		this.startIndicator();

		// Create iframe in preparation for file upload.
		this.createFrame();
		
		var frame_id = 'upload-4ds-temp';
		var upload_encoding = 'multipart/form-data';
		var oconn = this;
		var io = $(frame_id);
		
		// Track original HTML form attribute values.
		var raw_form_attributes = {
			action: this.form.getAttribute('action'),
			method: this.form.getAttribute('method'),
			target: this.form.getAttribute('target')
		};		

		// Initialize the HTML form properties in case they are not defined in the HTML form.
		this.form.setAttribute('action', url);
		this.form.setAttribute('method', 'POST');
		this.form.setAttribute('target', frame_id);

		if(this.form.encoding) {
			// IE does not respect property enctype for HTML forms.
			// Instead it uses the property - "encoding".
			this.form.setAttribute('encoding', upload_encoding);
		} else {
			this.form.setAttribute('enctype', upload_encoding);
		}

		var form_elements = null;
		if (this.options.parameters) {
			// Create hidden variables for the parameters
			form_elements = this.appendPostData();
		}

		// Start file upload.
		this.form.submit();

		// Remove hidden input created from parameters
		if (form_elements && form_elements.length > 0) {
			for (var i = 0; i < form_elements.length; i++) {
				this.form.removeChild(form_elements[i]);
			}		
		}

		// Restore HTML form attributes to their original values prior to file upload.
		for (var prop in raw_form_attributes){
			if (this.hasOwnProperty(raw_form_attributes, prop)) {
				if (raw_form_attributes[prop]) {
					this.form.setAttribute(prop, raw_form_attributes[prop]);
				} else {
					this.form.removeAttribute(prop);
				}
			}		
		}

		// Create the upload callback handler that fires when the iframe
		// receives the load event.  Subsequently, the event handler is detached
		// and the iframe removed from the document.
		var upload_callback = function() {
			try {
				// responseText and responseXML will be populated with the same data from the iframe.
				// Since the HTTP headers cannot be read from the iframe
				oconn.transport.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML : io.contentWindow.document.documentElement.textContent;
				oconn.transport.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument : io.contentWindow.document;
			}
			catch(e){}
			
			if (oconn.options.onComplete) {
				oconn.options.onComplete(oconn.transport);
			}
			
			Event.stopObserving(io, "load", upload_callback);

			setTimeout(
				function(){
					document.body.removeChild(io);
					oconn.stopIndicator();
				}, 100);
		};

		Event.observe(io, "load", upload_callback)
	}
};

// * Date/Time Format ********************************************************************
// ***************************************************************************************

/* Date/Time Format v0.2; MIT-style license
By Steven Levithan <http://stevenlevithan.com> */

Date.prototype.format = function(mask) {
	var d = this; // Needed for the replace() closure
	
	// If preferred, zeroise() can be moved out of the format() method for performance and reuse purposes
	var zeroize = function (value, length) {
		if (!length) length = 2;
		value = String(value);
		for (var i = 0, zeros = ''; i < (length - value.length); i++) {
			zeros += '0';
		}
		return zeros + value;
	};
	
	return mask.replace(/"[^"]*"|'[^']*'|\b(?:d{1,4}|m{1,4}|yy(?:yy)?|([hHMs])\1?|TT|tt|[lL])\b/g, function($0) {
		switch($0) {
			case 'd':	return d.getDate();
			case 'dd':	return zeroize(d.getDate());
			case 'ddd':	return ['Sun','Mon','Tue','Wed','Thr','Fri','Sat'][d.getDay()];
			case 'dddd':	return ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'][d.getDay()];
			case 'm':	return d.getMonth() + 1;
			case 'mm':	return zeroize(d.getMonth() + 1);
			case 'mmm':	return ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][d.getMonth()];
			case 'mmmm':	return ['January','February','March','April','May','June','July','August','September','October','November','December'][d.getMonth()];
			case 'yy':	return String(d.getFullYear()).substr(2);
			case 'yyyy':	return d.getFullYear();
			case 'h':	return d.getHours() % 12 || 12;
			case 'hh':	return zeroize(d.getHours() % 12 || 12);
			case 'H':	return d.getHours();
			case 'HH':	return zeroize(d.getHours());
			case 'M':	return d.getMinutes();
			case 'MM':	return zeroize(d.getMinutes());
			case 's':	return d.getSeconds();
			case 'ss':	return zeroize(d.getSeconds());
			case 'l':	return zeroize(d.getMilliseconds(), 3);
			case 'L':	var m = d.getMilliseconds();
					if (m > 99) m = Math.round(m / 10);
					return zeroize(m);
			case 'tt':	return d.getHours() < 12 ? 'am' : 'pm';
			case 'TT':	return d.getHours() < 12 ? 'AM' : 'PM';
			// Return quoted strings with the surrounding quotes removed
			default:	return $0.substr(1, $0.length - 2);
		}
	});
};

Date.prototype.dateDiff = function(interval, date2) {
	var interval_units = $H({'yyyy': 1000*60*60*24*365, 'm': 1000*60*60*24*30, 'd': 1000*60*60*24, 'h': 1000*60*60, 'M': 1000*60, 's': 1000});
	var date1_ts = this.getTime();
	var date2_ts = date2.getTime();
	var time_diff = 0;

	if(typeof interval_units[interval] != "undefined") {
		var diff = date2_ts - date1_ts;
		time_diff = Math.floor(diff / interval_units[interval]);
	}
	return time_diff;
};

// * Validator ***************************************************************************
// ***************************************************************************************
PageHelper.Validator = {
	validateEmailAddress: function(email) {
		var filter=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
		if (!filter.test(email)) {
			return false;
		} else {
			return true;
		}
	},
	validateFortnoxNumber: function(number) {
		var ok = true;
		if (number.length == 0) {
			ok = false;
		} else {
			var valid_char='ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö0123456789_/+-';
			for (var i=0; i<number.length; i++) {
				if (valid_char.indexOf(number.charAt(i))<0) {
					ok = false;
					break;
				}
			}
		}
		return ok;
	}
};


