/**
 * Implements some basic functionallity to an module
 * such as update, send, hide, show etc.
 * Also attachs a eventdispatcher to the object
 */
function _BasicModule ()
{	
	this.initialize = function ( o, content ) {
		// Event dispatcher support
		EventDispatcher.initialize(o);

		o.__visible = false;
		o.__lastRequest = new Object();
		o.__savingElem = _div("", "moduleSave");
		o.content = content;
		o.content.appendChild( o.__savingElem );
		
		
		// send a new xmlrequest
		o.send = function (url, data, callback, method) {
			// clear and show loading
			this.clear();
			this.content.appendChild( _span("Laddar...") );
			// store this request
			this.__lastRequest.url = url;
			this.__lastRequest.data = data;
			this.__lastRequest.callback = callback;
			this.__lastRequest.method = method;
			// send request
			Application.send(url, data, callback, method);
		}
		
		// change the pending request data
		o.setRequestData = function (data) {
			this.__lastRequest.data = data;
		}
		
		// clear the content
		o.clear = function () {
			Utils.removeChildrenFromNode(this.content);
			this.content.innerHTML = "";
			this.content.appendChild( this.__savingElem );
		}
		
		// update the module, meaning repeat the last request
		o.update = function () {
			if ( !this.__visible ) return;
			
			if ( this.__lastRequest.url && this.__lastRequest.data && this.__lastRequest.callback )
				this.send( this.__lastRequest.url, this.__lastRequest.data, this.__lastRequest.callback, this.__lastRequest.method );
		}
		
		// show the module content
		o.show = function () {
			this.__visible = true;
			this.content.style.display = 'block';
		}

		// hide the module content
		o.hide = function () {
			this.__visible = false;
			this.content.style.display = 'none';
		}
		
		// show the saving overlay
		o.showSave = function () {
			this.__savingElem.style.width = this.content.offsetWidth + "px";
			this.__savingElem.style.height = this.content.offsetHeight + "px";
			this.__savingElem.style.display = "block";
		}

		// hide the saving overlay
		o.hideSave = function () {
			this.__savingElem.style.display = "none";
		}
	}
}
var BasicModule = new _BasicModule();function _BasicWindow ()
{	
	this.initialize = function ( o, windowdata ) {
		// Event dispatcher support
		EventDispatcher.initialize(o);

		o.__lastRequest = new Object();
		o.windowdata = windowdata;
		o.content = windowdata.content;
		
		// send a new xmlrequest
		o.send = function (url, data, callback, method) {
			// clear and show loading
			this.clear();
			this.setTitle("Laddar...");
			// store this request
			this.__lastRequest.url = url;
			this.__lastRequest.data = data;
			this.__lastRequest.callback = callback;
			this.__lastRequest.method = method;
			// send request
			Application.send(url, data, callback, method);
		}
		
		// clear the window content
		o.clear = function () {
			Utils.removeChildrenFromNode(this.windowdata.content);
		}
		
		// update the window content, meaning repeat the last request
		o.update = function () {
			this.send( this.__lastRequest.url, this.__lastRequest.data, this.__lastRequest.callback, this.__lastRequest.method );
		}
		
		// set a new title on the window
		o.setTitle = function (title) {
			WindowManager.setTitle( this.windowdata.id, title );
		}
		
		// show the window
		o.show = function () {
			WindowManager.show( windowdata.id );
		}

		// hide the window
		o.hide = function () {
			WindowManager.hide( windowdata.id );
		}
	}
}
var BasicWindow = new _BasicWindow();DragHandler = new Object();
DragHandler.currentObject = null;
DragHandler.overlayObject = null;
DragHandler.isDrag = false;
DragHandler.offsetX = 0;
DragHandler.offsetY = 0;

DragHandler.enableDrag = function ( buttonObject, dragObject, overlayObject ) {
	buttonObject.dragObject = dragObject;
	buttonObject.overlayObject = overlayObject;
	buttonObject.onmousedown = dragHandlerMouseDown;
}

dragHandlerMouseDown = function ( e ) {
	e = e || window.event;
	if (!e) return;

	DragHandler.currentObject = this.dragObject;
	DragHandler.overlayObject = this.overlayObject;
	DragHandler.isDrag = true;
	DragHandler.offsetX = e.screenX - Number(this.dragObject.style.left.substring(0, this.dragObject.style.left.indexOf("p")) );
	DragHandler.offsetY = e.screenY - Number(this.dragObject.style.top.substring(0, this.dragObject.style.top.indexOf("p")) );
	
	DragHandler.overlayObject.style.display = "block";
}

dragHandlerMouseUp = function ( e ) {
	e = e || window.event;
	if (!e) return;

	if (DragHandler.isDrag) {
		DragHandler.isDrag = false;
		DragHandler.currentObject.style.left = Number(e.screenX - DragHandler.offsetX) + "px";
		DragHandler.currentObject.style.top = Number(e.screenY - DragHandler.offsetY) + "px";
		DragHandler.overlayObject.style.display = "none";
	}
}
document.onmouseup = dragHandlerMouseUp;

dragHandlerMouseMove = function ( e ) {
	e = e || window.event;
	if (!e) return;
	
	if (DragHandler.isDrag) {
		DragHandler.currentObject.style.left = Number(e.screenX - DragHandler.offsetX) + "px";
		DragHandler.currentObject.style.top = Number(e.screenY - DragHandler.offsetY) + "px";
	}
}

document.onmousemove = dragHandlerMouseMove;/**
 * Global helper function to create new tags
 */

function _get(id) {
	try {
		return document.getElementById(id);
	}
	catch (e) {
		alert(id + " not found");
	}
};

function _elem(type, id, className) {
	try {
		var elem = document.createElement(type);
		if (className != "" && className) elem.className = className;
		if (id != "" && id) elem.id = id;
		return elem;
	}
	catch (e) {
		alert("unable to create new " + type + " element");
	}
};

function _a(text, className, cb, href, rel, title) {
	try {
		var a = _elem("a");
		a.innerHTML = text;
		a.className = className;
		if (href) {
			a.href = href;
			if (cb && cb != "")
				a.onclick = function () { cb(); return false;};
			else
				a.onclick = null;
			a.rel = rel;
			a.title = title;
		}
		else {
			a.href = "javascript:;";
			a.onclick = function () { cb(); return false;};
		}
		return a;
	}
	catch (e) {
		alert("unable to create new link " + e);
	}
};

function _br(className) {
	var br = _elem("br");
	if (className && className != "")
		br.className = className;
	return br;
};

function _div(id, className) {
	var e = _elem("div");
	if (id != "" && id) e.id = id;
	if (className) e.className = className;
	return e;
};

function _p(text, id, className) {
	var e = _elem("p");
	if (id) e.id = id;
	if (className) e.className = className;
	e.innerHTML = text;
	return e;
};

function _span(text, id, className) {
	var e = _elem("span");
	if (id) e.id = id;
	if (className) e.className = className;
	e.innerHTML = text;
	return e;
};

function _label(text) {
	var l = _elem("label");
	l.innerHTML = text;
	return l;
};

function _h1(text) {
	var e = _elem("h1");
	e.innerHTML = text;
	return e;
};

function _h2(text) {
	var e = _elem("h2");
	e.innerHTML = text;
	return e;
};

function _input(type, id, value, cb, maxlen) {
	var e = _elem("input");
	e.type = type;
	e.id = e.name = id;
	e.value = value == undefined ? "" : value;
	if (maxlen) {
		e.maxLength = maxlen;
	}
	if (cb) {
		e.onclick = cb;
	}
	return e;
};

function _textarea(id, value) {
	var e = _elem("textarea");
	e.id = e.name = id;
	e.value = value == undefined ? "" : value;
	return e;
};

function _select(id, size) {
	var e = _elem("select");
	e.id = e.name = id;
	e.size = size;
	return e;
};

function _img(src, alt, width, height, title, className, id, onload) {
	var e = _elem("img");
	e.src = src;
	if (width && width != "")
		e.width = width;
	if (height && height != "")
		e.height = height;
	if (alt && alt != "") 
		e.alt = e.title = alt;
	if (title && title != "")
		e.title = e.title;
	if (className && className != "")
		e.className = className;
	if (id && id != "")
		e.id = id;
	if (onload && onload != "")
		e.onload = onload;
	
	return e;
};/**
 * A simple implementation of a event dispatcher, a object must
 * first be initialized before it will be able to listen
 */
function _EventDispatcher () {
	this.initialize = function (scope) {
		scope._listeners = new Array();
		
		scope.dispatchEvent = function ( evt ) {
			try {
				var len = this._listeners.length;
				for ( var i=0; i < len; ++i ) {
					var obj = this._listeners[i];
					if ( obj.type == evt.type ) {
						obj.delegate(evt);
					}
				}
			} catch (e) {
				alert("dispatch failed: " + e + "\n\tevt.type: " + evt.type);
			}
		}
		
		scope.addEventListener = function (type, delegate) {
			var obj = new Object();
			obj.type = type;
			obj.delegate = delegate;
			
			this._listeners.push(obj);
		}
		
		scope.removeEventListener = function (type, delegate) {
			var len = this._listeners.length;
			for ( var i=0; i < len; ++i ) {
				var obj = this._listeners[i];
				if ( obj.type == type && obj.delegate == delegate ) {
					this._listeners.splice(i,1);
					return;
				} 
			}
		}
	}
}
var EventDispatcher = new _EventDispatcher();function Form () {
	this.root = null;
	this.currentTag = null;
	this.owner = null;
	this.validations = null;
	
	this.begin = function (id, owner) {
		this.root = _elem("form");
		this.root.name = this.root.id = id;
		this.root.method = "post";
		this.root.action = "#";
		this.root.enctype = "multipart/form-data";
		this.owner = owner;
		this.validations = new Array();
	}
	
	this.openTag = function (id, className) {
		if ( this.currentTag != null ) {
			alert("Tag not closed"); return;
		}
		
		this.currentTag = _div(id, className);
	}
	
	this.closeTag = function () {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}

		//this.root.appendChild(this.currentTag);
		var temp = this.currentTag
		this.currentTag = null;
		return temp;
	}
	
	//
	// Insert form fields
	//
	this.insertText = function (id, label, value, maxlen, validationMethod) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		var e = _input("text", id, value, null, maxlen);
		if ( validationMethod ) {
			e.onblur = Utils.delegate(this, "validateSingle", id, validationMethod);
			this.validations.push( {id:id, method:validationMethod} );
		}
		this.currentTag.appendChild( _label(label) );
		this.currentTag.appendChild( _br() );
		this.currentTag.appendChild( e );
		this.currentTag.appendChild( _br() );
		return e;
	}
	
	this.insertPassword = function (id, label, maxlen, validationMethod) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		var e = _input("password", id, "", null, maxlen);
		if ( validationMethod ) {
			e.onblur = Utils.delegate(this, "validateSingle", id, validationMethod);
			this.validations.push( {id:id, method:validationMethod} );
		}
		this.currentTag.appendChild( _label(label) );
		this.currentTag.appendChild( _br() );
		this.currentTag.appendChild( e );
		this.currentTag.appendChild( _br() );
		return e;
	}
	
	this.insertCheckbox = function (id, label, value, checked) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		var e = _input("checkbox", id, value)
		e.className = "formStyleCheckbox";
		e.checked = checked ? "checkted" : "";
		this.currentTag.appendChild( e );
		this.currentTag.appendChild( _label(label) );
		this.currentTag.appendChild( _br() );
	}
	
	this.insertSelect = function (id, label, validationMethod) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		var e = _select(id, 1);
		if ( validationMethod ) {
			e.onblur = Utils.delegate(this, "validateSingle", id, validationMethod);
			this.validations.push( {id:id, method:validationMethod} );
		}
		this.currentTag.appendChild( _label(label) );
		this.currentTag.appendChild( _br() );
		this.currentTag.appendChild( e );
		this.currentTag.appendChild( _br() );
		return e;
	}
	
	this.insertTextarea = function (id, label, value, maxlen, validationMethod) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		var s = _span(" ("+maxlen+" tecken kvar)");
		s.id = id + "_cl";
		
		var l = _label(label);
		l.appendChild(s);
		
		this.currentTag.appendChild( l );
		this.currentTag.appendChild( _br() );
		var e = _textarea(id, value);
		e.onkeydown = Utils.delegate(this, "onInputChange", id, maxlen);
		e.onkeyup = Utils.delegate(this, "onInputChange", id, maxlen);
		e.onchange = Utils.delegate(this, "onInputChange", id, maxlen);
		if ( validationMethod ) {
			e.onblur = Utils.delegate(this, "validateSingle", id, validationMethod);
			this.validations.push( {id:id, method:validationMethod} );
		}
		this.currentTag.appendChild( e );

		return e;
	}
	
	this.insertSubmit = function (id, label, cb) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		var e = _input("button", id, label, cb);
		this.currentTag.appendChild( e );
		return e;	
	}
	
	this.insertHidden = function (id, value) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		var e = _input("hidden", id, value);
		this.currentTag.appendChild( e );
		return e;
	}
	
	this.insertCustom = function ( label, e ) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		
		this.currentTag.appendChild( _label(label) );
		this.currentTag.appendChild( _br() );
		this.currentTag.appendChild( e );
		return e;
	}
	
	this.insertElement = function ( e ) {
		if ( this.currentTag == null ) {
			alert("Tag not open"); return;
		}
		this.currentTag.appendChild( e );
		return e;
	}
	
	//
	// Validation stuff
	//
	this.validate = function () {
		for( var i=0; i < this.validations.length; ++i ) {
			this.validateSingle( this.validations[i].id, this.validations[i].method );
		}
	}
	
	this.validateSingle = function (id, method) {
		var value = _get(id).value;
		
		var onval = function (result) {
			if ( result == 1 ) _get(id).className = "";
			else _get(id).className = "inputError";
		}
	
		eval( "x_"+method+"('"+ escape(value) +"', "+onval+");" );;
	}
	
	//
	// Helpers
	//
	this.bindSelectData = function (id, data, selectedId) {
		var select = _get(id);

		for( var _i in data ) {
			var i = data[_i];
			
			len = select.options.length;
			select[len] = new Option(i.name); 
			select[len].value = i.id;
			if(selectedId == i.id) {
				select[len].selected = "selected";
			}
		}
	}
	
	this.fillSelect = function (id, url, params, defaultId, noneText, _method) {
		Application.send( url, params, Utils.delegate(this, "onFillSelect", id, defaultId, noneText, _method));
	}
	
	
	this.onFillSelect = function (id, defaultId, noneText, _method, req) {
		var data = Utils.xmlToObject(req.responseXML);
		
		var select = _get(id);
		
		select[0] = new Option(noneText); 
		select[0].value = "-1";
		
		var _this = this;
		select.onchange = function () {
			_this.owner[_method](this.options[this.selectedIndex].value);
		}
				
		for( var _i in data ) {
			var i = data[_i];
			
			len = select.options.length;
			select[len] = new Option(i.name); 
			select[len].value = i.id;
			if(defaultId == i.id) {
				select[len].selected = "selected";
			}
		}
	}
	
	//
	// CALLBACKS
	//
	this.onInputChange = function (id, maxlen) {
		var e = _get(id);
		var l = this.setCharsLeft( id, e.value.length, maxlen );
		
		if (l <= 0) {
			e.value = String(e.value).substr(0, maxlen);
			this.setCharsLeft( id, e.value.length, maxlen );
		}
	}
	
	this.setCharsLeft = function (id, current, maxlen) {
		var e = _get(id + "_cl");
		var left = maxlen - current;
		e.innerHTML = "("+left+" tecken kvar)";
		return left;
	}
}function _GMap ()
{
	this.EVENT_SET_LOCATION = "setloc";
	this.EVENT_SET_MARKER = "setmrk";
	
	this.ClassName = "GMap";
	this.Map = null;
	this.GeoCoder = null;
	this.Icons = null;
	this.Markers = null;
	this.DivName = "";
	this.OfflineMode = false;
	this.Zoom = -1;
	
	this.initialise = function (divName) {
		if (this.OfflineMode) return;
		
		EventDispatcher.initialize(this);
		
		this.DivName = divName;
		if (GBrowserIsCompatible()) {
			this.Zoom = 10;
	        this.Map = new GMap2(_get(divName));
	        this.Map.setCenter(new GLatLng(59.33321, 18.06489), this.Zoom);
		}
		else {
			Application.alert("This browser is not compatible with Google Maps");
			return;
		}

		this.Map.enableDoubleClickZoom();
		this.Map.addControl(new GLargeMapControl());
		this.Map.addControl(new GMapTypeControl());

		GEvent.addDomListener(this.Map, "DOMMouseScroll", this.wheelZoom);  
		GEvent.addDomListener(this.Map, "mousewheel", this.wheelZoom); 

		this.GeoCoder = new GClientGeocoder();

		this.Icons = new Object();
		this.Markers = new Object();
	}
	
	this.destroy = function () {
		if (this.OfflineMode) return;
		
		GUnload();
	}
	
	this.wheelZoom = function (a) {
		if (this.OfflineMode) return;
		
		if(typeof newcenter == "undefined"){
			newcenter = map.getCenter();
		}
		if (a.detail) {
			if (a.detail < 0){ map.zoomIn(newcenter,true); }
			else if (a.detail > 0){ map.zoomOut(newcenter,true); }
		}
		else if (a.wheelDelta){
			if (a.wheelDelta > 0)
				{ map.zoomIn(newcenter,true); }
			else if (a.wheelDelta < 0)
				{ map.zoomOut(newcenter,true); }
		}
	}
	
	// Jump to a specific location on the map
	this.gotoLocation = function (asLoc) {
		if (this.OfflineMode) return;

		var p = new GLatLng(asLoc.latitude, asLoc.longitude);
		this.Map.setCenter(p, asLoc.zoom);
		this.Zoom = asLoc.zoom;
	}
	
	// Pan to a new location
	this.panToLocation = function (loc) {
		var p = new GLatLng(loc.latitude, loc.longitude);
		this.Map.panTo(p);		
	}
	
	// Try to find a location with geocoder
	this.searchLocation = function ( location, zoom ) {
		if (this.OfflineMode) return;
		
		var _this = this;
		this.GeoCoder.getLatLng( location, 
			function ( point ) {
				if (!point) {
					alert(location + " not found");
					// try to steal from eniro then huh?
				} 
				else { 
					if ( !zoom ) zoom = _this.Map.getZoom();
					_this.Map.setCenter(point, zoom);
					_this.Map.Zoom = zoom;
				}
			}
		);
	}
	
	// Add a new icon to the icon list
	this.addIcon = function (iconname, icon) {
		if (this.OfflineMode) return;

		// create a new icon
		/*var icon = new GIcon();
		
		icon.image = asIcon.imageSource;
		icon.shadow = asIcon.shadowSource;
		icon.iconSize = asIcon.iconSize;
		icon.shadowSize = asIcon.shadowSize;
		icon.iconAnchor = asIcon.iconAnchor;
		icon.infoWindowAnchor = asIcon.infoWindowAnchor;
		*/
		this.Icons[iconname] = icon;
	}
	
	// Place a marker on the map
	this.addMarker = function (mapMarker, customClickFunction) {
		if (this.OfflineMode) return;
	
		var p = new GLatLng(mapMarker.location.latitude, mapMarker.location.longitude);
		var marker = null;

		var options = new Object();
		options.draggable = mapMarker.draggable
		if (mapMarker.toolTip != "")
			options.title = mapMarker.toolTip;
		
		if ( this.Icons[mapMarker.iconName] )
			options.icon = this.Icons[mapMarker.iconName];

		marker = new GMarker(p, options);
		
		if ( mapMarker.draggable == true ) {
			var _this = this;
			this.SLMarker = marker;
			GEvent.addListener(this.SLMarker, "dragend", function() {_this.selectOnMapMarkerChanged();} );
		}
		
		var clickFunction;
		if (customClickFunction != null) {
			clickFunction = customClickFunction;
		}
		else {
			clickFunction = function() {
				if (mapMarker.numTabs == 1) { // No tabs, just one page
					marker.openInfoWindowHtml( mapMarker.tabContent[0].htmlContent );
				} 
				else { // Tabs
					var tabs = new Array();
					
					for ( var i=0; i < mapMarker.tabContent.length; ++i ) {
						var tabInfo = mapMarker.tabContent[i];
						var htmlContent = "";
						if (tabInfo.htmlURL != "") {
							htmlContent = '<iframe src="'+tabInfo.htmlURL+'" frameborder="no" scrolling="auto"></iframe>';
						}
						else {
							htmlContent = tabInfo.htmlContent;
						}
						
						tabs.push( new GInfoMarkerTab(tabInfo.tabName, htmlContent) );
					}
					
					marker.openInfoWindowTabsHtml(tabs);
				}
			}
		}
		GEvent.addListener(marker, "click", clickFunction);
		
		try {
			this.Map.addOverlay(marker);
		} catch (e) {
			Application.alert('Add marker failed ' + mapMarker.id);
		}
		this.Markers[mapMarker.id] = marker;
	}
	
	// Remove a single marker by id
	this.removeMarker = function ( id ) {
		if (this.OfflineMode) return;

		if ( this.Markers[id] ) {
			this.Map.removeOverlay(this.Markers[id]);
			this.Markers[id] = null;
		}
	}
	
	// Removes all the markers on the map
	this.clearMarkers = function () {
		if (this.OfflineMode) return;
		if (this.Map) {
			try {
				this.Map.clearOverlays();
				this.Markers = new Object();
			} catch (e) {
				Application.alert("GMap.clearMarkers: " + e);
			}
		}
	}
	
	/*
		Place a marker on the map
	*/	
	this.SMEvent = null;
	this.SMCB = null;
	this.SMMarker = null;
	this.SMControl = null;
	this.SMStoredMarkers = null;
	this.resetSetMarkerOnMapState = function () {
		if (this.OfflineMode) return;

		if (this.SMEvent) GEvent.removeListener(this.SMEvent);
		if (this.SMMarker) {
			try {
				this.Map.removeOverlay(this.SMMarker);
			} catch (e) {
				Application.alert("resetSetMarkerOnMapState: " + e);
			}
		}
		
		// Recover markers
		this.Markers = new Object();
		for ( var s in this.SMStoredMarkers ) {
			try {
				this.Markers[s] = this.SMStoredMarkers[s];
				this.Map.addOverlay( this.SMStoredMarkers[s] );
			} catch (e) {
				Application.alert('Add marker failed ' + s);
			}
		}
		this.SMStoredMarkers = null;
		this.SMEvent = null;
		this.SMCB = null;
		this.SMMarker = null;
		this.showSetMarkerToolbar(false);
	}
	
	this.enterSetMarkerOnMapState = function ( cb, defaultPoint ) {
		if (this.OfflineMode) return;

		// Store current map markers
		this.SMStoredMarkers = new Object();
		for ( var s in this.Markers ) {
			this.SMStoredMarkers[s] = new Object();
			this.SMStoredMarkers[s] = this.Markers[s];
			this.removeMarker(s);
		}
		//this.clearMarkers();

		this.SMCB = cb;
		this.showSetMarkerToolbar(true);
		var _this = this;
		this.SMEvent = GEvent.addListener(this.Map, "click", function(marker, point){_this.onEnterSetMarkerOnMapState(marker, point);});
		
		// Add a default marker if any
		if (defaultPoint != null) {
			var p = new GLatLng(defaultPoint.lat, defaultPoint.lng);
			this.SMMarker = new GMarker(p, {draggable: true});
			this.Map.setCenter(p, 10);
			
			var _this = this;
			GEvent.addListener(this.SMMarker, "dragend", function() {_this.setMarkerOnMapChanged();} );
	
			this.Map.addOverlay(this.SMMarker);
		}
	}
	
	this.onEnterSetMarkerOnMapState = function (marker, point) {
		if (this.OfflineMode) return;

		if (this.SMEvent) GEvent.removeListener(this.SMEvent);
		this.SMEvent = null
		
		if ( this.SMMarker ) {
			try {
				//GEvent.removeListener(this.SLMarker)
				this.Map.removeOverlay(this.SMMarker);
			} catch (e) {
				Application.alert("onEnterSetMarkerOnMapState - unable to remove marker: " + e);
			} 
		}
		
		this.SMMarker = new GMarker(point, {draggable: true});
		
		var _this = this;
		GEvent.addListener(this.SMMarker, "dragend", function() {_this.setMarkerOnMapChanged();} );

		this.Map.addOverlay(this.SMMarker);
		if (this.SMCB) this.SMCB(this.SMMarker.getPoint());
	}
	
	this.setMarkerOnMapChanged = function () {
		if (this.OfflineMode) return;

		if (this.SMCB) this.SMCB(this.SMMarker.getPoint());
	}

	//This should be move outside of this method
	this.showSetMarkerToolbar = function (show) {
		if (this.OfflineMode) return;
		
		this.dispatchEvent( {type:this.EVENT_SET_MARKER, show:show} );
		
		/*
		if (show) {
			//var div = getElem(this.DivName);
			var div = getElem("gmapcontent");
			div.style.display = "block";
			div.style.zIndex = 100;
			div.style.border = "2px solid #ffffff";
			
			this.SMControl = new MarkerConfirmControl();
			this.Map.addControl(this.SMControl);
			var back = getElem("gmapselectback");
			back.style.display = "block";
			back.style.zIndex = 99;
		}
		else {
			//var div = getElem(this.DivName);
			var div = getElem("gmapcontent");
			div.style.display = "block";
			div.style.zIndex = "";
			div.style.border = "";
			
			this.Map.removeControl(this.SMControl);
			this.SMControl = null;
			var back = getElem("gmapselectback");
			back.style.display = "none";
			back.style.zIndex = 99;
		}
		*/
	}
	
	/*
	 * Find a location on the map, but place no marker
	 */
	this.SLCB = null;
	this.SLControl = null;
	this.SLStoredMarkers = null;
	this.SLQuery = "";
	this.resetSetLocationOnMapState = function () {
		if (this.OfflineMode) return;

		// Recover markers
		this.Markers = new Object();
		for ( var s in this.SLStoredMarkers ) {
			try {
				this.Markers[s] = this.SLStoredMarkers[s];
				this.Map.addOverlay( this.SLStoredMarkers[s] );
			} catch (e) {
				Application.alert('Add marker failed ' + s);
			}
		}
		this.SLStoredMarkers = null;
		this.SLCB = null;
		this.showSetLocationToolbar(false);
	}
	
	this.enterSetLocationOnMapState = function ( cb, defaultPoint, zoom, query ) {
		if (this.OfflineMode) return;

		// Store current map markers
		this.SLStoredMarkers = new Object();
		for ( var s in this.Markers ) {
			this.SLStoredMarkers[s] = new Object();
			this.SLStoredMarkers[s] = this.Markers[s];
			this.removeMarker(s);
		}

		this.SLCB = cb;
		var _this = this;
		
		GEvent.addListener(this.Map, "moveend", function() {_this.setLocationOnMapChanged();} );
		GEvent.addListener(this.Map, "dragend", function() {_this.setLocationOnMapChanged();} );

		// Go to a default location if there is any
		if (defaultPoint != null) {
			var p = new GLatLng(defaultPoint.lat, defaultPoint.lng);
			this.Map.setCenter(p, zoom);
		}
		else if ( query && query != "" ) {
			this.SLQuery = query;
			this.searchLocation(query, zoom);
		}
		this.showSetLocationToolbar(true);
	}

	this.setLocationOnMapChanged = function () {
		if (this.OfflineMode) return;

		if (this.SLCB) this.SLCB(this.Map.getCenter(), this.Map.getZoom(), this.SLQuery);
	}


	this.showSetLocationToolbar = function (show) {
		if (this.OfflineMode) return;
		
		this.dispatchEvent( {type:this.EVENT_LOCATION, show:show} );
		
		/*
		if (show) {
			//var div = getElem(this.DivName);
			var div = getElem("gmapcontent");
			div.style.display = "block";
			div.style.zIndex = 100;
			div.style.border = "2px solid #ffffff";
			
			this.SLControl = new LocationConfirmControl();
			this.Map.addControl(this.SLControl);
			var back = getElem("gmapselectback");
			back.style.display = "block";
			back.style.zIndex = 99;
		}
		else {
			//var div = getElem(this.DivName);
			var div = getElem("gmapcontent");
			div.style.display = "block";
			div.style.zIndex = "";
			div.style.border = "";
			
			this.Map.removeControl(this.SLControl);
			this.SLControl = null;
			var back = getElem("gmapselectback");
			back.style.display = "none";
			back.style.zIndex = 99;
		}
		*/
	}
}

//

//Represents a marker on the map, create

// an instance and add it to the map
function MapMarker () {
	this.ClassName = "MapMarker";
	
	this.id = Utils.newGuid(); // Private
	this.numTabs = 0; // Private
	this.index = 0;
	
	// Contains object with 3 vals
	// tabName
	// htmlContent
	// htmlURL	<- prio 1
	this.tabContent = new Array();
	
	this.toolTip = "";
	this.draggable = false;
	this.iconName = "defaultIcon";
	this.location = new Object();
	
	this.addTab = function (tabName, htmlContent, htmlURL) {
		var tab = new Object();
		tab.tabName = tabName;
		tab.htmlContent = htmlContent;
		tab.htmlURL = htmlURL;
		
		tabContent.push(tab);
		numTabs = tabContent.length;
	}
}

var GMap = new _GMap();
//

//Control that contains an ok button

//

function MarkerConfirmControl() {
}
MarkerConfirmControl.prototype = new GControl();
MarkerConfirmControl.prototype.initialize = function(map) {
	var container = newElem("div");
	container.appendChild(newInput("button", "", "Klar"));
	
	GEvent.addDomListener(container, "click", function() {
		window.gmap.resetSetMarkerOnMapState();
	});
	
	map.getContainer().appendChild(container);
	return container;
}
MarkerConfirmControl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(20, 20));
}

//

// Controller with search options and confirm button

// used when finding a location but not placing a marker

//

function LocationConfirmControl() {
}
LocationConfirmControl.prototype = new GControl();
LocationConfirmControl.prototype.initialize = function(map) {
	var container = newElem("div");
	
	container.appendChild(newInput("text", "gmapLocationQuery", window.gmap.SLQuery));
	
	var searchButton = newInput("button", "", "Sök", newDelegate(this, "onSearchClicked"));
	container.appendChild(searchButton);
	
	var doneButton = newInput("button", "", "Klar");
	this.setButtonStyle(doneButton);
	container.appendChild(doneButton);
	
	GEvent.addDomListener(doneButton, "click", function() {
		window.gmap.resetSetLocationOnMapState();
	});
	
	map.getContainer().appendChild(container);
	return container;
}
LocationConfirmControl.prototype.onSearchClicked = function () {
	var q = getElem("gmapLocationQuery").value;
	window.gmap.SLQuery = q;
	window.gmap.searchLocation(q);
}
LocationConfirmControl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(20, 20));
}
LocationConfirmControl.prototype.setButtonStyle = function(button) {
	button.style.margin = "0px 0px 0px 15px";
}
function Localization ()
{
	this.EVENT_COUNTRY_CHANGED = "loccountry";
	this.EVENT_LAN_CHANGED = "loclan";
	this.EVENT_KOMMUN_CHANGED = "lockommun";
	
	//
	// Län and kommuner tjafs
	//
	this.selectLanTagId = "";
	this.selectKommunTagId = "";
	this.selectCountryTagId = "";
	this.presetCountry = -1;
	this.presetLan = -1;
	this.presetKommun = -1;
	
	this.getSearchString = function () {
		var qry = "";
		try {
			var select = _get(this.selectKommunTagId);
			if (select.options[select.selectedIndex].value != -1)
				qry += select.options[select.selectedIndex].text + ", ";
	
			select = _get(this.selectLanTagId);
			if (select.options[select.selectedIndex].value != -1)
				qry += select.options[select.selectedIndex].text + ", ";
				
			qry += "Sweden";
			return qry;
		}
		catch (e) {
			return "Stockholm, Sweden";
		}
	}
	
	this.getCountry = function () {
		var select = _get(this.selectCountryTagId);
		try {
			return select.options[select.selectedIndex].value;
		} catch (e) {
			return -1;
		}
	}
	
	this.getLan = function () {
		var select = _get(this.selectLanTagId);
		try {
			return select.options[select.selectedIndex].value;
		} catch (e) {
			return -1;
		}
	}
	
	this.getKommun = function () {
		var select = _get(this.selectKommunTagId);
		try {
			return select.options[select.selectedIndex].value;
		} catch (e) {
			return -1;
		}
	}
	
	this.buildLocalizationList = function (selectCountryTagId, selectLanTagId, selectKommunTagId, presetCountry, presetLan, presetKommun) {
		EventDispatcher.initialize(this);
		
		this.selectCountryTagId = selectCountryTagId;
		this.selectLanTagId = selectLanTagId;
		this.selectKommunTagId = selectKommunTagId;
		this.presetCountry = presetCountry;
		this.presetLan = presetLan;
		this.presetKommun = presetKommun;		
		
		Application.send("/service/localization/", "a=country", Utils.delegate(this, "onGetCountrySelectList"));
	}
	
	this.onGetCountrySelectList = function (req) {
		var data = Utils.xmlToObject(req.responseXML)
				
		var select = _get(this.selectCountryTagId);
		
		select[0] = new Option("Välj land"); 
		select[0].value = "-1";
		
		var _this = this;
		select.onchange = function () {
			_this.getLanSelectList(this.options[this.selectedIndex].value);
			_this.dispatchEvent( {type:_this.EVENT_COUNTRY_CHANGED, id:this.options[this.selectedIndex].value} );
		}
				
		for( var _i in data ) {
			var i = data[_i];
			
			len = select.options.length;
			select[len] = new Option(i.name); 
			select[len].value = i.id;
			if(this.presetCountry == i.id) {
				select[len].selected = "selected";
				this.getLanSelectList(i.id);
			}
		}
	}
	
	this.getLanSelectList = function (countryid) {
		if (countryid == 1) {
			_get(this.selectLanTagId).disabled = "";
			_get(this.selectKommunTagId).disabled = "";
			Application.send("/service/localization/", "a=lan", Utils.delegate(this, "onGetLanSelectList"));
		}
		else  {
			_get(this.selectLanTagId).disabled = "disabled";
			_get(this.selectKommunTagId).disabled = "disabled";			
		}
	}
	
	this.onGetLanSelectList = function (req) {
		var data = Utils.xmlToObject(req.responseXML)

		var select = _get(this.selectLanTagId);
		
		select[0] = new Option("Välj län"); 
		select[0].value = "-1";
		
		var _this = this;
		select.onchange = function () {
			_this.getKommunSelectList(this.options[this.selectedIndex].value);
			_this.dispatchEvent( {type:_this.EVENT_LAN_CHANGED, id:this.options[this.selectedIndex].value} );
		}
				
		for( var _i in data ) {
			var i = data[_i];

			len = select.options.length;
			select[len] = new Option(i.name); 
			select[len].value = i.id;
			if(this.presetLan == i.id) {
				select[len].selected = "selected";
				this.getKommunSelectList(i.id);
			}
		}
	}
	
	this.getKommunSelectList = function (lanid) {
		Utils.removeChildrenFromNode( _get(this.selectKommunTagId) );

		if (lanid != -1) {
			Application.send("/service/localization/", "a=kommun&lan="+lanid, Utils.delegate(this, "onGetKommunSelectList"));
		}
	}
	
	this.onGetKommunSelectList = function (req) {
		var data = Utils.xmlToObject(req.responseXML)
			
		var select = _get(this.selectKommunTagId);
		
		select[0] = new Option("Välj kommun"); 
		select[0].value = "-1";

		var _this = this;
		select.onchange = function () {
			_this.dispatchEvent( {type:_this.EVENT_KOMMUN_CHANGED, id:this.options[this.selectedIndex].value} );
		}
		
		for( var _i in data ) {
			var i = data[_i];

			len = select.options.length;
			select[len] = new Option(i.name); 
			select[len].value = i.id;
			if(this.presetKommun == i.id) {
				select[len].selected = "selected";
			}
		}
	}
}function _PageNavigation() {
	
	this.navigationData = null;
	
	this.calculate = function ( current, total, navsize ) {
		this.navigationData = new Array();
		
		if ( current > 1 ) {
			this.addNav("Föregående", current-1, false);
		}
		
		var steps = Math.floor( (current-1) / navsize );
		var prev = steps*navsize;
		var next = ((steps+1)*navsize)+1;
		
		if ( prev > 1 )
			this.addNav("...", prev);
		
		var s = prev+1;
		var e = Math.min( next, total+1);
		for ( var i = s; i < e; ++i ) {
			this.addNav(i, i, i == current);
		}

		if ( next < total )
			this.addNav("...",next,false);
		
		if ( current < total ) {
			this.addNav("Nästa", current+1, false);
		}
		
		return this.navigationData;
	}
	
	this.addNav = function ( label, pageId, selected ) {
		var o = new Object();
		o.label = label;
		o.pageid = pageId;
		o.selected = selected;
		this.navigationData.push( o );		
	}
	
}
var PageNavigation = new _PageNavigation();var promo_resizing = false;
var show_promo = true;

setFrameSize = function()
{ 
	var wh;  			
	var ww;
	
	if (typeof( window.innerHeight ) == 'number' )
		wh = window.innerHeight;
	else
		wh = (document.documentElement.clientHeight>0) ? document.documentElement.clientHeight : document.body.clientHeight;

	if (typeof( window.innerWidth ) == 'number' )
		ww = window.innerWidth;
	else
		ww = (document.documentElement.clientWidth>0) ? document.documentElement.clientWidth : document.body.clientWidth;

	$j("#frame").height(wh - 6);

	if (!Application.checkLogin()) {
		if (ww > 1140 && promo_resizing == false) {		
			if (show_promo == true) {
				promo_resizing = true;
				$j("#content").animate({width: 1100}, "slow", function(){promo_resizing = false;});
				$j("#promo").show("slow");
			}
		} else if (promo_resizing == false) {
				promo_resizing = true;
				$j("#promo").hide();
				$j("#content").animate({width: 856}, 'slow', function(){promo_resizing = false;});
		}
	}
}/**
 * Implements some basic functionallity to an module
 * such as update, send, hide, show etc.
 * And has suppoer for tabs
 * Also attachs a eventdispatcher to the object
 */
function _TabModule ()
{	
	this.initialize = function ( o, container, menucontent, content ) {
		// Event dispatcher support
		EventDispatcher.initialize(o);

		o.__visible = false;
		o.__lastRequest = new Object();
		o.__savingElem = _div("", "moduleSave");
		o.container = container;
		o.menucontent = menucontent;
		o.content = content;
		o.content.appendChild( o.__savingElem );
		
		// send a new xmlrequest
		o.send = function (url, data, callback, method) {
			// clear and show loading
			this.clear();
			this.content.appendChild( _span("Laddar...") );
			// store this request
			this.__lastRequest.url = url;
			this.__lastRequest.data = data;
			this.__lastRequest.callback = callback;
			this.__lastRequest.method = method;
			// send request
			Application.send(url, data, callback, method);
		}
		
		// change the pending request data
		o.setRequestData = function (data) {
			this.__lastRequest.data = data;
		}
		
		// clear the content
		o.clear = function () {
			Utils.removeChildrenFromNode(this.content);
			this.content.innerHTML = "";
			this.content.appendChild( this.__savingElem );
		}
		
		// update the module, meaning repeat the last request
		o.update = function () {
			if ( !this.__visible ) return;
			
			if ( this.__lastRequest.url && (this.__lastRequest.data || this.__lastRequest.data == "") && this.__lastRequest.callback )
				this.send( this.__lastRequest.url, this.__lastRequest.data, this.__lastRequest.callback, this.__lastRequest.method );
		}
		
		// show the module content
		o.show = function () {
			this.__visible = true;
			this.container.style.display = 'block';
		}

		// hide the module content
		o.hide = function () {
			this.__visible = false;
			this.container.style.display = 'none';
		}
		
		// show the saving overlay
		o.showSave = function () {
			this.__savingElem.style.width = this.content.offsetWidth + "px";
			this.__savingElem.style.height = this.content.offsetHeight + "px";
			this.__savingElem.style.display = "block";
		}

		// hide the saving overlay
		o.hideSave = function () {
			this.__savingElem.style.display = "none";
		}
	}
}
var TabModule = new _TabModule();function _Utils ()
{
	/**
	 * Validates a email
	 */
	this.validateEmail = function(str) {
	   return (str.indexOf(".") > 2) && (str.indexOf("@") > 0);
	}

	/**
	 * Creates an object that represents a callback method
	 * attached to a class instance
	 */
	this.delegate = function (scope, method) {
		var paramObj = new Object();
		for (var i=2; i<arguments.length; ++i) {
			paramObj['arg'+i] = arguments[i];
		}
		var delegatedFunc;
		
		delegatedFunc = function() {
			var args = "";
			var cnt = 0;
			for(a in paramObj) {
				if(args!="") args += ",";
				++cnt;
				
				if ( typeof(paramObj[a]) == "string" )
					args += "'"+paramObj[a]+"'";
				else
					args += paramObj[a];
			}
			if ( arguments.length != cnt ) {
				for(var i=0; i < arguments.length; ++i) {
					if ( arguments[i] ) {
						if(args!="") args += ",";
						args += "arguments["+i+"]";
					}
				}
			}
			//try {
				eval("scope[method]("+args+");");
			//}
			//catch (e) {
			//	alert(scope+"["+method+"]("+args+") failed\n\n" + e);
			//}
			//return false;
		}
		delegatedFunc.paramObj = paramObj;
	
		return delegatedFunc;
	}
	
	/**
	 * Create a new GUID
	 * Unique 32 char
	 */
	this.newGuid = function () {
	    var g = "{";
	    for(var i = 0; i < 32; i++)
	    g += Math.floor(Math.random() * 0xF).toString(0xF) + (i == 8 || i == 12 || i == 16 || i == 20 ? "-" : "")
	    return g + "}";
	}
	
	/**
	 * Either change the location or open url in a new window
	 */
	this.gotoLocation = function (url, newWindow) {
		if (newWindow) {
			var nwin = window.open(url, Math.floor(Math.random() * 0xF).toString(0xF));
			nwin.focus();
		}
		else {
			window.location.href = url;
		}
	}
	
	/**
	 * Removes all chindren from the specified noe
	 */
	this.removeChildrenFromNode = function (node)
	{
		if (node == undefined || node == null) return;
		if (node.hasChildNodes() == false ) return;
	
		var tempArray = new Array();
		for ( var i=0; i<node.childNodes.length; ++i ) {
			tempArray.push(node.childNodes[i]);
		}
		
		for ( var i=0; i < tempArray.length; ++i) {
			try {
				node.removeChild(tempArray[i]);
			} catch(e) {
				alert("removeChildrenFromNode " + e);
			}
		}
	}
	
	this.xmlToObject = function (node) {
		var data = new Object();
		
		var child = node;//.firstChild;
				
		// find the first param node
		while ( child.nodeName != "param" ) {
			child = child.firstChild;
			if ( !child ) return null;
		}
		
		// start parsing
		while (child) {
			var key = child.getAttribute('key');
			
			if ( key == undefined ) {
				child = child.nextSibling;
				continue;
			}
			
			// CDATA, value or children?
			var value = null;
			if( child.firstChild ) {
				if ( child.firstChild.nodeName == "param" ) { // children 
					value = Utils.xmlToObject(child.firstChild);
				}
				else  // CDATA
					value = child.firstChild.nodeValue; 
			}
			else 
				value = child.nodeValue;
			
			data[key] = value;
			child = child.nextSibling;
		}
		
		return data;
	}
	
	/**
	 * Convert all newlines to br
	 */
	this.convertNewline = function (t) {
		return t.replace(/(\r\n|[\r\n])/g, "<br />");
	}
	
	/**
	 * Convert Degrees Minutes Seconds to Decimal Degrees
	 */
	this.convertDMSToDD = function (d, m, s) {
		d = Number(d); m = Number(m); s = Number(s);
		s /= 60;
		m += s;
	
		var deg = m / 60;
	
		return Number(d + deg).toFixed(14);
	}
	
	/**
	 * Convert Decimal Degrees To Degrees Minutes Seconds
	 */
	this.convertDDToDMS = function (n) {
		var d = Math.floor(n);
		var f = n - d;
		
		var m = Math.floor(f * 60);
		
		var s = (f * 60) - m;
		s *= 60;
		
		var o = new Object();
		o.d = d;
		o.m = m;
		o.s = s.toFixed(2);
		return o;
	}
	
	/**
	 * nuhu
	 */
	this.convertDMSPaste = function ( inputId ) {
		var input = _get(inputId);
		var value = input.value;

		if ( value.indexOf("º") > 0 && value.indexOf("'") > 0 && value.indexOf("\"") > 0 ) {
			var myReg = /(\d+)º\s(\d+)'\s(\d+\.\d+)"/;
			
			var result = value.match(myReg);
			
			if (result) {
				input.value = result[1] + " " + result[2] + " " + result[3];
			}
			else {
				alert("Koordinaterna är av okänt format. Ex. 59º 20' 24.73\"");
			}
		}
	}
}
var Utils =  new _Utils();/**
 * Easy usage of the popup windows
 */
function _WindowManager ()
{	
	// Event dispatcher support
	EventDispatcher.initialize(this);
	
	this.EVENT_MODAL_ENABLE  = "modenable";
	this.EVENT_MODAL_DISABLE  = "moddisable";
	
	this._windows = new Object();
	this._prefix = "win_";
	this._zindex = 92; // gör snyggare i framtiden ;)
	
	this.container = null;
	
	this.initialize = function (container) {
		this.container = container;
	}

	this.show = function (id) {
		this._windows[id].win.style.display = 'block';
		if ( this._windows[id].options && this._windows[id].options.ismodal ) this.dispatchEvent({type:this.EVENT_MODAL_ENABLE});
	}

	this.hide = function (id) {
		this._windows[id].win.style.display = 'none';
		if ( this._windows[id].options && this._windows[id].options.ismodal ) this.dispatchEvent({type:this.EVENT_MODAL_DISABLE});
	}
	
	this.setTitle = function (id, title) {
		//Utils.removeChildrenFromNode( this._windows[id].title );
		this._windows[id].title.innerHTML = title;
		//this._windows[id].title.appendChild( _span(title) );
	}

	/**
	 * Create an window that will have the same scope as the main document
	 * All content will be added in a div
	 */
	this.createInternal = function (id, title, width, height, options) {
		var win = _div(this._prefix + id, "windowroot");
		win.style.zIndex = this.getNextHighestDepth();

		var t = this.styleTop(width, height);
		var c = this.styleContent(width, height);
		
		var content = _elem("div");
		c.appendChild(content);
		win.appendChild(t);
		win.appendChild(c);

		var overlay = _elem("div", "", "windowcontentoverlay");
		overlay.style.width = width + "px";
		overlay.style.height = height + "px";
		win.appendChild(overlay);
				
		var titleelement = _h1(title);
		t.appendChild( titleelement );
		var closeelem = _a("[Stäng]", "", Utils.delegate(this, "hide", id));
		closeelem.style.left = (width-40) + "px";
		t.appendChild( closeelem );
		
		this._windows[id] = {
			win:win,
			id:id,
			content:content,
			title:titleelement,
			options:options,
			overlay:overlay
		};
		
		this.container.appendChild( win );
		
		var arrayPageSize = getPageSize();
		var arrayPageScroll = getPageScroll();
		var x = arrayPageScroll[0] + (arrayPageSize[2] / 2);
		var y = arrayPageScroll[1] + (arrayPageSize[3] / 2);
		
		x -= width/2;
		y = 200;//height/2;
		
		win.style.left = x + "px";
		win.style.top = y + "px";
		
		//DragHandler.enableDrag( t, win, overlay );
		
		return this._windows[id];
	}
	
	/**
	 * Create a new window that will contain the content of a 
	 * path as an iframe.
	 */
	this.createIFrame = function (id, title, width, height, url, arg, options) {
		var win = _div(this._prefix + id, "windowroot");
		win.style.zIndex = this.getNextHighestDepth();

		var t = this.styleTop(width, height);
		var c = this.styleContent(width, height);
		
		var src = "/window/" + url + "/?windowid=" + id + "&w=" + width + "&h=" + height + "&" + arg;
		
		// IE7 fix, unable to find parent if it's cached.. but only sometimes... 
		var d = new Date();
		var ct = d.getTime();
		src += "&cache=" + ct;
		
		var html = '<iframe src="'+src+'" frameborder="no" width="'+width+'px" height="'+height+'px" scrolling="no"></iframe>'

		var content = _elem("div");
		content.innerHTML = html;
		c.appendChild(content);
		win.appendChild(t);
		win.appendChild(c);

		var overlay = _elem("div", "", "windowcontentoverlay");
		overlay.style.width = width + "px";
		overlay.style.height = height + "px";
		win.appendChild(overlay);
		
		var titleelement = _h1(title);
		t.appendChild( titleelement );
		var closeelem = _a("[Stäng]", "", Utils.delegate(this, "hide", id));
		closeelem.style.left = (width-40) + "px";
		t.appendChild( closeelem );
			
		this._windows[id] = {
			win:win,
			id:id,
			content:content,
			title:titleelement,
			options:options,
			overlay:overlay
		};
		
		this.container.appendChild( win );
		
		var arrayPageSize = getPageSize();
		var arrayPageScroll = getPageScroll();
		var x = arrayPageScroll[0] + (arrayPageSize[2] / 2);
		var y = arrayPageScroll[1] + (arrayPageSize[3] / 2);
		
		x -= width/2;
		y = 200;//height/2;
		
		win.style.left = x + "px";
		win.style.top = y + "px";
		
		//DragHandler.enableDrag( t, win, overlay );
		
		return this._windows[id];
	}
	
	/**
	 * Create a window that will read the content of a url
	 * and fill the window main div with it
	 */
	this.createInternalURL = function (id, title, width, height, url, options) {
		throw "TODO: Implement WindowManager.createInternalURL";
	}
	
	this.getNextHighestDepth = function () {
		return this._zindex++;
	}
	
	/**
	 * Get the top element of a window
	 */
	this.styleTop = function (w, h) {
		var windowtop = _div("", "windowtop");
		
		var windowtopback = _div("", "windowtopback");
		
		var m = _div("", "windowtopback_m");
		m.style.width = (w-10)+"px";
		var l = _div("", "windowtopback_l");
		var r = _div("", "windowtopback_r");
		
		windowtopback.appendChild(l);
		windowtopback.appendChild(m);
		windowtopback.appendChild(r);
		
		windowtop.appendChild(windowtopback);
		return windowtop;
	}

	/**
	 * Get the content element of a window
	 */
	this.styleContent = function (w, h) {
		var div = _div(undefined, "windowcontent");
		div.style.width = w + "px";
		div.style.height = h + "px";
		return div;
	}
}
var WindowManager = new _WindowManager();function _Voting () {
	
	this.buildCurrentRating = function(rating, size, color, _scope, _cb) {
	
		color = "w";
		size = 13;	
	
		var div = _div("", "rating");
		var _int = Math.floor(rating);
		var _float = rating-_int;
		var useHalf = false;
		var _rest = 6 - _int;
		if (_float > 0.80) {
			_int++;
			_rest--;
		}
		else if (_float > 0) {
			useHalf = true;
			_rest--;
		}
		
		var i;
		var i2 = 1;
		var e;
		for (i=0; i<_int; ++i) {
			e = _img("/g/rating_"+color+size+"_full.gif");
			e.defaultLook = "full";
			e.imgSize = size;
			e.backColor = color;
			this.setRatingInput(e, i2, _scope, _cb);
			div.appendChild( e );
			++i2;
		}
		if (useHalf) {
			e = _img("/g/rating_"+color+size+"_half.gif");
			e.defaultLook = "half";
			e.imgSize = size;
			e.backColor = color;
			this.setRatingInput(e, i2, _scope, _cb);
			div.appendChild( e );	
			++i2;
		}
		for (i=0; i<_rest; ++i) {
			e = _img("/g/rating_"+color+size+"_empty.gif");
			e.defaultLook = "empty";
			e.imgSize = size;
			e.backColor = color;
			this.setRatingInput(e, i2, _scope, _cb);
			div.appendChild( e );
			++i2;
		}
		
		return div;
	}
	
	this.buildVotingModule = function(_scope, _cb, color) {
		var div = _elem("div");
		for (var i=0; i<6; ++i) {
			var e = _img("/g/rating_"+color+"13_empty.gif");
			e.defaultLook = "empty";
			e.imgSize = 13;
			e.backColor = "w";
			this.setRatingInput(e, i+1, _scope, _cb);
			div.appendChild(e);
		}
		return div;
	}
	
	this.setRatingInput = function(e, rating, _scope, _cb) {
		if (_scope && _cb) {
			e.style.cursor = "pointer";
			e.ratingIndex = (rating-1);
			e.id = "uservote_" + (rating-1);
			e.onclick = Utils.delegate(_scope, _cb, rating);
			e.onmouseover = function () {Voting.onRatingOver(this.ratingIndex);}
			e.onmouseout = function () {Voting.onRatingOut(this.ratingIndex);}
		}
	}
	
	this.onRatingOver = function(index) {
		try {
			for (var i=0; i<index+1; ++i) {
				var e = _get("uservote_" + i);
				e.src = "/g/rating_"+e.backColor+e.imgSize+"_full.gif";
			}
			for (var i=index+1; i<6; ++i) {
				var e = _get("uservote_" + i);
				e.src = "/g/rating_"+e.backColor+e.imgSize+"_empty.gif";
			}
		} catch (e) {
			
		}
	}
	
	this.onRatingOut = function(index) {
		try {
			for (var i=0; i<6; ++i) {
				var e = _get("uservote_" + i);
				e.src = "/g/rating_"+e.backColor+e.imgSize+"_"+e.defaultLook+".gif";
			}
		} catch (e) {
			
		}
	}
	
}
var Voting = new _Voting();/**
  Request class, implements the XMLHttpRequest object and enables a easier usage
  and multiple calls
**/
function _XMLRequest ()
{
	this.EVENT_SEQURITY_ERROR = "seqerror"; // Usually dispatched when a user is not logged in
	
	this.construct = function () {
		EventDispatcher.initialize(this);
	}
	
	this.send = function(url, data, callback, method) {
		var req = null;
		
		if ( !method ) method = "POST";
		
		// Try to create the request object
		var msXmlHttp = new Array(
			'Msxml2.XMLHTTP.5.0',
			'Msxml2.XMLHTTP.4.0',
			'Msxml2.XMLHTTP.3.0',
			'Msxml2.XMLHTTP',
			'Microsoft.XMLHTTP');
		
		for (var i = 0; i < msXmlHttp.length; i++) {
			try {
				req = new ActiveXObject(msXmlHttp[i]);
			} catch (e) {
				req = null;
			}
		}
		
		if(!req && typeof XMLHttpRequest != "undefined")
			req = new XMLHttpRequest();
		if (!req)
			throw "Unable to create XMLHttpRequest object. Not supported";
		
		var readychange = function() {
			try {
				if (req.readyState == 4) {
					if (req.status < 400) {
						// check error
						if ( req.responseXML && req.responseXML.firstChild ) {
							if( req.responseXML.firstChild.nodeName == "error") {
								if ( req.responseXML.firstChild.firstChild.nodeValue == "ERR_LOGIN" ) {
									XMLRequest.dispatchEvent( {type:XMLRequest.EVENT_SEQURITY_ERROR} );
								}
								else {
									var e = "XMLRequest.response: " + req.responseXML.firstChild.nodeName + ": " + req.responseXML.firstChild.firstChild.nodeValue + "\n";
									e += "\turl: " + url + "\n";
									e += "\tdata: " + data + "\n";
									throw e;
									return;
								}
							}
						}
						
						try {
							if ( callback ) {
								callback(req);
								delete callback;
							}
						}
						catch (e) {
							
						}
					} 
					else if (typeof req == "undefined" || typeof req.status == "undefined") {
						// don't do anything. user has navigated away
						if (callback) delete callback;
					} 
					else if (req.status == 401) { // unauthorized
						throw "401 - You are not authorized";
						if (callback) delete callback;
					} 
					else if (req.status == 404) {
						throw "404 - File not found";
						if (callback) delete callback;
					} 
					else {
						switch(req.status) {
							// windows error codes
							case 12002: // server timeout
							case 12029: case 12030: case 12031: // dropped connection
							case 12152: // connection closed by server
							case 13030:
								throw "There was a network problem. Please reload the page.";
								break;
							case 500: case 503:
								throw "There was an internal server error. Please try later.";
								break;
							default:
								throw "There was a problem loading data:" + "\nstatus: " + req.status+ "/" + req.statusText + "\n" + url;
						}
					}
					try {delete callback;} catch(e) {}
				}
			} catch (e) {
				alert("XMLRequest.ready: " + e);
			}
		}
		
		// IE7 cache the requests, override it with this 
		var d = new Date();
		var t = d.getTime();
		if ( url.indexOf('?') != -1 ) {
			url += "&cache=" + t;	
		}
		else {
			url += "?cache=" + t;
		}

		if (method=="POST") {
			req.open("POST", url, true);
			req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			req.onreadystatechange = readychange;
			req.send(data);
		} else {
			req.open("GET", url, true);
			req.onreadystatechange = readychange;
			req.send(null);
		}
		
		return req;
	}
}
var XMLRequest = new _XMLRequest();