var common_enableDebug = false;

if((typeof HTMLElement != 'undefined') && HTMLElement.prototype.__defineGetter__ != 'undefined') {
	HTMLElement.prototype.__defineGetter__("innerText", function () {
		var r = this.ownerDocument.createRange();
		r.selectNodeContents(this);
		return r.toString();
	});
}

// kts. http://www.alistapart.com/articles/getoutbindingsituations
function common_createBoundedWrapper(object, method) {
  return function() {
    return method.apply(object, arguments);
  };
}

// abstract mouse button codes between browsers
// returns a 3-bit integer where the bits correspond to buttons like this:
// bit 1:	left button
// bit 2: midde button
// bit 3: right button
function common_resolveButton(aEvent) {
	var mouseButton = 0;
	var myEvent = aEvent ? aEvent : window.event;
	var eWhich = 0;
	var eButton = 0;
	if(myEvent.which) {
		eWhich = myEvent.which;
		// mozilla which-property doesn't support multiple buttons at once, but we don't care, since we don't need to detect those situations
		if(myEvent.which == 1) mouseButton = mouseButton | 1;
		if(myEvent.which == 2) mouseButton = mouseButton | 2;
		if(myEvent.which == 3) mouseButton = mouseButton | 4;
		// should be noted here that firefox seems to return always 1 for mousemove, regardles of the actual button
	} else {
		eButton = myEvent.button;
		if(myEvent.type == "contextmenu") {
			// IE doesnt't set the button property on this one, so we just assume it's right
			mouseButton = mouseButton | 4;
		} else if(myEvent.type == "click") {
			// IE doesnt't set the button property on this one, so we just assume it's left
			mouseButton = mouseButton | 1;
		} else if(myEvent.button) {
			if(myEvent.button & 1) mouseButton = mouseButton | 1;
			if(myEvent.button & 2) mouseButton = mouseButton | 4;
			if(myEvent.button & 4) mouseButton = mouseButton | 2;
		}
	}

	debugPrint("common_resolveButton: type="+myEvent.type+" which="+eWhich+" button="+eButton+" resolved="+mouseButton, "common");

	return mouseButton;
}

/*
	Tekee uniikin ID:n jota ei löydy koko sivun DOM:sta + se on isompi kuin aikaisemmin tehdyt.
*/

function common_generate_uid() {
	var thisDate = new Date();
	var uid = thisDate.getTime();
	var failSafe = 100;
	var exists = document.getElementById("uniq"+uid);
	while(!exists && failSafe) {
		uid++;
		failSafe--;
		exists = document.getElementById("uniq"+uid);
	}

	if(!exists) {
		return "uniq"+uid;
	} else {
		alert("common_generate_uid() failed.");
		return 0;
	}
}

function toggle_display(imageElement, toggleElementId) {
	toggleElement = document.getElementById(toggleElementId);
	if(toggleElement) {
		if(toggleElement.style.display == "none") {
			toggleElement.style.display = "";
			if(imageElement) imageElement.src = imageElement.src.replace(/closed/i,"open");
		} else {
			toggleElement.style.display = "none";
			if(imageElement) imageElement.src = imageElement.src.replace(/open/i,"closed");
		}
	}
}

function IE_PNG_Fix() {
	elementsToFix = new Array();
	elementsToFix[0] = document.getElementById("IE_bugfix1");
	elementsToFix[1] = document.getElementById("IE_bugfix2");
	elementsToFix[2] = document.getElementById("IE_bugfix3");
	elementsToFix[3] = document.getElementById("IE_bugfix4");
	elementsToFix[4] = document.getElementById("IE_bugfix5");
	elementsToFix[5] = document.getElementById("IE_bugfix6");
	elementsToFix[6] = document.getElementById("IE_bugfix7");
	elementsToFix[7] = document.getElementById("IE_bugfix8");

	for(i in elementsToFix) {
		el = elementsToFix[i];
		if(el) {
			// jos elementistä löytyy filter-style, niin ollaan (todennäköisesti) IE:ssä.
			if(el.style.filter) {
				el.style.backgroundImage = "";	// otetaan IE:llä background pois, jotta filter toimii.
			}
		}
	}

}

var activeDoc = null;
var selectionMemory;
var rangeMemory;
var storedSelection = null;

function restoreSelection() {
	debugPrint("restoreSelection()","common");

	if(activeDoc) {
		if(storedSelection) {
			if(storedSelection.select) {
				debugPrint("Selecting storedSelection","common");
				storedSelection.select();
			}
		} else {
			debugPrint("Setting activeDoc active","common");
//			var sel = activeDoc.document.selection;
//			activeRange = sel.createRange();
//			activeRange.select();
			activeDoc.setActive();
		}
	}
}

function storeSelection() {
	debugPrint("storeSelection","common");
	if(activeDoc) {
		var sel = activeDoc.document.selection;
		debugPrint("storeSelection: seltype "+sel.type,"common");
		if(sel.type == "Text") {
			storedSelection = sel.createRange();
			debugPrint("storeSelection: textrange "+storedSelection,"common");
		} else if(sel.type=="Control") {
			storedSelection = sel.createRange();
			debugPrint("storeSelection: controlrange "+storedSelection,"common");
		} else if(sel.type=="None") {
			storedSelection = null;
//			storedSelection = sel.createRange();
			debugPrint("storeSelection: none "+storedSelection,"common");
		}
	}
}

// funktio poistaa editFocuksen.
function loseEditFocus() {
	debugPrint("loseEditFocus()","common");
	if(activeDoc) {
		var sel = activeDoc.document.selection;
		if(sel) {
			if(sel.type == "Control") {
				debugPrint("Control selection emptied","common");
				sel.empty();
			}
		}
	}
}


// kätevä debug-funktio. Näyttää olion kaikki propertyt (tai arrayn keyt/valuet)
function showProps(element, printMethod) {
	var info = "";
	var line;
	var cnt = 0;
	// jos on olemassa showProps-elementti
	// sijoitetaan output siihen, muuten alert
	var el = document.getElementById('showProps');
	if(el) el.innerHTML = "<pre>";

	for(var i in element) {
		cnt++;

		info += i + " = ";
		if(el) el.innerHTML += i + " = ";

		// jotkut täytyy skipata, muuten tulee errori
		line = "";
		if(i != "selectionStart" && i != "selectionEnd")
			line = element[i];

		if(el) {
			el.innerHTML += line + "<br>\n";
		} else {
			info += line + "\n";
		}

		if(cnt==20) {
			// paloitellaan pitkä data useaan alerttiin
			alert(info);
			info = "";
			cnt = 0;
		}
	}

	if(cnt>0) {
		if(el) {
			el.innerHTML += '</pre>';
		} else {
			alert(info);
		}
	}
}

function showPropsInAWindow(element) {
	var info = "";
	var cnt = 0;
	var line = "";

	for(var i in element) {
		cnt++;
		info += i + " = ";

		// jotkut täytyy skipata, muuten tulee errori
		line = "";
		if(i != "selectionStart" && i != "selectionEnd") line = element[i];

		info += line + "\n";
	}
	showTextInAWindow(info);
}

/**
 *	Tällä funktiolla voi printata debug-viestejä.
 *
 *	@param txt Viesti
 *	@param group optionaalinen group, joka viestin printtasi.
 *								Tämän perusteella viesti joko näytetään tai ei näytetä, riippuen siitä onko groupin debuggaus käytössä.
 *								(esim. treeview, treeview_action.. Tämä voi siis olla mitä vaan kooderi on päättänyt tietyn debug-groupin nimeksi)
 *
 *								Eli siis kun teet jotain skriptiä johonkin mokkulaan ja haluat vain siitä mokkulasta debug-viestit näkyviin,
 *								keksi mokkulalle joku nimi, laita skriptin alkuun "var mokkulanNimi_enableDebug = true;",
 *								ja kaikkiin debugPrint() kutsuihin toiseksi parametriksi "mokkulanNimi".
 *								debugPrint näyttää vain ne debug-viestit jotka ovat enabloitu.
 */
function debugPrint(txt, group) {
	// tarkistetaan onko debug-viestien kohde-elementti olemassa (eli js_debug-moodi on päällä)
	var dbg = document.getElementById("js_debug");
	if(! dbg) {
		dbg = parent.document.getElementById("js_debug");
	}
	if(! dbg) return;	// jos ei löydy, pois..

	// tarkistetaan onko kyseisen groupin debuggaus päällä?
	var debugging = false;
	if(!group) {
		debugging = true;
	} else {
		// koitetaan onko "group" itse määritellyt debugin päälle?
		try {
			eval("debugging = "+group+"_enableDebug;");
		} catch(err) {
			debugging = false;
		}
	}

	// groupin debug ei ole päällä
	if(!debugging) return;

	if(dbg.style.display != "block") dbg.style.display = "block";

	var oDiv=document.createElement("div");
	var oTextNode = document.createTextNode(txt);
	oDiv.appendChild(oTextNode);

	dbg.appendChild(oDiv);
	dbg.scrollTop = dbg.scrollTop + 100;
}

function openInWindow(href,target) {
	var dummy = window.open(href,target);
}


function showTextInAWindow(txt) {
	var swin = window.open();
	swin.document.write("<html><head><title>info</title></head><body style='overflow: hidden; padding: 0px; margin: 0px;'><textarea style='width: 100%; height: 100%; padding: 0px; margin: 0px; border: 0px;'>");
	swin.document.write(txt);
	swin.document.write("</textarea></body></html>");
}

function sendErrorReport(txt) {
	txt = "Virheraportti osoitteesta "+document.location.href+":\n--- Virheraportti: ---\n"+txt;
	var errorReportXml = createXMLHttpRequest();
	errorReportXml.open("POST", "index.php",false);
	// vältetään cachetus
	errorReportXml.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
	errorReportXml.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	errorReportXml.onreadystatechange=function() {
		if(errorReportXml.readyState == 4) {
			if(errorReportXml.status == "200") {
				alert(errorReportXml.responseText);
			}
		}
	}
	var postData = "action=errorReport&errorReport-report="+escape(txt);
	if(confirm("Haluatko nähdä lähetettävän raportin ennen lähetystä?")) {
		alert("Seuraavanlainen raportti lähetetään kun painat ok:\n\n"+txt);
	}
	errorReportXml.send(postData);
}


// geneerinen eventin cancel-handler
function cancelEvent(e) {
	if(!e) e = window.event;
	if(e) {
		e.returnValue = false;
		e.cancelBubble = true;
//		e.bubbles = false;
		debugPrint(e.type +" cancelled.","common");
	}
	return false;
}

// pari yleiskäyttöistä funktiota joilla voi chekata jonkun elementin paikan.

// palauttaa elementin y-koordinaatin koko dokumentin ylälaitaan nähden.
function getOffsetTop(elm) {
	var mOffsetTop = elm.offsetTop;
	var mOffsetParent = elm.offsetParent;
	while(mOffsetParent){
		mOffsetTop += mOffsetParent.offsetTop;
		if(mOffsetParent.scrollTop > 0) {
			mOffsetTop -= mOffsetParent.scrollTop;
		}
		mOffsetParent = mOffsetParent.offsetParent;
	}
	mOffsetTop += document.body.scrollTop;
	return mOffsetTop;
}

// palauttaa elementin x-koordinaatin koko dokumentin vasempaan laitaan nähden.
function getOffsetLeft(elm) {
	var mOffsetLeft = elm.offsetLeft;
	var mOffsetParent = elm.offsetParent;
	while(mOffsetParent) {
		mOffsetLeft += mOffsetParent.offsetLeft;
		if(mOffsetParent.scrollLeft > 0) {
			mOffsetLeft -= mOffsetParent.scrollLeft;
		}
		mOffsetParent = mOffsetParent.offsetParent;
	}
	mOffsetLeft += document.body.scrollLeft;
	return mOffsetLeft;
}

function getContentHeight(el) {
	var hgt = 0;
	var childs = el.children;
	for(i in childs) {
		if(childs[i].style) {
				if(childs[i].style.pixelHeight) hgt = hgt + Math.floor(childs[i].style.pixelHeight);
		}
	}
	return Math.floor(hgt);
}

function getContentWidth(el) {
	var hgt = 0;
	var childs = el.children;
	for(i in childs) {
		if(childs[i].style) {
				if(childs[i].style.pixelWidth) hgt = hgt + Math.floor(childs[i].style.pixelWidth);
		}
	}
	return Math.floor(hgt);
}


// etsii annetun elementin sellaisen parentin, jolla on id
function findElementParentWithId(src) {
	var failsafe = 0;
	while(src && failsafe < 20) {
		//debugPrint("findElemId: searching " + failsafe + " id " + src.id,"common");
		if(src.id) return src; // löytyi
		//muuten etsitään ylöspäin
		src = src.parentElement;
		failsafe = failsafe + 1;
	}
	if(failsafe == 20) {
		alert("findElementParentWithId: failsafe 20");
	}
	//ei löytynyt
	return null;
}

// etsii annetun elementin sellaisen parentin, jolla on annettun niminen parametri
function findElementParentWithParam(src, paramName) {
	var failsafe = 0;
	while(src && (failsafe < 20) ) {
//		debugPrint("findElemP: searching ("+src.tagName+") " +src.id+" " + failsafe,"common");
		params = getElementParams(src);
		if(params[paramName]) return src; //löytyi

//		showProps(src);

		src = src.parentNode;
		failsafe = failsafe + 1;
	}
	if(failsafe == 20) {
		alert("findElementParentWithId: failsafe 20");
	}

	//ei löytynyt
	return null;
}

// tällä pääsee eroon ylimääräisistä tagi-parametreistä (expandot)
// eli name parametriin vain samalla lailla kuin esim stylessä "key:value;key:value"
// timo 250408: sallittu välilyönnit, oliko jokin syy miksei saa olla välilyöntejä?
function getElementParams(el) {
	var hash = new Array();
	if(el.id) {
		var elParams = document.getElementById(el.id + '_params');
		if(elParams) {
			// jos elementillä on parametrejä
			var allParams = elParams.innerHTML.replace(/[\n\r]+/, "");
			var params = allParams.split(';');
			for (var i in params) {
				if(params[i]) {
					var keyvalue = params[i].split(':');
					arvo = keyvalue[1];
					if(! arvo) {
						arvo = "true";
					}
					hash[keyvalue[0]] = arvo;
					//debugPrint("param1: " + keyvalue[0] + " = " + arvo,"common");
				}
			}
		} else {
			// ei löytynyt params-diviä
			var expandoList = new Array('context');
			var value;
			for(var exp in expandoList) {
				eval("value = el." + expandoList[exp] + ";");
				hash[expandoList[exp]] = value;
				//debugPrint("param2: " + expandoList[exp] + " = " + value,"common");
			}
		}
	} else {
		// ei ole id:tä
		//alert("debug: getElementParams: elementillä ei ole id:tä");
		var expandoList = new Array('context');
		var value;
		for(var exp in expandoList) {
			eval("value = el." + expandoList[exp] + ";");
			hash[expandoList[exp]] = value;
			//debugPrint("param2: " + expandoList[exp] + " = " + value,"common");
		}
	}
	return hash;
}

// asettaa annetun params-hashin annetun elementin parametreiksi
function setElementParams(el, params) {
	if(! el.id) {
		alert("debug: setElementParams: element has no id");
		// ehkä tässä voisi luoda myös id:n?
		return;
	}
	var elParams = document.getElementById(el.id + '_params');
	if(! elParams) {
		// jos parametri-diviä ei löydy
		// luodaan tyhjä params-elementti
		//<div id="' + el.id + '_params" style="display: none;"></div>
		elParams = document.createElement('DIV');
		elParams.id = el.id + '_params';
		elParams.style.display = 'none';

		// tarvitseeko välttämättä edes liittää bodyyn?
		document.body.appendChild(elParams);
	}
	// debug
	if(! elParams) {
		alert("debug: elParams couldn't be created");
		return;
	}
	// käydään annettu hash läpi ja luodaan uusi params-string
	var allParams = '';
	for (var i in params) {
		if(allParams) {
			allParams = allParams + ';' + i + ':' + params[i];
		} else {
			allParams = i + ':' + params[i];
		}
	}
	elParams.innerHTML = allParams;
}

// pari kätevää konversiofunktiota.

function hexToDec(what) {
	// Hex To Dec
	// parametrissa voi olla alussa "#" tai sitten ei.

	if (what.charAt(0)=="#") what = what.substr(1);
	len = what.length;
	dec = 0;
	base = 16;
	mult = 1;
	for(i=len-1; i>=0; i--) {
		ch = what.charAt(i);
		if(ch == "0") ch = 0;
		if(ch == "1") ch = 1;
		if(ch == "2") ch = 2;
		if(ch == "3") ch = 3;
		if(ch == "4") ch = 4;
		if(ch == "5") ch = 5;
		if(ch == "6") ch = 6;
		if(ch == "7") ch = 7;
		if(ch == "8") ch = 8;
		if(ch == "9") ch = 9;
		if(ch == "a") ch = 10;
		if(ch == "b") ch = 11;
		if(ch == "c") ch = 12;
		if(ch == "d") ch = 13;
		if(ch == "e") ch = 14;
		if(ch == "f") ch = 15;

		dec = dec + ch*(mult);
		mult = mult * base;
	}

	return dec;
}

function decToHex(what,digits) {
	// Dec To Hex
	// palauttaa luvun heksana käyttäen digits-määrän merkkejä. luku palautetaan ilman "#" merkkia tai muita etuliitteitä.
	ret = "";
	while(what>0) {
		nybble = what & 15;
		if(nybble > 9) {
			if(nybble == "10") nybble = "a";
			if(nybble == "11") nybble = "b";
			if(nybble == "12") nybble = "c";
			if(nybble == "13") nybble = "d";
			if(nybble == "14") nybble = "e";
			if(nybble == "15") nybble = "f";
		}
		ret = nybble + ret;
		what = what >> 4;
	}

	if(ret.length<digits) {
		for(i=ret.length; i<digits; i++) ret = "0" + ret;
	}

	return ret;
}

function sqlNow() {
	stamp = new Date();

//	showProps(stamp);

	var sqldate = stamp.getYear();

	var temp;

	temp = (stamp.getMonth()+1).toString();
	while(temp.length<2) temp = "0"+temp;
	sqldate += "-" + temp;

	temp = stamp.getDate().toString();
	while(temp.length<2) temp = "0"+temp;
	sqldate += "-" + temp;

	temp = stamp.getHours().toString();
	while(temp.length<2) temp = "0"+temp;
	sqldate += " " + temp;
	temp = stamp.getMinutes().toString();
	while(temp.length<2) temp = "0"+temp;
	sqldate += ":" + temp;
	temp = stamp.getSeconds().toString();
	while(temp.length<2) temp = "0"+temp;
	sqldate += ":" + temp;

	return sqldate;
}

function common_decodeEmail(data) {
	data = unescape(data);
	var decoded = "";
	var keyIndex = 0;
	for(var i = 0; i < data.length; i++) {
		decoded += String.fromCharCode(data.charCodeAt(i) ^ common_email_unscramble_key.charCodeAt(keyIndex));
		keyIndex++;
		if(keyIndex >= common_email_unscramble_key.length) keyIndex = 0;
	}
	return decoded;
}

// skrollin määrä
function common_getScroll() {
	var scr = {x:0, t:0};
	if(window.pageXOffset !== undefined) {
		scr.x = window.pageXOffset;
		scr.y = window.pageYOffset;
	} else {
		var docEl = document.documentElement, bodyEl = document.body;
		scr.x = (docEl && docEl.scrollLeft || bodyEl && bodyEl.scrollLeft);
		scr.y = (docEl && docEl.scrollTop || bodyEl && bodyEl.scrollTop);
	}
	return scr;
}

// elementin position
function common_getPosition(el) {
	var curleft = curtop = 0;
	if(el.offsetParent) {
		do {
			curleft += el.offsetLeft;
			curtop += el.offsetTop;
		} while (el = el.offsetParent);
	}
	return {'x':curleft, 'y':curtop};
}

function common_getOffset(el) {
	return {'x':el.offsetLeft, 'y':el.offsetTop};
}

function common_getSize(el) {
	return {'width':el.offsetWidth, 'height':el.offsetHeight};
}


function common_getMousePosition(event) {
	if (event.pageX == null && event.clientX != null ) {
		var scroll = {x:0, t:0};
		var docEl = document.documentElement, bodyEl = document.body;
		event.pageX = event.clientX + (docEl && docEl.scrollLeft || bodyEl && bodyEl.scrollLeft);
		event.pageY = event.clientY + (docEl && docEl.scrollTop || bodyEl && bodyEl.scrollTop);
	}
	return {'x':event.pageX, 'y':event.pageY};
}


/**
 *	Seuraavat funktiot tekevät parhaansa selvittääkseen selaimen käytettävissä olevan pikselikoon.
 *	Tämä siis on näkyvä alue, eli selaimen ikkunan koko - käyttöliittymän elementit
 */
function common_getClientArea() {
	var area = {"width":0, "height":0};
	if(typeof( window.innerWidth ) == 'number') {
		area.width = window.innerWidth;
		area.height = window.innerHeight;
	} else {
		var docEl = document.documentElement, bodyEl = document.body;
		area.width =  (docEl && docEl.clientWidth || bodyEl && bodyEl.clientWidth);
		area.height = (docEl && docEl.clientHeight || bodyEl && bodyEl.clientHeight);
	}
	return area;
}

function common_getInnerWidth() {
	var innerSize = common_getClientArea();
	return innerSize.width;
}

function common_getInnerHeight() {
	var innerSize = common_getClientArea();
	return innerSize.height;
}




function json_handleEvalError(request, err) {
	var txt = "eval() ei onnistunut.\n";

	for(var e in err) {
		txt + e + ": " + err[e] + "\n";
	}

	var sHeaders = request.getAllResponseHeaders();
	for(var h in sHeaders) {
		txt + h + ": " + sHeaders[h] + "\n";
	}

	// kerätään mahdolliset reportit talteen
	var regString = '<!-- <reports> -->([^\000]*?)<!-- </reports> -->';
	var rx = new RegExp(regString, "mig");
	var reports = rx.exec(request.responseText);
	if(reports) {
		txt += reports[0]+"\n";
	}

	txt += "\nPaina ok nähdäksesi koko responseTextin.";
	if(confirm(txt)) {
		showTextInAWindow(request.responseText);
	}
	return true;
}
