
// DHTML Layering API for eMB MS and integrated applications

(function() {
// (hide everything except the things we make public explicitly)

var embLayerManager;

window.embGetLayerManager = function () {
  if (!embLayerManager) {
    embLayerManager = new EmbLayerManager();
  }
  return embLayerManager;
}

function LayerException(msg, context) {
  this.msg = msg;
  this.context = context;
  
  return this;
}


function EmbLayerManager() {
	this._textMap = {
		loading: "Bitte haben Sie einen Moment Geduld. Die Seite wird geladen.",
		ok: "OK",
		cancel: "Abbrechen",
		close: "Schliessen",
		server_error: "Diese Funktion steht leider zur Zeit nicht zur Verfuegung. Versuchen Sie es bitte spaeter erneut."
	};
	
}

// --- Debugging utilities



function EmbUtils() {
}

// printf-debugging support
var debugConsole = window.console;

if (!window.console) {
  debugConsole = {
    log:   function() {},
    debug: function() {},
    print: function() {},
    isDummy: true
  };
  
  try {
    window.console = debugConsole;
  } catch (e) {
    // we don't really care
  }
}

EmbUtils.prototype = {
	fullHeight: function(doc) {
	    var body = doc.body;
	    var elem = doc.documentElement;
	    return Math.max(
	        Math.max(body.scrollHeight, elem.scrollHeight),
	        Math.max(body.offsetHeight, elem.offsetHeight),
	        Math.max(body.clientHeight, elem.clientHeight)
	    );
	},

	docElem: function docElem(property) {
      var t;
      return ((t = document.documentElement) || (t = document.body.parentNode)) && isNumber( t[property] ) ? t : document.body
    },

	viewSize: function viewSize(doc) {
		var result = {w:window.innerWidth, h:window.innerHeight};
		
		var elem = this.docElem('clientWidth');
		var body = document.body;
		var w, h;
		if (isNumber(document.clientWidth)) {
		  result = { w : document.clientWidth, h : document.clientHeight };
		} else if (
			(Math.max(elem.clientWidth, body.clientWidth)) > window.innerWidth
			|| (Math.max(elem.clientHeight, body.clientHeight)) > window.innerHeight			
		) {
			result = { 
			  w:Math.min(elem.clientWidth, body.clientWidth, window.innerWidth), 
			  h:Math.min(elem.clientHeight, body.clientHeight, window.innerHeight)
			};
		} else if (
			elem === body
		) {
		  result = { w : body.clientWidth, h : body.clientHeight };
		} else if (isNumber(body.clientWidth)) {
		  result = { w : body.clientWidth, h : body.clientHeight };
		} else if (isNumber(elem.clientWidth)) {
		  result = { w : elem.clientWidth, h : elem.clientHeight };
		}

		result.dcw = document.clientWidth;
		result.dch = document.clientHeight;
		result.ecw = elem.clientWidth;
		result.ech = elem.clientHeight;
		result.bcw = body.clientWidth;
		result.bch = body.clientHeight;
		result.ww = window.innerWidth;
		result.wh = window.innerHeight;

		return result;
	}

};

EmbUtils.prototype.debugString = function debugString(obj, filter) {
	filter = filter || /.*/;
	var result = '';
	for (var i in obj) {
		if (filter.test(i) && "function" != typeof(obj[i])) {
			try {
				result += "~"+i+":"+obj[i];
			} catch (x) {}
		}
	}
	return result;
}

EmbUtils.prototype.addHandler = function addHandler(obj, name, handler) {
	var oldHandler = obj[name];
	var newHandler = handler;
	if (typeof(old) == "function") {
		newHandler = function() {
			try {
				oldHandler();
			} catch (x) {}
			try {
				handler();
			} catch (x) {}
		};
	}
	obj[name] = newHandler;
}

window.embDebugSession = EmbUtils.prototype.createDebugConsole = function createDebugConsole () {
	if (debugConsole.isDummy) {
		debugConsole = {
			_consoleWindow: null,
			embInit: function() {
				if (!this._consoleWindow || this._consoleWindow.closed) {
					var win = this._consoleWindow = window.open("/mt.html", "embDebugConsole", "left=10,top=10,width=500,height=500,toolbar=no,location=no,scrollbars=yes,resizable=yes");
					win.blur();
/*
					var doc = win.document;
					var body = doc.body;						
					var div = doc.createElement("div");
					div.appendChild(doc.createTextNode("*"));
					body.appendChild(div);
*/
				}
			},
			
			_log: function(args) {
				this.embInit();
				for (var i = 0; i < args.length; ++i) {
					var doc = this._consoleWindow.document;
					var div = doc.createElement("div");
					div.appendChild(doc.createTextNode(args[i]));
					doc.body.appendChild(div);
				}
			},
			log:   function() { this._log(arguments); },
			debug: function() { this._log(arguments); },
			print: function() { this._log(arguments); }
		};
		window.console = debugConsole;
	} else {
		debugConsole.log("embDebugSession(): reuse existing console");
	}
}

var _embUtils;
var embUtils = window.embUtils = function () {
	if (!_embUtils) {
		_embUtils = new EmbUtils();
	}
	return _embUtils;
}


// --- DOM utilities

/* browser handling inspired by / copied from jQuery */

var userAgent = navigator.userAgent.toLowerCase();

// Figure out what browser is being used
var browser = {
	version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
	mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent ),
	safari: /webkit/.test( userAgent ),
	opera: /opera/.test( userAgent ),
	msie: /msie/.test( userAgent ) && !/opera/.test( userAgent )
};

var styleFloat = browser.msie ?
	"styleFloat" :
	"cssFloat";

	// Check to see if the W3C box model is being used
var boxModel = !browser.msie || document.compatMode == "CSS1Compat";

var browserMapping;
if (browser.msie) {
  browserMapping = {
  	"class":       ".className",
	"for":         ".htmlFor",
	"float":       ".styleFloat",
	"cssFloat":    ".styleFloat",
	"styleFloat":  ".styleFloat",
	"readonly":    "readOnly",
	"maxlength":   "maxLength",
	"cellspacing": "cellSpacing",
    "style":       ".style.cssText"
  };
} else {
  browserMapping = {
	"float": ".cssFloat",
	"cssFloat": ".cssFloat",
	"styleFloat": ".cssFloat"
  };
}

var _isDomObj = function(x) {
	return (!!x["nodeType"]);
}

var _isString = function(x) {
	return "string" == typeof(x);
}


// non-html-tag methods have an underscore to mark them as support methods, 
// everything else should just be named like the corresponding html tag
var DOM = {
	_flatten1: function(args) {
		var replacement = undefined;
		// check whether we have any array elements:
		for (var i = 0; i < args.length; ++i) {
			var ai = args[i];
			if (ai && ai["length"] && ai[ai.length-1] && !_isDomObj(ai) && !_isString(ai)) { 
				// it's array-like, but not a string or DOM object
				replacement = new Array();
				break;
			}
		}
		if (replacement) {
			// flatten out the first level of arrays (and array-like objects), leave out undefined entries
			for (var i = 0; i < args.length; ++i) {
				var ai = args[i];
				if (ai && ai["length"] && ai[ai.length-1]) {
					for (var j = 0; j < ai.length; ++j) {
						replacement[replacement.length] = ai[j];
					}
				} else if (ai) {
					replacement[replacement.length] = ai;
				}
			}
			return replacement;
		}
		return args;
	},

	_add: function(elem, args) {
		args = this._flatten1(args);
		for (var i = 0; i < args.length; ++i) {
			var x = args[i];
			var tx = typeof(x);

			if (tx == "undefined" || null == x) {
				// ignore undefined entries
			} else if (tx == 'object' && _isDomObj(x)) {
				elem.appendChild(x);
			} else if (tx == 'object') {
				// add all properties of x into tag, either as direct property or as an attribte
				for (var z in x) {
					var y = browserMapping[z] || z;
					if (y.substr(0,1) == ".") {
						// forced assignment to a direct property (e.g. .innerHTML)
                        if (-1 < y.indexOf(".", 1)) {
                            eval("elem"+y+"='"+x[z]+"';");
                        } else {
                            elem[y.substr(1)] = x[z];
                        }
					} else if (y.substr(0,2) == "on" && "function" == typeof(x[z])) {
						// onxxx handler
						elem[y] = x[z];
					} else {
						elem.setAttribute(y, x[z]);
					}
				}
			} else if (tx == 'string') {
				var tn = document.createTextNode(x);
				elem.appendChild(tn);
			}
		}
	},
	_createElement: function(t, o) {
		var elem;
		if (o && o["name"] && !_isDomObj(o)) {
			// try the special IE method		
			try {
				elem = document.createElement('<'+t+' name="'+o["name"]+'" >');
				if (!elem.name) {
					elem = null;
				}
			} catch (e) {
			}
		}
		if (!elem) {
			elem = document.createElement(t)
		}
		return elem;
	},

	_make_tagfun: function(t){
		this[t] = function() {
		    var result = this._createElement(t, arguments[0]);
			this._add(result, arguments);
			return result;
		};
	},

	append2DOM: function() {
		var html = "";
		var args = this._flatten1(arguments);
		var elem = args[0];
		for (var i = 1; i < args.length; ++i) {
			if(elem) {
				elem.appendChild(args[i]);
			}
		}
	},
	set2DOM: function() {
		var args = this._flatten1(arguments);
		var elem = args[0];
		while (elem.childNodes.length) {
			elem.removeChild(elem.childNodes[0]);
		}
		this.append2DOM(args);
	}
};

(function(){
	var tags = "a|p|div|span|ol|ul|li|dl|dt|dd|input|select|button|label|img|script|style|form|iframe".split("|");
	for (var t in tags) {
		DOM._make_tagfun(tags[t]);
	}
})();

window.embUtils().dom = function() { return DOM; }

// --- layergroup handling

function LayerGroup(layerGroupDOM) {
	if (layerGroupDOM) {
		var children = layerGroupDOM.getElementsByTagName("div");
		this.children      = children;
		this.coverLayer    = children[0];
		this.dialogLayer   = children[1];
		this._element      = layerGroupDOM;
	}
}

LayerGroup.prototype.equals = function(that) {
	if (that) {
		return this._element == that._element;
	}
	return false;
}

function x$(x) {
	return document.getElementById(x);
}

function xheight(x) {
	if (x$(x) && x$(x).offsetHeight) {
		return x$(x).offsetHeight;
	}
	return 0;
}

function isNumber(x) {
  try {
    var n = Number(x);
    return (!!n);
  } catch (e) {
    return false;
  }
}

// primitives: html / dhtml element manipulation
EmbLayerManager.prototype.primitives = {
	init: function(id) {
		this.elem = x$(id);
		embUtils().addHandler(window, "onresize", updateLayerPositions);
		embUtils().addHandler(window, "onscroll", updateLayerPositions);
	},

	n:0,

	newLayerGroup: function() {
		var zBase = 2001+this.n;
		this.n += 4;

		var coverLayer = DOM.div({"class":"embCoverLayer"});

		coverLayer.style.height  = embUtils().fullHeight(window.document) + "px";
		coverLayer.style.zIndex = (zBase+1);
		var dialogLayer = DOM.div({"class":"embDialogLayer"});
		dialogLayer.style.display = "none";
		dialogLayer.style.zIndex = (zBase+2);
		
		var newDiv = DOM.div({"class":"embLayerGroup", "id":"embLayerGroup"},
			coverLayer,
			dialogLayer
		);
		
		// TODO: n should be derived from currentLayerGroup?
		newDiv.style.zIndex = zBase;
		
		DOM.append2DOM(this.elem, newDiv);
		
		return new LayerGroup(newDiv);
	},

	currentLayerGroup: function() {
		var lastChild;
		if(this.elem) {
			lastChild = this.elem.lastChild;
		}
		return lastChild ? new LayerGroup(lastChild) : undefined;
	},

	removeLayerGroup: function(layerGroup) {
		
//debugConsole.log("remove layer group: "+embUtils().debugString(layerGroup));
		
		this.elem.removeChild(layerGroup._element);
	}
};

var setSelectVisibility = function(vis, base) {
    base = base && base._element || document;

	if (browser.msie && 0 == browser.version.indexOf("6")){
		vis = vis && "visible" || "hidden";
		selects = base.getElementsByTagName("select");
		for(var i=0 ;i < selects.length; i++){
			selects[i].style.visibility = vis;
		}
	}
}

var jsPattern = /^\s*javascript:([\w\W]*)$/;

var makeAction = function(a) {
	if (!a) { 
		return function(){} 
	} else if (typeof(a) == "function") { 
		return a; 
	} else {
		var m = jsPattern.exec(a);
		if (m) {
			try {
				return new Function(m[1]);
			} catch (e) {
				debugConsole.log(e +" in " + m[1]);
				return function(){} 
			}
		} else {
			return function() { 
				window.location.href = a; 
			};
		}
	}
}

// --- notification styles: one function per style, style name is function name
EmbLayerManager.prototype.notifications = {
	_button: function(name, props, action) {
		var options = props[name];
		var label   = (options && options.length > 1 && options[1]) ? options[1] : embGetLayerManager().getText(name); 
		var action  = (options && options.length > 0 && options[0]) ? options[0] : action;
		action = makeAction(action);
		return DOM.div({"class":"button"},
			DOM.a({href:"#",onclick:action},
				DOM.div(label)
			)
		);
	},
	_ok_cancel_dialog: function(msg, props, closeAction, hasOk, hasCancel, hasOptions, hasLinklist) {
		if (!props) props = {};

		if (!closeAction) {
			closeAction=function(){embGetLayerManager().closeLayer();};
		}
		var domOptions = null;
		if (hasOptions) {
			var radios = [];
			var elems = [];
			var actions = {};
			var rname = "lyopt"+(Math.round(Math.random()*3456));
			for (var i in props.options) {
				var opt = props.options[i];
				var id = rname+"_"+i;
				radios[i] = DOM.input({type:"radio","name":rname,id:id,".value":"v"+i});
				elems[i] = DOM.li(radios[i], DOM.label({"for":id}, opt.text));
				actions[id] = makeAction(opt.action);
			}
			if (radios.length) {
			    var form = DOM.form({name:"optionsForm",action:"#",method:"POST"},DOM.ul(elems));
				domOptions = DOM.div({"class":"options"}, form);
				var runChoice = function() {
					for (var i in radios) {
						var thisOne = radios[i];
						if (thisOne.checked) {
							actions[thisOne.id]();
							return true;
						}
					}
					return false;
				};
				if (!props.ok) {
					props.ok=[runChoice];
				} else {
					var oldAction = makeAction(props.ok[0]);
					props.ok[0] = function() {
						if (!runChoice()) {
							oldAction();
						}
					}
				}
			}
		}

		var buttons = new Array();
		if (hasOk)     { buttons[buttons.length] = this._button("ok", props, closeAction); }
		if (hasCancel) { buttons[buttons.length] = this._button("cancel", props, closeAction); }
		
		var domLinklist = null;
		if (hasLinklist) {
			var links = [];
			for (var i in props.options) {
				var opt = props.options[i];
				links[links.length] = DOM.li(DOM.a({href:opt.href},opt.text));
			}
			if (links.length) {
				domLinklist = DOM.div({"class":"links"}, DOM.ul(links));
			}
		}

		return [
			DOM.div({"class":"content", ".innerHTML":msg}),
			domLinklist,
			domOptions,
			DOM.div({"class":"buttons"}, buttons)
		];
	},
	ok: function(msg, props, closeAction) {
		return this._ok_cancel_dialog(msg, props, closeAction, true, false, false, false);
	},
	ok_cancel: function(msg, props, closeAction) {
		return this._ok_cancel_dialog(msg, props, closeAction, true, true, false, false);
	},
	ok_cancel_options: function(msg, props, closeAction) {
		return this._ok_cancel_dialog(msg, props, closeAction, props.ok, props.cancel, true, false);
	},
	linklist: function(msg, props, closeAction) {
		return this._ok_cancel_dialog(msg, props, closeAction, props.ok, props.cancel, false, true);
	},
	progress: function(msg, props, closeAction) {
		return [ 
			DOM.div({"class":"progress"},
				DOM.img({src:"/css/css_ng/layer/loadingAni.gif"})
			),
			DOM.div({"class":"progressContent", ".innerHTML":msg})
		];
	}
	
};

function _addOnload(f, before) {
	var onload = window.onload;
	window.onload = function() {
		if (before) {
		  f();
		}
		if (onload) {
			onload();
		}
		if (!before) {
		  f();
		}
	}
}

// public methods
EmbLayerManager.prototype.initDiv = function() {
	document.write('<div id="embLayerCollection"></div>');
	var me = this;
	_addOnload(function(){me.init()});
};

EmbLayerManager.prototype.init = function(id) {
	if (!id) id = 'embLayerCollection';
	this.primitives.init(id);
};

EmbLayerManager.prototype.getText = function(t) {
  var r = this._textMap[t];
  if (!r) {
    r = t+' <span title="missing replacement text">*</span>';
  }
  return r; 
}

EmbLayerManager.prototype.addTextMap = function(m) {
  for (i in m) {
    this._textMap[i] = m[i];
  }
}

EmbLayerManager.prototype.openProgress = function(style, msg, icon, props) {
	props = props || {};
	if (icon) props.icon = icon;
	this.openNotification("progress", msg, props);
};
EmbLayerManager.prototype.closeProgress = function() {
	this.closeLayer();
};


function styleOptions(style, width) {
	var result = {"class":style};
    
    if (width) {
        result["style"] = "width:" + width + "px;"
                        + "margin-left:" + Math.max(Math.round(-width/2),-480) + "px;";
    }

	return result;
}

EmbLayerManager.prototype._createFrame = function(style, html, title, closeAction, width) {
	var closePart = undefined;
	if (closeAction) {
		var me = this;
		closeAction = makeAction(closeAction);
		var closeFunction = function() {
			var currentLayer = me.primitives.currentLayerGroup();
			closeAction();
			if (currentLayer.equals(me.primitives.currentLayerGroup())) {
				me.closeLayer();
			}
			return false; // never evaluate href-target of closebutton-link.
		};
		theHref = location.href;
		idx = theHref.indexOf("lyUrl");
		if(idx!=-1) {
			theHref = theHref.substr(0,idx-1);
		}
		var closeArgs = {"class":"close", href:''+theHref, onclick:closeFunction };
		
		closePart = DOM.a(closeArgs);
	}

	var parts = [];
	parts[parts.length] = DOM.div({"class":"title"}, DOM.div({"class":"titleC"}, DOM.div(title), closePart));
	if (typeof(html) == 'string') {
		parts[parts.length] = DOM.div({"class":"contents"}, DOM.div({"class":"contentsC", ".innerHTML":html}));
	} else { // assume html consists of dom or text objects
		parts[parts.length] = DOM.div({"class":"contents"}, DOM.div({"class":"contentsC"}, html, DOM.div({"class":"contentsE"})));
	}
	//parts[parts.length] = DOM.div({"class":"bottom"}, " ", DOM.div({"class":"bottomC", ".innerHTML":"&nbsp;"}));
    parts[parts.length] = DOM.div({"class":"bottom"}, DOM.div({"class":"bottomC"}));
	
	return DOM.div(styleOptions(style, width), parts);
};

function evalScripts(scripts) {
    for (i in scripts) {
		var s = scripts[i];
//debugConsole.log("going to eval: " + s);
		try {
            eval(s);
		} catch (e) {
	        debugConsole.log("error in eval: " + e + " evaluating [["+s+"]]");
	        //if (browser.msie) {
			//	alert("error in eval: " + e + " evaluating [["+s+"]]");
	        //}
		}
    }
}

function extractScripts(html) {
	var result = {html:html, script:[]};

	// Extract JavaScript code. We want to execute all embedded Javascript
	// after the HTML has been added to the DOM
	try {
        var pattern = /<script[^>]*>([\w\W]*?)<\/script>/gi;
		var m;
        while (m = pattern.exec(html)) {
			var s = m[1];
			s = s.replace(/^\s*<!--/, "");
            result.script[result.script.length] = s;
        }

        if (typeof(html.replace) == "function") {
	        // Replace JavaScript code in result document
	        result.html = html.replace(pattern, "");
        }

	} catch (e) {
        debugConsole.log("error in extractScripts: " + e);
	}
	return result;
}

function getScrollHeight()
{
   var h = window.pageYOffset ||
           document.body.scrollTop ||
           document.documentElement.scrollTop;
           
   return h ? h : 0;
}

var dialogs = [];

function updateLayerPositions() {
	var vsz = embUtils().viewSize(document);
	var fh = jQuery(document).height();
	var sh = getScrollHeight();

	for (i in dialogs) {
		var d = dialogs[i];
		var cn = d.childNodes[0];
		var oh = jQuery(cn).height() + 27;

debugConsole.log("div ="+cn+" class="+cn.getAttribute("class")+" oh="+oh+" vsz="+embUtils().debugString(vsz));

		if (oh) {
			var top = Math.min(vsz.ech - oh,32);
			if (top >= 0) {
debugConsole.log("top="+top+" sh="+sh);
				d.style.top = sh+top+"px";
			} else {
				var relPos = sh / (fh - vsz.ech);
				var top = sh - relPos * (oh - vsz.ech);
debugConsole.log("rp="+relPos+" top="+top+" sh="+sh);
				d.style.top = Math.round(top)+"px";
			}
		}
	}
}

function _index(a, e) {
	for (i in a) {
		if (a[i] === e) {
			return i;
		}
	}
	return null;
}

function _contains(a, e) {
	return (null != _index(a, e));
}

function _add(a, e) {
	if (!_contains(a,e)) {
		a[a.length] = e;
	}
}

function _remove(a,e) {
	var i = _index(a,e);
	var nl = a.length-1;
	if (i && i != a.length-1) {
		a[i] = a[nl];
	}
	a.length = nl;
	
}

EmbLayerManager.prototype._setLayer = function(layerGroup, layout, html, title, closeAction, width) {
	var dialogLayer = layerGroup.dialogLayer;

	var separatedHTML = extractScripts(html);

	DOM.set2DOM(dialogLayer, this._createFrame(layout, separatedHTML.html, title, closeAction, width));
	dialogLayer.style.display = 'block';
	//scrollCheckInterval = setInterval(function() { setScrollPosition(dialogLayer); },300);

	evalScripts(separatedHTML.script);

	_add(dialogs, dialogLayer);
	updateLayerPositions();
}

var closeHooks = [];

EmbLayerManager.prototype.showLayer = function(layout, html, title, closeAction, width) {
	setSelectVisibility(false, this.primitives.currentLayerGroup());

    closeHooks[closeHooks.length] = null;
	var layerGroup = this.primitives.newLayerGroup();
	this._setLayer(layerGroup, layout, html, title, closeAction, width);
};

EmbLayerManager.prototype.replaceLayer = function(layout, html, title, closeAction, width) {
    closeHooks[closeHooks.length - 1] = null;
	var layerGroup = this.primitives.currentLayerGroup();
	this._setLayer(layerGroup, layout, html, title, closeAction, width);
};

EmbLayerManager.prototype.setLayerCloseHook = function(hook) {
    if ("function" != typeof(hook)) {
        debugConsole.log("unsupported hook type in setLayerCloseHook: "+typeof(hook));
    }
    closeHooks[closeHooks.length - 1] = hook;
}

EmbLayerManager.prototype.closeLayer = function(force) {
	var layerGroup = this.primitives.currentLayerGroup();

	if (layerGroup && closeHooks[closeHooks.length - 1] && !force) {
        var x = closeHooks[closeHooks.length - 1];
        closeHooks[closeHooks.length - 1] = null;
        if (!x()) {
            layerGroup = null;
        }
    }
	if (layerGroup) {
		layerGroup.dialogLayer.style.display = "none";
		this.primitives.removeLayerGroup(layerGroup);

		setSelectVisibility(true, this.primitives.currentLayerGroup());
		//clearInterval(scrollCheckInterval);
		
		if (dialogs && dialogs.length > 0 ) {
			_remove(dialogs, layerGroup.dialogLayer);
		}
		
        closeHooks.length = closeHooks.length - 1;

		return true;
	}
	return false;
};

EmbLayerManager.prototype.openNotification = function(style, msg, props) {
	props = props || {};
    if (!this.notifications[style]) {
		style="ok";
		msg = msg + "\r\n\r\n(unknown notification style: "+style+")";
	}

	var html = this.notifications[style](msg, props);

	var clientAction = null;
	if (props.closeAction) {
		clientAction = props.closeAction;
	}
	if (!clientAction && props.cancel && props.cancel[0]) {
		clientAction = props.cancel[0];
	}
	if (!clientAction && ("ok" == style) && props.ok && props.ok[0]) {
		clientAction = props.ok[0];
	}
	this.showLayer("notification", html, props["title"], clientAction);
};

function xmltext2dom(text) {
	if (window.ActiveXObject)
	{
	   var xml = new ActiveXObject("Microsoft.XMLDOM");
	   xml.loadXML(text);
	}  else if (document.implementation)
	{
	   var xml = (new DOMParser()).parseFromString(text, "text/xml");
	}
	return xml;
};

EmbLayerManager.prototype._handleReadyStateChange = function (status) {
debugConsole.log("readystate: "+status);
	if (status == 2) {
	}
};

EmbLayerManager.prototype._handleData = function (status, data, param, type, statusmsg, layerfun) {
	if(status == AJAXConnector.SUCCID_LOAD) {
		var doc = data;
		if (type == AJAXConnector.RESPONSE_TEXT) {
			doc = xmltext2dom(data);
		}
		this._processResponse(doc, layerfun);
	} else {
		debugConsole.log(statusmsg+" "+data);
		this.closeProgress();
		this.openNotification("ok", this.getText("server_error"));
	}
};

function unpackContents(element) {
  var result = null;
    
  var child = element.firstChild;
  
  while (child) {
  	var cnn = child.nodeName;
  	if (cnn == "#text" || cnn == "#cdata-section") {
  		if (!result) result = child.nodeValue;
  		else         result += child.nodeValue;
  	} else {
  		debugConsole.log("unexpected node type in unpackContents: "+cnn);
  	}
  	child = child.nextSibling;
  }
  
  return result;
}

EmbLayerManager.prototype._processResponse = function (doc, layerfun) {
	var layer = doc.documentElement;
	if (layer) {
		var head = layer.getElementsByTagName("head");
		var body = layer.getElementsByTagName("body");
		var script = layer.getElementsByTagName("script");


		var redirected = false;
		var onload = layer.getElementsByTagName("onload");
		if (onload) {
			for (var i = 0; i < onload.length; ++i) {
				var onloadFunction = unpackContents(onload[i]);
				if (onloadFunction) {
					try {
						eval(onloadFunction);
						redirected = true;
					} catch (exception) {
						this.closeProgress();
						/*this.openNotification("ok", this.getText('server_error')+'<br><br>'+debugString(exception)+'<br><br>'+onloadFunction);*/
						this.openNotification("ok", this.getText('server_error'));
						return;
					}
				}
			}
		}

		if (!head || 1 !== head.length 	|| !body || 1 !== body.length) {
			this.closeProgress();
			if (!redirected) {
				this.openNotification("ok", "<div>Got bad response: "+doc+"</div>");
			}
		} else {

//debugConsole.log("body: "+body[0]);

			var bodyContents = body[0].childNodes;
//debugConsole.log("bodyContents: "+bodyContents);
			var bcn = bodyContents[0].nodeName;
			if (bcn == "#cdata-section") {
				bodyContents = bodyContents[0].data;
//debugConsole.log("bodyContents: unpacked cdata ("+bcn+")"+embUtils().debugString(bodyContents));
			}
			
//debugConsole.log("bodyContents: "+bodyContents);
			
			// handle flash
			// console.log("checking flash");
			var flashConstraint = head[0].getElementsByTagName("flash");
			// console.log(flashConstraint);
			if(flashConstraint[0]) { // the layer content requires flash
				var flashMinVersion = flashConstraint[0].getAttribute('min_version');
				// console.log("minimum flash version: " + flashMinVersion);
				var isFlashAvailable = flash_versioncheck(flashMinVersion);
				if(!isFlashAvailable) {
					this.closeProgress();
					this.openNotification("linklist", this.getText("multimedialayerfallbacktext"), {
						closeAction:function(){},
						ok: [null, "close"],
						title: this.getText("multimedialayerfallbackwintitle"),
						options: [ { href: this.getText("multimedialayerfallbackextlink"), text: this.getText("multimedialayerfallbacklinktext") }]
					});
					return;
				}
			}
			// end: handle flash
			
			var title = head[0].getElementsByTagName("title");
			var titleContents = "";
			if (title && 1 <= title.length) {
				titleContents = unpackContents(title[0]);
			}
			var layout = head[0].getElementsByTagName("layout");
			var layoutContents = "";
			if (layout && 1 <= layout.length) {
				layoutContents = unpackContents(layout[0]);
			}

			var width = head[0].getElementsByTagName("width");
			var widthContents = undefined;
			if (width && 1 <= width.length) {
			    try {
			        widthContents = 5+parseInt(unpackContents(width[0]));
                } catch (e) {
                    debugConsole.log("Not a valid width: "+e);
                }
			}

			var closeAction = head[0].getElementsByTagName("close-action");
			var closeActionContents = "";
			if (closeAction && 1 <= closeAction.length) {
				closeActionContents = unpackContents(closeAction[0]);
			}

			var styles = head[0].getElementsByTagName("style");
			var scripts = head[0].getElementsByTagName("script");

			var headRef = document.getElementsByTagName("head").item(0);
			var fileref = "";

			var numStyles = styles.length;
			//alert("Number of styles = " + numStyles);
			for (styleIndex = 0; styleIndex < numStyles; styleIndex++) {
				//alert("Style = " + styles[styleIndex].firstChild.nodeValue);
				fileref = document.createElement("link");
				fileref.setAttribute("rel", "stylesheet");
				fileref.setAttribute("type", "text/css");
				fileref.setAttribute("href", styles[styleIndex].firstChild.nodeValue);
				headRef.appendChild(fileref);
			}

			var numScripts = scripts.length;
			//alert("Number of scripts = " + numScripts);
			for (scriptIndex = 0; scriptIndex < numScripts; scriptIndex++) {
				//alert("Script = " + scripts[scriptIndex].firstChild.nodeValue);
				fileref = document.createElement('script')
				fileref.setAttribute("type","text/javascript");
				fileref.setAttribute("src", scripts[scriptIndex].firstChild.nodeValue);
				headRef.appendChild(fileref);
			}
			
			
			// force new layer if set body attribute forceNewLayer			
			var forceNewLayer=false; 				
			if(body && body.length > 0) {
				var attr=body[0].getAttribute("forceNewLayer");
				if(attr && attr == "true" ){
				    var me=this;
	    			layerfun=function(a,b,c,d,e) {me.showLayer(a,b,c,d,e)}
				}
			}
			
			this.closeProgress();
			layerfun(layoutContents, bodyContents, titleContents, closeActionContents, widthContents);
		}

	}

};

EmbLayerManager.prototype._loadLayer = function(layerfun, source, props) {
	props = props || {};

    // use AjaxConnector
    var connector = new AJAXConnector();
 	
	var ts = typeof(source);
	var me = this;
	if (ts == 'string') {
		
		if(!props.silentLoading) {
			connector.registerProgressHandler( function(status) {
				me._handleReadyStateChange(status);
			});
		}
		connector.registerDataHandler( function(status, data, param, type, statusmsg) {
			me._handleData(status, data, param, type, statusmsg, layerfun);
		});
		var method = AJAXConnector.REQUEST_GET;
		var content = "";
		if(props.method) {
			if (props.method == "POST" || props.method == "post") {
				method = AJAXConnector.REQUEST_POST;
				
				var pvt = typeof(props.vars);
				if (pvt == "object") {
					content = "";
					for (i in props.vars) {
						content += i;
						content += '=';
						content += encodeURIComponent(props.vars[i]);
						content += '&';
					}
				} else if (pvt == "string") {
					content = encodeURI(props.vars);
				} else {
					debugConsole.log("unexpected type in props.vars: "+ pvt);
				}
				
				var charset = document.characterSet || "utf-8";
				props.headers = props.headers || {};
				props.headers["Content-Type"] = "application/x-www-form-urlencoded;charset="+charset;
			} else if (props.method == "HEAD" || props.method == "head") {
				method = AJAXConnector.REQUEST_HEAD;
			}
		}

		if (props.bp) {
			props.headers = props.headers || {};
			props.bu = props.bu || window.location.href;

			props.headers["X-Bypass-Path"] = props.bp;
			props.headers["X-Base-Url"] = props.bu;
			if (0 == props.bu.indexOf("https://")) {
				props.headers["X-Other-Protocol"] = props.bu;
			}
			if (props.be) props.headers["X-Bypass-Encoding"] = props.be;
		}

		if(!props.silentLoading) {
			var progressMsg = props.progressMsg || this.getText("loading");
			this.openProgress("", progressMsg);
		}

		connector.sendRequest(source, content, method, null, props.headers);
		
	} else {
		throw new LayeringException("Illegal argument: source must be string, not '"+ts+"'");
	}

};

EmbLayerManager.prototype.loadNewLayer = function(source, props) {
	var me = this;
	return this._loadLayer(function(a,b,c,d,e) {me.showLayer(a,b,c,d,e)}, source, props);
};

EmbLayerManager.prototype.loadIntoLayer = function(source, props) {
	var me = this;
	return this._loadLayer(function(a,b,c,d,e) {me.replaceLayer(a,b,c,d,e)}, source, props);
};


EmbLayerManager.prototype.maybeOpenNamedLayer = function(layerlinks) {
debugConsole.log('maybeOpenNamedLayer'+layerlinks);


	var me = this;
	var f = function() {
		window.setTimeout(function(){me.openNamedLayer(layerlinks)}, 200);
	}
	_addOnload(f);
}

EmbLayerManager.prototype.openNamedLayer = function(layerlinks) {
debugConsole.log('openNamedLayer'+layerlinks);
	var layerKey = getLocationHash(location);
	if (layerKey && layerKey.indexOf("#layer_") == 0) {
		layerKey = layerKey.substr(1);

		var layerParams = '';
		var qmark = layerKey.indexOf("?");
		if (qmark && qmark != -1) {
			layerParams = layerKey.substring(qmark);
			layerKey = layerKey.substring(0, qmark);
		}
		
		var layerUrl = null;
		var layerBypass = null;
		var layerlink = layerlinks[layerKey];

		if (!layerlink) {
			for (k in layerlinks) {
				if (k.indexOf(layerKey) == 0) {
					layerlink = layerlinks[k];
					break;
				}
			}
		}

		if (!layerlink) {
			layerlink = getLocationHash(location).substring("#layer_".length).split('|');
		}

		if (layerlink && 2 <= layerlink.length) {
			layerUrl    = layerlink[0];
			layerBypass = layerlink[1];
		}
		
		if (layerParams && layerUrl) {
			if (-1 == layerUrl.indexOf('?')) {
				layerUrl += layerParams;
			} else {
				layerUrl += '&' + layerParams.substring(1);
			}
		}

		if (layerUrl) {
			debugConsole.log("Opening layer: " + layerUrl + " " + layerBypass);
			var params = new Array();
			params["bp"] = layerBypass;
			window.embGetLayerManager().loadNewLayer(layerUrl, params);
		}
	}
}

EmbLayerManager.prototype.setUrlWithNamedLayer = function(layerlinks, namedLayer, host, newSelectors, obsoleteSelectors) {

	var loc = window.location.href;
	
	// maybe set a different host (for protocol switch)
	if (host && host.length > 0 && !loc.indexOf(host) == 0) {
		var index = loc.indexOf("://");
		index = loc.indexOf("/", index + 3);
		loc = host + loc.substring(index);
	}
	
	var indexOfFileextension = -1;
	
	// Insert selectors before file extension.
	if (newSelectors && newSelectors.length > 0) {
		if (typeof(newSelectors) == "string") {
			newSelectors = [newSelectors];
		}
		indexOfFileextension = findIndexOfFileextension(loc);
		for (i = 0; i < newSelectors.length; i++) {
			var sel = newSelectors[i];
			if (sel.charAt(0) != '.') {
				sel = '.' + sel;
			}
			if (sel.charAt(sel.length - 1) == '.') {
				sel = sel.substring(0, sel.length - 1);
			}
			var testindex = loc.indexOf(sel + '.');
			if (testindex != -1 && testindex < indexOfFileextension) {
				// already present, skip this one.
				continue;
			} 
			loc = loc.substring(0, indexOfFileextension) + sel + loc.substring(indexOfFileextension);
			indexOfFileextension = indexOfFileextension + sel.length;
		}
	}
	
	// Remove obsolete selectors:
	if (obsoleteSelectors && obsoleteSelectors.length > 0) {
		if (typeof(obsoleteSelectors) == "string") {
			obsoleteSelectors = [obsoleteSelectors];
		}
		if (indexOfFileextension == -1) {
			indexOfFileextension = findIndexOfFileextension(loc);
		}
		for (i = 0; i < obsoleteSelectors.length; i++) {
			var sel = obsoleteSelectors[i];
			if (sel.charAt(0) != '.') {
				sel = '.' + sel;
			}
			var testindex = loc.indexOf(sel + '.');
			if (testindex != -1 && testindex <= indexOfFileextension - sel.length) {
				loc = loc.substring(0, testindex) + loc.substring(testindex + sel.length, loc.length);
			}
		}
	}
	
	// add named layer
	if (!namedLayer.indexOf('#') == 0) {
		namedLayer = '#' + namedLayer;
	}
	var anchorIndex = loc.indexOf('#');
	if (anchorIndex != -1) {
		loc = loc.substring(0, anchorIndex);
	}
	loc = loc + namedLayer;
	
	var openLayerManually = false;
	var newLocWithoutAnchor = loc.substring(0, loc.indexOf('#'));
	var oldLocWithoutAnchor = window.location.href;
	var testindex = oldLocWithoutAnchor.indexOf('#'); 
	if (testindex != -1) {
		oldLocWithoutAnchor = oldLocWithoutAnchor.substring(0, testindex);
	}
	if (oldLocWithoutAnchor == newLocWithoutAnchor) {
		openLayerManually = true;
	}
	
	window.location.href = loc;
	if (openLayerManually) {
		window.embGetLayerManager().openNamedLayer(layerlinks);
	}
}

var findIndexOfFileextension = function(url) {
	var index = url.indexOf('?');
	if (index == -1) {
		index = url.indexOf('#');
	}
	if (index == -1) {
		index = url.length;
	}
	return url.lastIndexOf('.', index);
}

var getLocationHash = function(location) {
	/* IE6 returns location.hash only up to the next 
	  questionmark. Make sure that we get everything 
	  after #
	*/
	var locHash = location.hash;
	var index = location.href.indexOf(locHash);
	if (-1 != index && index + locHash.length < location.href.length) {
		locHash = location.href.substring(index);
	}
	return locHash;
}

})();


