/*
All source code (HTML, JS, CSS) involved in the rendering of this website/course is Copyright © 2006-2007 CaT Concepts and Training GmbH.
All rights reserved.

You are not allowed to copy, change or use source code from this website/course without first obtaining written permission.
All violations will be prosecuted to the fullest extent of the law.
*/


var indexed_char = new Array("|",":",";","&","#","=","_");
var chars = indexed_char.join("<<, >>");

var INSERT_USER_NAME=unescape("Bitte geben Sie einen Benutzernamen ein");
var PASS_CORRECT=unescape("Passwort korrekt!");
var PASS_INCORRECT=unescape("Falsches Passwort");
var USER_DOESNT_EXIST="Sie melden sich zum ersten Mal mit diesem Benutzernamen an. Bitte fuellen Sie die folgenden Felder aus.";
var PASS_VALIDATION_FAILED=unescape("Die Passwörter stimmen nicht überein.");
var PASS_TOO_SHORT=unescape("Passwort muss mindestens 5 Zeichen lang sein.");
var WRONG_CHARS=unescape("Eintrag enthält ungültige Zeichen >>"+chars+"<<");
var USER_CREATED=unescape("Benutzer angelegt.");
var FORM_INCOMPLETED=unescape("Bitte füllen Sie alle mit * markierten Felder aus.");

var SEQUENCE_IN_WINDOW = '';

/* ---------------------------------------------------------------------------------------------
 * Global Declarations
 */
var expDays = 100;
var imageSuffixes = new Array('jpg', 'jpeg', 'gif', 'bmp', 'png', 'tif', 'tiff');
imageSuffixes.push('swf'); //semantically incorrect, but gives flash-movies a html-framework...
var popup_window;

var user; //user object;

var STATE_CONSTANTS=new Object();
STATE_CONSTANTS['unknown']=-1;
STATE_CONSTANTS['incomplete']=0;
STATE_CONSTANTS['completed']=1;
STATE_CONSTANTS['active']=2;
STATE_CONSTANTS['failed']=3;
STATE_CONSTANTS['passed']=4;

var nco_state_images = new Array();


/*
moved to template....
nco_state_images['completed'] = "icon_state_complete.gif";
nco_state_images['failed'] = "icon_state_failed.gif";
nco_state_images['incomplete'] = "icon_state_current.gif";
nco_state_images['unknown'] = "icon_state_notvisited.gif";
nco_state_images['passed'] = "icon_state_passed.gif";
*/

var tree;
var xmldom, course, course_identifier, current_nco, current_tco, qco_path, fullscreen, user_name, user_id;
var aco_div, aco_table;
var qcodom, current_qco, questions, current_question, final_exam, append_to_cycle, show_score, final_feedback, mastery_treshold, show_feedback;
var user_questions = new Array();
var user_score;

var display_mco, display_qco;

var mco_height = 200;

var mco_type, global_mco_id; //finishLU, cap_end

var progRelevantItemsCount=0; //number of all progress-relevant Items in course
var done_progRelevant=0; //progressCounter (user)

var mco_index = {};

var indexCookiePosition = new Array();
var indexExamPosition = new Array();
var finalExamId = -1; //maybe there is none....

var scoCookieStates = new Array(); //maybe parallel to indexCookiePosition,
								  //but i want to keep it separated for now...
var sco_cookie_score;


var displayAttr= (isIE()) ? 'block' : 'table-cell'; //IE doesn't understand 'table-cell' ??!

/*
if(! window.opener.dx_checks[3]._passed){
    USE_COOKIES = false;
}
*/

/* -------------------------------------------------------------------------------------------
 * Rotating Tabs
 */

var tabsTotalWidth=650; //<-- must be calculated
var tabs= new Array();
var tabsMin, tabsMax;
var tabWidths= new Array();

function tabsScrollRight(){//add one more on the right!
	tabsMax=tabsMax+1
    tabsFillUp(tabsMax, -1);
    tabsScrollerImages();
}

function tabsScrollLeft(){ //add one more on the left!
	tabsMin=tabsMin-1
	tabsFillUp(tabsMin, 1);
	tabsScrollerImages();
}

function tabsScrollerImages(){
    if(tabsMin==0){
        hide_navbutton('tabImgScrollLeft');
    }else{
        show_navbutton('tabImgScrollLeft');
    }

    if(tabsMax==tabs.length-1){
        hide_navbutton('tabImgScrollRight');
    }else{
        show_navbutton('tabImgScrollRight');
    }
}


function tabsGetVisibleTabs(){
	//if(DEBUG_MODE){db(8,0, 'call tabsGetVisible -- tabsMin / tabsMax: ' + tabsMin + '/' + tabsMax)}

	tabsMin=tabs.length;
	tabsMax=0;
	for (var i=0; i< tabs.length; i++){
		if (tabs[i].style.display != 'none'){
			if (i < tabsMin){tabsMin=i;}
			if (i > tabsMax){tabsMax=i;}
		}
	}

	//if(DEBUG_MODE){db(8,0, 'done tabsGetVisible -- tabsMin / tabsMax: ' + tabsMin + '/' + tabsMax)}
}


function tabsFillUp(start, direction){
	//if(DEBUG_MODE){db(8,1,'call: tabsFillUp (start = ' + start + ') (' + tabsMin + '/' + tabsMax + ')')}

	var tWidthCounter=0;
	if(tabs.length == tabWidths.length)	{
		if (direction > 0) {
			//ensure invisiblility of previous tabs
			for(var i=0; i < start; i++){
				tabs[i].style.display = 'none';
			}
			for(i; i < tabs.length; i++){
				//tabs[i].style.display=displayAttr;
				tWidthCounter += tabWidths[i] //.offsetWidth;
				//db(10,0,'\n widths[i]: ' + tabWidths[i]  +'\n counter: ' + tWidthCounter) // + ' \n tabs[i].offsetWidth:  ' +  tabs[i].offsetWidth )
				tabs[i].style.display = (tWidthCounter  < tabsTotalWidth) ? displayAttr : 'none';
			}
		}else{
			//ensure invisiblility of previous tabs
			for(var i=tabs.length-1; i > start; i--){
				tabs[i].style.display = 'none';
			}
			for(i; i >= 0; i--){
				//tabs[i].style.display=displayAttr;
				//tWidthCounter += tabs[i].offsetWidth;
				tWidthCounter += tabWidths[i];
				//db(10,0,'\n widths[i]: ' + tabWidths[i]  +'\n counter: ' + tWidthCounter) // + ' \n tabs[i].offsetWidth:  ' +  tabs[i].offsetWidth )
				tabs[i].style.display = (tWidthCounter < tabsTotalWidth) ? displayAttr : 'none';
			}

		}
		tabsGetVisibleTabs();

		if(tabsMin > tabsMax){
			tab_tcoId=tabs[start].getElementsByTagName('table')[0].id;
			ElementTabTitle=$(tab_tcoId + '_lnk');

			var tLen=5;
			var tWidth=10;
			oldTabTitle=ElementTabTitle.innerHTML;

			while (tWidth < tabsTotalWidth - 50){
				tLen += 2;
				//alert(tWidth + ' #  ' + tabsTotalWidth);
				newTabTitle=oldTabTitle.substr(0, tLen) + '...';
				ElementTabTitle.innerHTML=newTabTitle;
				tabs[start].style.display=displayAttr;
				tWidth=tabs[start].offsetWidth;
			}

			tabsMin=tabsMax=start;
		}

	}

	//if(DEBUG_MODE){db(8,-1,'done: tabsFillUp')}
}



/* -------------------------------------------------------------------------------------------
 * DEBUG
 */
var debug_indent=0;
function db(level, indent, txt){

  if(level >= parseInt($('debug_level').value)){
          if(indent>0){debug_indent=debug_indent + indent};
          spacer='';
          for(i=0; i<debug_indent;i++){spacer=spacer + '__';}
          if(indent==0){spacer=spacer + '...'};
          if(indent<0){debug_indent=debug_indent + indent};
          $('debug_out').value=$('debug_out').value + '\n' + spacer + txt;
  }
}

function db_clear(){
        debug_indent=0;
    $('debug_out').value='';
}
function stop_debug(){
        DEBUG_MODE=False;
        $('debug_out_wrapper').style.display='none';
}

/* ---------------------------------------------------------------------------------------------
 * SCORM
 */
function SCOInitialize() {
    if(DEBUG_MODE){db(3,1,'call:SCOInitialize')}
    /*if ((SCORM_MODE) && (!LMSIsInitialized())) {
        loadPage();
		db(3,-1, 'api.init')
    }*/

	loadPage();

    if(DEBUG_MODE){db(3,-1,'done:SCOInitialize')}
    //getTCOXML();
}


function SCOUnitialize() {
    if(DEBUG_MODE){db(3,1,'call:SCOUninitialize')}

    if ((SCORM_MODE) && (LMSIsInitialized())) {
        computeTime(); //store cmi.core.total_time (or rather: session_time)
        result = doLMSCommit();
        doLMSFinish();
    }

    if(_OFFLINE_SCORM){
        //decide what we want to set;
        //this is a single-SCO implementation (monolithic course)

        var _lessons_status;
        if(finalExamId != -1){ // if there is a final exam, this is all we want
            _lessons_status = user.states.getState(finalExamId);
            if((_lessons_status)==-1){_lessons_status=0;}

        }else{ //count NCOs and set to complete if, ja, if what?!

            var _objId;
			if(user){ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
				var _allObjIds = user.states.getObjIds();

				var counter_NCO = 0;
				var counter_NCO_done = 0;

				for(var i = 0; i < _allObjIds.length; i++){
					_objId = _allObjIds[i];
					if(_objId.substr(0,4) == 'NCO-'){ //this is weak string-binding, but all we have
						counter_NCO++;
						if(user.states.getState(_objId) == 1|| user.states.getState(_objId) == 4){
							counter_NCO_done++;
						}
					}
				}

                if(COURSE_COMPLETE_PERCENT != false){
                    _lessons_status = (percent >= COURSE_COMPLETE_PERCENT) ? 1:0;
                }else{
				    //currently, course is complete for 100% completed/passed NCOs
				    _lessons_status = (counter_NCO_done == counter_NCO) ? 1:0;
                }

				_lessons_status = state2String(_lessons_status);
				__LMSSetValue(__LESSON_STATUS, _lessons_status);
				__LMSCommit();
			}
        }
    }

    if(DEBUG_MODE){db(3,-1,'done:SCOUninitialize')}
}

function finishLearningUnit() {
    if(DEBUG_MODE){db(3,1,'call:FinishLearningUnit')}
    doQuit("completed");
    if ((fullscreen) && (window.opener)) {
        window.close();
    }
    if(DEBUG_MODE){db(3,-1,'done:FinishLearningUnit')}
}


function cap_end(){
	 if (current_nco.getAttribute('isACO') == 'false'){
        setMCOState(global_mco_id, "completed");
    }
    // if(popup_window){
    //    popup_window.close();
    //}
}



function openSCOPopup() {
    if(DEBUG_MODE){db(0,1,'call: openScoPopup')}
    var ns4up = (document.layers) ? 1 : 0;
    var ie4up = (document.all) ? 1 : 0;
    var xsize = screen.width;
    var ysize = screen.height;
    var breite=xsize;
    var hoehe=ysize;
    var xpos=(xsize-breite)/2;
    var ypos=(ysize-hoehe)/2;

    var fs_window = window.open(document.URL,"fs_window","statusbar=no,toolbar=no,location=no,directories=no,resizable=no,menubar=no,width="+breite+",height="+hoehe+",screenX="+xpos+",screenY="+ypos+",top="+ypos+",left="+xpos)
    fs_window.focus();

    if(DEBUG_MODE){db(0,-1,'done: openScoPopup')}
}

var popup_params;

function openCustomPopup(url, maximize, width, height) {
	if (maximize == "true") {
		width = screen.availWidth;
		height = screen.availHeight;
	}
    var xpos=0;
	var ypos=0;

    popup_params = "'" + url + '\',\'' + maximize + '\',' + width + ',' + height;
    var cursorType = (isIE()) ? 'hand' : 'pointer';
    var __content_html = '<table width="100%" cellpadding="0" cellspacing="0"><tr><td style="cursor:' + cursorType +';" onclick="javascript:openCustomPopup(' + popup_params + ');">'  + SEQUENCE_IN_WINDOW +  '</td></tr></table>';


    if (__customPopReferrerDiv){
        //__customPopReferrerDiv.innerHTML =  '<div align="center"><br /><br />Die Sequenz wurde in einem neuen Fenster geladen.</div>';
        __customPopReferrerDiv.innerHTML =  __content_html;

    }else{
        //document.getElementById("mco_content").innerHTML = '<div align="center"><br /><br />Die Sequenz wurde in einem neuen Fenster geladen.</div>';
        document.getElementById("mco_content").innerHTML = __content_html;
    }

    var _attrs = "statusbar=no,toolbar=no,location=no,directories=no,resizable=no,menubar=no,width="+width+",height="+height+",screenX="+xpos+",screenY="+ypos+",top="+ypos+",left="+xpos;
    popup_window = window.open(url, "popup_window", _attrs);

	if (maximize == "true") {
		 popup_window.resizeTo(width, height);
         //do not resize, if not fullscreen;
         //window opens with innerDimension = width/height, which is needed for proper content measures.
	}
	popup_window.focus();
    //store for later...
    //popup_params = "'" + url + '\',\'' + maximize + '\',' + width + ',' + height;
    //popup_window.onunload = popupOnBlur;
}


function popupOnBlur(){
    //pass
    /*
    if (__customPopReferrerDiv){
        __customPopReferrerDiv.innerHTML = '<div align="center"><br /><br />Die Sequenz soll in einem neuen Fenster geladen werden.<br> <br> Wenn Sie diese Sequenz wiederholen möchten, <a style="text-decoration:underline; color:#000000;" href="javascript:openCustomPopup(' + popup_params + ');">klicken Sie bitte hier</a>. </div>';
    }else{
        document.getElementById("mco_content").innerHTML = '<div align="center"><br /><br />Die Sequenz soll in einem neuen Fenster geladen werden.<br> <br> Wenn Sie diese Sequenz wiederholen möchten, <a style="text-decoration:underline; color:#000000;" href="javascript:openCustomPopup(' + popup_params + ');">klicken Sie bitte hier</a>. </div>';
     }
     */
}



/* ----------------------------------------------------------------------------
state/data - handling
store everything, care about cookies later...
*/
function state2String(state){
        for(k in STATE_CONSTANTS){
                if(STATE_CONSTANTS[k] == state){
                        return k;
                }
        }
        return 'unknown'; //fallback
}


function objUser(userName){
    this.username=userName;
    this.states=new objState();
    this.scores=new objScore();
    this._fields=new Array();

}


function objState(){
    this.statesById = new Object();

    this.setState=function (id, state){
        if(isNaN(parseInt(state))){state=STATE_CONSTANTS[state];} //translate constant so you can use both
        this.statesById[id]=state;
			if(DEBUG_MODE){
				buffer='';
				for(k in this.statesById){
						if(this.statesById[k].toString().indexOf('function')<0){buffer=buffer + k + ' : ' + this.statesById[k] + '\n';}
				}
				$('states_out').value=buffer;
			}

    }

	this.getState=function (id){
        return (isNaN(this.statesById[id])) ? -1 : this.statesById[id];
    }

	this.getDict=function(){
		var ret= new Array()
		for(k in this.statesById){
			if(this.statesById[k].toString().indexOf('function')<0){
				ret[k]=this.statesById[k]
				}
		}
		return ret;
	}
    this.getObjIds = function(){
        var ret= new Array()
		for(k in this.statesById){
			if(this.statesById[k].toString().indexOf('function')<0){
				ret.push(k)
				}
		}
		return ret;

    }


    return this;
}


function objScore(){
    this.quizes=new Object();

	this.setOverallScore=function(examId, score){
			if(this.existId(examId)==false){this.resetScore(examId)}
		this.quizes[examId]['overall_score']=score;
	}
	this.getOverallScore=function(examId){
			if(this.existId(examId)==false){return 0;}
	return this.quizes[examId]['overall_score'];
	}

    this.resetScore=function(examId){
        if(DEBUG_MODE){db(1,0, 'resetScore')}
        this.quizes[examId]=new Object();
        this.quizes[examId]['overall_score']=0;
    }
    this.setQuestionScore=function(examId, questionId, score){
        if(this.existId(examId)==false){this.resetScore(examId)}
        this.quizes[examId][questionId]=score;
        if(DEBUG_MODE){db(1,0, 'setScore: ' + score)}
    }
        this.getQuestionScore=function(examId, questionId){
        if(this.existId(examId)==false){return 0;}
        return (this.quizes[examId][questionId]) ? this.quizes[examId][questionId] : 0;
        }

        this.getQuestions=function(examId){
                var ret=new Array();
                if(this.existId(examId)==false){return ret;}
                for(k in this.quizes[examId]){
                        if(this.quizes[examId][k].toString().indexOf('function')<0 && k != 'overall_score'){
                                ret.push(k)
                        }
                }
                return ret
        }

    this.getScore=function(examId){
            //calculates score !!
        score=0;
        var qs=this.getQuestions(examId)
        for(var k=0; k < qs.length; k++){
            score=score+this.quizes[examId][qs[k]];
        }
        return score;
    }

        this.existId=function(examId){
                return (this.quizes[examId]) ? true : false;
        }

    return this
}






/* ---------------------------------------------------------------------------------------------
 * XML-HTTP Requests
 */
function requestXML(path, func) {
    // Call AJAX method to request file from server
    new Ajax.Updater("",
        path,  // relative path
        {
            method: "get",
            onComplete: func,  // call "func" when request is complete
            onFailure: reportError
        }
    );
}

function requestFile(path, target) {
    new Ajax.Updater(target,
        path,  // relative path
        {
            method: "get",
            onFailure: reportError
        }
    );
}

function requestFileCB(path, func) {
    new Ajax.Updater("",
        path,  // relative path
        {
            method: "get",
            onComplete: func,
            onFailure: reportError
        }
    );
}

function setSEQUENCE_IN_WINDOW(response){
    SEQUENCE_IN_WINDOW = response.responseText;
}


function SCORM_BUILD_TREE(response){
	if(DEBUG_MODE){db(0,1,'call: SCORM_BUILD_TREE');}

	var objDom = new XMLDoc(response.responseText, reportError);
    xmldom = objDom.docNode;
    course = xmldom.getElements("organizations")[0].getElements("organization")[0];
	tree = new dhtmlXTreeObject($("TreeSlot"), "100%", "100%", 0);

    _fillTree(course, 0); //does not set states....
    //_setTreeStates(); //does set states (reverse order, meaning from leaf to root)

    if(DISPLAY_ENDFUNCTION){
        insertEndFunction();
    }

	requestNCO();
	if(DEBUG_MODE){db(0,-1,'done: SCORM_BUILD_TREE');}
}


function requestContent() {

    if(SCORM_MODE) {
		SCOInitialize();
	}

    //just once
    if(DEBUG_MODE){
        $('debug_out_wrapper').style.display='block';
        db(0,1,'call: requestContent');
    }else{
        $('debug_out_wrapper').style.display='none';
    }


	$('LoadWrapper').style.visibility='visible';
    $('LeftColumn').style.visibility='hidden';
    $('RightColumn').style.visibility='hidden';
    if (SEQUENCE_IN_WINDOW == ''){
        requestFileCB('../../resources/seqInDiffferenWin.html', setSEQUENCE_IN_WINDOW);
    }


	if(OFFLINE_MODE){

        if(_OFFLINE_SCORM){
            __LMSInit();
            user_id = __LMSGetValue(__USER_ID);

        }else{
            if(USE_COOKIES){
                user_id = getCookie("dx_current_user");
            }
         }
        if(user_id==null){ //force user name if still null
            user_id='anonymous';
        }


        user=new objUser(user_id);

        //get user-data from cookie
         if(USE_COOKIES){
            var cookieData = dxGetCookie(user_id, 0);
            if(cookieData){
                var pairs=cookieData.split('&');
                for(var i=0; i < pairs.length;  i++){
                    var kv=pairs[i].split('=');
                    k=kv[0];
                    v=kv[1];
                    user._fields.push(k);
                    user[k]=v;
                }
            }
        }

        requestXML("../../imsmanifest.xml", handleContent); // request IMS manifest in offline mode
    }

    if(SCORM_MODE) {
        course_identifier = "none";
        //SCOInitialize();
        user_id = 'u' + doLMSGetValue("cmi.core.student_id"); // get username from LMS
        user=new objUser(user_id);
        requestNCO(); // request data.xml in SCORM mode
    }


    $('LeftColumn').style.visibility='visible';
    $('RightColumn').style.visibility='visible';
    //$('LoadWrapper').style.display='none';


    if(DEBUG_MODE){db(0,-1,'done: requestContent');}
}

function requestNCO(path) {
    /* Request TCO information of current NCO */
    if(DEBUG_MODE){db(0,1,'call: requestNCO');}

	var path = (path == null) ? "./data.xml" : path;  // make "path" an optional parameter, default: "./data.xml"

    requestXML(path, handleNCO);
    if(DEBUG_MODE){db(0,-1,'done: requestNCO');}
}

function requestMCO(mco_id) {
    if(DEBUG_MODE){db(0,1, 'call: requestMCO');}

	//hook for "finishLU"...
	var mco = current_tco.getElementById(mco_id);
	mco_type=mco.getAttribute('mcotype');
	mco_CompleteOnCall=mco.getAttribute('CAP_END_onCall')=='True';
	global_mco_id=mco_id;

	if (mco.getAttribute('fullscreen') == "true") {

		//Hide flashscreen
		$('LoadWrapper').style.display='none';

		// Open popup
        __customPopReferrerDiv = false;
		var url = "../SCO_for_"+current_nco.getAttribute("id")+"/"+mco_id+".html";
		if (mco.getAttribute('maximize') == "true") {
			openCustomPopup(url, "true");
		} else {
		    var width = mco.getAttribute('popup_width');
			var height = mco.getAttribute('popup_height');
			openCustomPopup(url, "false", width, height);
		}
	} else {
		//Load and trigger onMCOLoaded...
		if (OFFLINE_MODE) {
			requestFileCB("../SCO_for_"+current_nco.getAttribute("id")+"/"+mco_id+".html", onMCOLoaded);
		}
		if (SCORM_MODE){
			requestFileCB(mco_id+".html", onMCOLoaded);
		}
	}

    // Update page layout for current MCO
    mco_height = current_tco.getElementById(mco_id).getElements("height")[0].getText();
    regulateHeights();
    updateMCONavigationBar(mco_id);

    //do not go into recursive functions with ACOs - they are not in the tree!
	//also, wait for flash to call cap_end() if mco_CompleteOnCall is false..
	//standard text is set to "completed" immediately.

	if(current_nco.getAttribute('isACO') == 'true'){
		//#setMCOState(mco_id, "completed");
		//#shorter:
			user.states.setState(current_nco.getAttribute('id'), 'completed')
			if(SCORM_MODE){
				doLMSSetValue("cmi.core.lesson_status", "completed");
			}
	}else{
		if(mco_type != 'flash' || mco_CompleteOnCall){
			setMCOState(mco_id, "completed");
		}
    }

    if(DEBUG_MODE){db(0,-1, 'done: requestMCO');}
}


 /* ---------------------------------------------------------------------------------------------
  * Cookies
  */


var cookieStateStringBin=''

function clearCookie(){
        init_BlankBinaryCookieStateString();
        dxSetCookie(user.username, 1, convertBinCookieString2Hex());
        user=new objUser(user_name);
        //#TODO: should reset properly...
        //requestContent();
}


function init_BlankBinaryCookieStateString(){
        //needs array:indexCookiePosition to be set.
        var z;
        cookieStateStringBin=''
        for (z=0; z < Math.ceil(indexCookiePosition.length/8)*8; z++){
                cookieStateStringBin=cookieStateStringBin + '0';
        }
}

function setState_binCookieString(pos, state){
        if(state != 1){state=0}
        //old_l=cookieStateStringBin
        cookieStateStringBin=cookieStateStringBin.substring(0,pos) + state.toString() + cookieStateStringBin.substring(pos+1,cookieStateStringBin.length)
        //old_h=convertBinCookieString2Hex()

}

function getState_binCookieString(pos){
        return cookieStateStringBin.substr(pos,1);
}

function convertBinCookieString2Hex(){
        var z;
        var s='';
        var cookieStateStringHex='';
        for(z=0; z < cookieStateStringBin.length; z+=8){
                cookieStateStringHex = cookieStateStringHex + binToHex(cookieStateStringBin.substr(z,8));
        }
        return cookieStateStringHex
}


function storeCookieOnBlur(){
        //alert("old storeCookieOnBlur")
        //#TODO: confirm box
        //is called even if useCookies is off!!!
        if(DEBUG_MODE){db(0,1, 'call: storeCookieOnBlur');}

		if(SCORM_MODE){

			var sco_cookie_bin='';
			for(var c=0; c< scoCookieStates.length; c++){
				var append=(scoCookieStates[c]) ? scoCookieStates[c]  : '0' ;
				sco_cookie_bin=sco_cookie_bin + append;
			};

			if (current_nco.getAttribute('id')==current_qco){	// is finalExam
				questions=current_nco.getElements('QCO')[0].getElements('questions')[0].getElements('question')
				scoreString=''
				for (var i=0; i< questions.length; i++){
					uResult=user.scores.getQuestionScore(current_qco, questions[i].getAttribute('id'))
					scoreString=scoreString + uResult + '-';
				}
				scoreString=scoreString.substr(0, scoreString.length-1);
				//alert("blur" + user.states.getState(current_qco))
			}

			cookieString=sco_cookie_bin
			if (scoreString){
				cookieString=cookieString+ '#' + scoreString;
			}else{
				cookieString=cookieString+ '#' + sco_cookie_score;
			}

		}

		if (OFFLINE_MODE){
			var z, itemId;
			var scoreString='#'
			for(z=0; z < indexCookiePosition.length; z++){
				itemId=indexCookiePosition[z];
				setState_binCookieString(z, user.states.getState(itemId))

				if(itemId.substring(0,3)=='QCO' && itemId != finalExamId){
						//get Score or OverallScore
						uOScore=(user.states.getState(itemId)==0) ? user.scores.getScore(itemId) : user.scores.getOverallScore(itemId);
						scoreString=scoreString + uOScore + ",";

						if(user.states.getState(itemId)==3 || user.states.getState(itemId)==4){//exam passed/failed; store as "done" anyway
							setState_binCookieString(z, 1)
						}
				}



				if (itemId == finalExamId){
                    /*
					if(user.states.getState(itemId)==3){//exam failed; store as "done" anyway
                    */
                    if(user.states.getState(itemId)==3 || user.states.getState(itemId)==4){//exam failed; store as "done" anyway
							setState_binCookieString(z, 1)
  					}

					var tmp_element=getElementByIdentifier(xmldom, itemId);
					var totalNoQuestions=tmp_element.getElements('totalNoQuestions')[0].getText()
					var userScoreQuestions=user.scores.getQuestions(itemId);

					//carefull! if final exam has not been called between two refreshes,
					//there are no items under question, but an array in overall_score!
					if(isNaN(user.scores.getOverallScore(itemId))){
						scoreString=scoreString+user.scores.getOverallScore(itemId).join('-');
						scoreString=scoreString + ',';
					}else{
						for(var i=0; i<totalNoQuestions; i++){
							//get score from user.scores as long as there are values:
							if(i<userScoreQuestions.length){
									scoreString=scoreString + user.scores.getQuestionScore(itemId, userScoreQuestions[i]) + "-";
							}else{
									scoreString=scoreString + "0-";
							}
						}
						scoreString=scoreString.substr(0,scoreString.length-1) + ",";
					}
				}
			}
			var cookieString = convertBinCookieString2Hex() + scoreString
		}


		//nnow=new Date();
		//expires=new Date(nnow.getTime() + (365 * 24 * 60 * 60 * 1000)) //a year
		//setCookie(user.username, cookieString, expires,'/')
        dxSetCookie(user.username, 1,  cookieString)
		//alert(cookieString)

        return false;

        if(DEBUG_MODE){db(0,-1, 'done: storeCookieOnBlur');}
}



/* --------------------------------------------------------------------------------------------- */

function _findCookiePositionById(id){ //TODO: this is not used?
        //returns position of item in indexCookiePosition
        var i;
        for(i=0; i<indexCookiePosition.length; i++){
                if(indexCookiePosition[i]==id){
                        return i;
                }
        }
        return -1;
}

/* ---------------------------------------------------------------------------------------------
 *
 */

    //we do not have "id" in manifest, but "identifier".
    //thus, copy the getElementById-funtion and alter it:

    function getElementByIdentifier(node, identifier){
        var ret;
        if (node.getAttribute("identifier") == identifier) {
            return node;
        } else {
            var elements = node.getElements();
            var intLoop = 0;
            while (intLoop < elements.length) {
                var element = elements[intLoop];
                ret = getElementByIdentifier(element, identifier);
                if (ret != null) {
                    break;
                }
                intLoop++;
            }
        }
        return ret;
    }
/* ---------------------------------------------------------------------------------------------
wait for tree:*/

var global_firstNCOId;

function hopefullyTreeIsReady(){
    tree.closeItem("COURSE-"+COURSE_ID)

    tree.selectItem(global_firstNCOId);
    fireTreeElement(global_firstNCOId);
}


/* ---------------------------------------------------------------------------------------------
 * XML-HTTP Response Handlers
 */

function handleContent(response) { //this is only in offlineMode
    if(DEBUG_MODE){db(0,1, 'call: handleContent')}
    // Initialize XML DOM
    var objDom = new XMLDoc(response.responseText, reportError);
    var first_nco;
    xmldom = objDom.docNode;

    // Get organizations (SCOs)
    course = xmldom.getElements("organizations")[0].getElements("organization")[0];
    course_identifier = course.getAttribute("identifier");

    //collect all items into Array:indexCookiePosition
    _collectCookieStoreableItems(course)


    if(USE_COOKIES){
            //look for user-cookie
//            cookieString=getCookie(user.username)
            cookieString=dxGetCookie(user.username,1)

            if(DEBUG_MODE){db(2,0, 'cookieString: ' + cookieString)}
            //cookieString="c00#2,2-0-4,"

            if(cookieString=='' || cookieString==null){ //TODO: check properly
                    if(DEBUG_MODE){db(2,0, 'init new cookie');}
                    //reset str:cookieStateStringBin
                    init_BlankBinaryCookieStateString()
            }else{
                    cookieCrumbs=cookieString.split('#')

                    cookieStateStringBin=hexToBin(cookieCrumbs[0])//! carefull ! state is binary 0, also if state is actually -1 !
                    //scores for the exams...
                    if (cookieCrumbs[1]){
                            examScores=cookieCrumbs[1].split(',');
                            for(var i=0; i < examScores.length-1; i++){
                                    examId = indexCookiePosition[indexExamPosition[i]]

                                    if(examId==finalExamId){
                                            //sonderfall fuer final exam:
                                            //wir haben den score-string, aber nicht die ids der fragen.
                                            //also speichern wir diesen (als array) im overall_score
                                            //und muessen ihn dann entsprechend beim aufruf des exams zerlegen!
                                            fExamScores=examScores[i].split('-');
                                            var examScore=new Array();
                                            var ufTotalScore=0;
                                            for(var z=0; z < fExamScores.length; z++){
                                                    ufScore=hexToDec(fExamScores[z]);
                                                    examScore.push(ufScore);
                                                    //anyway, we have to set the state correctly
                                                    //(it is stored as binary in the cookie, remember...)
                                                    //so, we count the user's score:
                                                    ufTotalScore += ufScore;
                                            }
                                            //yak, store an array where it's not supposed to be:
                                            user.scores.setOverallScore(examId, examScore);
                                    }else{
                                            var examScore = examScores[i]
											//alert('setting score: ' + examId + ' - ' + examScore)
                                            user.scores.setOverallScore(examId, examScore);
                                    }

                                    if(DEBUG_MODE){db(2,0, 'cookie_score: ' + examScore + ' - ' + examId);}
                            }
                    }

            }

            //now set states for TCOs/ QCOs:
            if(DEBUG_MODE){db(2,0, 'cookieStateStringBin: ' + cookieStateStringBin);}
            for(z=0; z < indexCookiePosition.length; z++){
//                    db(2,0, '## ' + z + '#' + getState_binCookieString(z) + ' # ' + indexCookiePosition[z])
                    if(getState_binCookieString(z)==1){
                            user.states.setState(indexCookiePosition[z], 'completed')

                            if(indexCookiePosition[z]==finalExamId){
                                    //set state for final exam; it is stored as 0/1, but may also be 3 (failed) or 4 (passed)!
                                    //ID//fExamItem=xmldom.getElementById(finalExamId);
                                    fExamItem=getElementByIdentifier(xmldom, finalExamId);

                                    fExamMaxScore=parseInt(fExamItem.getElements('maxScore')[0].getText());
                                    fExamMastery=parseInt(fExamItem.getElements('mastery')[0].getText());
                                    if ((ufTotalScore * 100 / fExamMaxScore) < fExamMastery){ // mastery (percent!) not reached.
                                        user.states.setState(indexCookiePosition[z], 'failed');
                                    }else{
                                        user.states.setState(indexCookiePosition[z], 'passed');
                                    }
                            }else{ //finalExam is not progress-relevant

									//so aren't TCOS...

									tcoItem=getElementByIdentifier(xmldom, indexCookiePosition[z]);

									if(tcoItem.getAttribute('always_completed')=="False"){
										done_progRelevant += 1;
									}
                            }
                    }
            }

        }

        //Relevant content for Progressbar (currently TCO) (and not QCOs, anymore... ;) )

		//progRelevantItemsCount=indexCookiePosition.length -1; //do not count FinalExam or ACOs
		//***progRelevantItemsCount will be set by _collectCookieStoreableItems
		//***to be a little more flexible with qco/tco relevance...

        //progRelevantItemsCount-=1;
        percent = Math.round(done_progRelevant * 100 / progRelevantItemsCount);
        if(DISPLAY_PROGRESS){
			newProgress(percent);
		}


    // Initialize and build tree
    //#TODO: use param show_tree?
    tree = new dhtmlXTreeObject($("TreeSlot"), "100%", "100%", 0);
    tree.setImagePath("./../../resources/");
    tree.enableAutoTooltips(1);
    //tree.enableMultiLineItems(100);

    if(OFFLINE_MODE){
        treeSlot=tree.parentObject
        aco_div=document.createElement('table');
        aco_div.setAttribute('id', 'aco_ul')
        aco_div.setAttribute('class', 'standartTreeRow')
        aco_div.style.fontFamily = FONT_TREE; //IE doesn't do it otherwise :(
        aco_div.style.color = COL_TREE_STD_FC;
        aco_table=document.createElement('tbody');

    }

    _fillTree(course, 0); //does not set states....
     if(DISPLAY_ENDFUNCTION){
        insertEndFunction();
    }
    _setTreeStates(); //does set states (reverse order, meaning from leaf to root)

    if(OFFLINE_MODE){//append ACO-area
        aco_div.appendChild(aco_table);
        tree.allTree.appendChild(aco_div);


        var acoCells = aco_div.getElementsByTagName('td');
        for (var i=0; i < acoCells.length; i++){
            acoCells[i].style.padding='0px';
            acoCells[i].style.spacing='0px';
            //font face ?!
        }
        //aco_div.style.paddingLeft = px(16); //positioning.... -->do in CSS
     }

    redrawTree(); //apply states.

    first_nco = course.getElements("item")[0].getAttribute("identifier");
    //$('TreeSlot').getElementsByTagName('div')[0].style.marginTop="0px";

    global_firstNCOId = first_nco;

    window.setTimeout(hopefullyTreeIsReady, 3000);

    if(DEBUG_MODE){db(0,-1, 'done: handleContent')}
}



function getScoCookieState(index){
	if(isNaN(index)){index=index.toInt();}
	//alert('index: ' + index)
	if (index >= scoCookieStates.length || scoCookieStates[index]==null){ //should not return "undefined")
		scoCookieStates[index]=0;
	}
	return scoCookieStates[index];
}


function init_rotatingTabs(){
    if(DEBUG_MODE){db(0,1, 'call: init_rotatingTabs')}
		//initialize rotating tabs
		var tabElements = $('tabsMain').getElementsByTagName('td');
        tabs=new Array(); //reset global var tabs
        tabWidths=new Array();
		for(var i=0; i < tabElements.length; i++){
			if(tabElements[i].className == 'tab'){
				//fill global var "tabs"
				tabs.push(tabElements[i]);
				tabElements[i].style.display=displayAttr;
                //alert(tabElements[i].offsetWidth)
				tabWidths.push(tabElements[i].offsetWidth);
			}
		}
		tabsMin=0;
		tabsMax=tabs.length;
        tabsFillUp(0, 1)
        tabsScrollerImages();
    if(DEBUG_MODE){db(0,-1, 'done: init_rotatingTabs')}
}


function handleNCO(response) {
    if(DEBUG_MODE){db(0,1, 'call: handleNCO')}

    // Initialize XML DOM
    var objDom = new XMLDoc(response.responseText, reportError);
    scodom = objDom.docNode;
    current_nco = scodom;
    var tcos = scodom.getElements("TCO");  // get TCO elements

    // Set global settings for current NCO
    var properties = scodom.getElements("properties")[0];
    qco_path = properties.getElements("QCOId")[0].getText();
    fullscreen = properties.getElements("fullscreen")[0].getText();

    if (SCORM_MODE) {
        //SCOInitialize(); //this is done by request Content...
		//set user.states (new context (and new user-object) for every call in online mode...)

		if(USE_COOKIES){
			//sco_cookie=getCookie(user.username);
            sco_cookie=dxGetCookie(user.username, 1)

			if(sco_cookie==null){sco_cookie='';}
			sCookie=sco_cookie.split('#');

			sco_cookie_bin =sCookie[0];
			sco_cookie_score=(sCookie[1]) ? sCookie[1] : '';

			for (var i=0; i < sco_cookie_bin.length;  i++){
				scoCookieStates[i]=sco_cookie_bin.substr(i,1); //fill global scoCookieStates
																										   //make sure, it is filled up to cookieIndex, which is a number rather than a string....
																										   //do NOT use "push()" here :)
			}
			//now set states (TCOs only)
			sItems=tcos
			for(var c=0; c < sItems.length; c++){
				if(sItems[c].getAttribute('always_completed')=="True"){
					var s_state = 1
				}else {
					var s_state = getScoCookieState(sItems[c].getAttribute('cookieIndex'));
				}
				var s_id 	  = sItems[c].getAttribute('id');
				user.states.setState(s_id, s_state);
			}

        }
		//get LessonState from LMS
		user.states.setState(scodom.getAttribute('id'), doLMSGetValue('cmi.core.lesson_status'))
		//alert(scodom.getAttribute('id') + '  has state ' + doLMSGetValue('cmi.core.lesson_status'))

	}


    if ((fullscreen == "True") && (!window.opener)) {
        alert('window pop-up not implemented....')
        //$("CourseWrapper").innerHTML = "<p align=\"center\">Das Modul wird in einem neuen Fenster geladen.<br /><br />Sollte sich kein Popup &ouml;ffnen, &uuml;berpr&uuml;fen Sie Ihre Browser-Einstellungen.</p>";
        //openSCOPopup();
        //return;
    }


    // Load & display MCO if existant
    display_mco=(tcos.length > 0);

    if (display_mco) {

        display_mco = true;
        var tco_navigation = buildTabNavigation('MCO');
        var buffer = '';
        var tco_id, tco_title;

        for (var i=0; i<tcos.length; i++) {
            buffer = buffer + buildOneTab(tcos[i].getAttribute("id"), tcos[i].getAttribute("title"), 'MCO');
        }

        $("mco_tab_area").innerHTML = tco_navigation[0] + buffer + tco_navigation[1];

//        init_rotatingTabs()

		//updateTCOTabs(); //colors....

		if(DEBUG_MODE){db(1,0,'filled mco_tab_area');}

        showTCO(tcos[0].getAttribute("id"));

    }


    // Load & display QCO if existant

    display_qco=(current_nco.getElements("QCO").length>0);

    if(DEBUG_MODE){db(1,0,'display_qco: ' + display_qco);}

    if (display_qco) {
        qcodom = current_nco.getElements("QCO")[0];
        current_qco=qcodom.getAttribute('id');
        questions = qcodom.getElements("questions")[0].getElements("question");
        if (qcodom.getElements("isFinalQuest")[0].getText() == "True") {
            final_exam = true;
            $("mco_content").innerHTML = "";  // hotfix to stop the sounds of flash mcos when changing the NCO
            $('LoadWrapper').style.display='none';
        } else {
            final_exam = false;
        }

            var qco_navigation = buildTabNavigation('QCO');
            var buffer = '';
            //for (var i=0; i<tcos.length; i++) { //hook for more than one qco... see TestCenter
                buffer = buffer + buildOneTab(current_qco,  qcodom.getElements("title")[0].getText(), 'QCO');
            //}

            $("qco_tab_area").innerHTML = qco_navigation[0] + buffer + qco_navigation[1];

        if (qcodom.getElements("param_ShowCurrentScore")[0].getText() == "True") {
            $("nav_button_current_points").style.visibility="visible";
        } else { $("nav_button_current_points").style.visibility="hidden"; }

        if (qcodom.getElements("param_showRemainingTasks")[0].getText() == "True") {
            $("nav_button_current_tasks").style.display = "inline";
        } else { $("nav_button_current_tasks").style.display = "none"; }

        if (qcodom.getElements("isFinalQuest")[0].getText() == "True") {
            final_exam = true;
            $("mco_content").innerHTML = "";  // hotfix to stop the sounds of flash mcos when changing the NCO
            $('LoadWrapper').style.display='none';
        } else { final_exam = false; }

        if (qcodom.getElements("param_AppendToCycle")[0].getText() == "True") {
            append_to_cycle = true;
        } else { append_to_cycle = false; }

        if (qcodom.getElements("param_ShowScore")[0].getText() == "True") {
            show_score = true;
        } else { show_score = false; }

        if (qcodom.getElements("param_ShowFeedback")[0].getText() == "True") {
            show_feedback = true;
        } else { show_feedback = false; }

        //$("qco_title").innerHTML = qcodom.getElements("title")[0].getText();


        final_feedback = qcodom.getElements("param_FinalFeedback")[0].getText(); //[none, simple, result, detailed]
        mastery_treshold = parseInt(qcodom.getElements("param_MasteryThreshold")[0].getText());
        max_score=parseInt(qcodom.getAttribute("maxScore"));



		if(SCORM_MODE){
			//and set overallScore:
			user_score=doLMSGetValue('cmi.core.score.raw');

			if(user_score=='newuserScore' || user_score==''){
				user_score=0;
			}else{
				user_score=parseInt(user_score);
			}

			user.scores.setOverallScore(current_qco,user_score)

			if(USE_COOKIES){
				var has_unfinishedQuestions=false;
				sItems=questions //now set states for questions:
				for(var c=0; c < sItems.length; c++){
					var s_state = getScoCookieState(sItems[c].getAttribute('cookieIndex'));
					var s_id 	  = sItems[c].getAttribute('id');
					user.states.setState(s_id, s_state);
					//alert(s_id + ' # #  ' + s_state)
					if(s_state == -1 || s_state==0){
						has_unfinishedQuestions=true;
						if(DEBUG_MODE){db(0,0,'question state is ' + s_state +' -> unfinishedQuestions=true');}
					}
				}
				if (current_qco==current_nco.getAttribute('id')){ // final Exam, set scores
					scores=sco_cookie_score.split('-');
					for (var z=0; z < sItems.length; z++){
						score=(scores[z]) ? parseFloat(scores[z]) : 0;
						user.scores.setQuestionScore(current_qco, sItems[z].getAttribute('id'), score);
					}
					 /*VIVERSA cares shit about SCORM-values - kindly remind her.....
					 This ranks cookie-states of single questions higher than LMS-statement about the QCO's status !!
					 */
					if(has_unfinishedQuestions){
						user.states.setState(current_qco, 'incomplete');
						scoCookieStates[current_qco]='0' ; //reset cookie state
						doLMSSetValue('cmi.core.lesson_status', 'incomplete');
					}
				}
			}

		}


		//##################################################
        //check, if the user has done this before:
		//alert('now ' + current_qco + '  has state ' + user.states.getState(current_qco))
		qcoUserState=user.states.getState(current_qco);

		//for normal eXams, user Score is stored in overallScore;
		//we do not bother about single questions....
		if(USE_COOKIES && OFFLINE_MODE){
			//re-check state, score might come from cookie...
			user_score=user.scores.getOverallScore(current_qco);

			//initial for FinalExamScores from Cookie:
            if(current_qco==finalExamId && isNaN(user_score)){ //initial, overallScore is an array
                var qs=qcodom.getElements('questions')[0].getElements('question');
                for (var z=0; z < qs.length; z++){
                    user.scores.setQuestionScore(current_qco, qs[z].getAttribute('id'), user_score[z]);
                }
                user.scores.setOverallScore(current_qco, user.scores.getScore(current_qco));
                user_score=user.scores.getOverallScore(current_qco);
            }

			user_score_percent = parseInt(user_score * 100 / max_score);
			if (user_score_percent >= parseInt(mastery_treshold)) {
				qcoUserState=4;
			}


		}
/*
			STATE_CONSTANTS['completed']=1;
			STATE_CONSTANTS['failed']=3;
			STATE_CONSTANTS['passed']=4;
*/
		if(qcoUserState==1 || qcoUserState==3 || qcoUserState==4){

            if(DEBUG_MODE){db(1,0, 'user has completed qco before: state ' + qcoUserState);}

			user_questions=new Array();
            user_score=user.scores.getOverallScore(current_qco)

            //initial for FinalExamScores from Cookie:
			db(0,0,"user_score: " + user_score)

            if(SCORM_MODE && USE_COOKIES && current_qco==finalExamId){
                user.scores.setOverallScore(current_qco, user.scores.getScore(current_qco));
                user_score=user.scores.getOverallScore(current_qco);
            }

            $("current_points").innerHTML = user_score;
            $("total_points").innerHTML = max_score;
            $("current_tasks").innerHTML = '0';

            showFeedbackPage();
        }

	/*	STATE_CONSTANTS['unknown']=-1;
			STATE_CONSTANTS['incomplete']=0;
			((STATE_CONSTANTS['active']=2;.... not used))
	*/

		if(qcoUserState==-1 || qcoUserState==0){

			if(DEBUG_MODE){db(1,0, (qcoUserState==-1) ? 'start qco from scratch' : 'qco has been started before, but not finished...');}

			if(qcoUserState==-1 || current_qco==finalExamId){ //allways reset FinalExam
				user.states.setState(current_qco, 'incomplete');
				user.scores.resetScore(current_qco);
				user_score=0;
			}

			user_questions = new Array();

			for (var i=0; i<questions.length; i++) {
				// Build cycle
				qId=questions[i].getAttribute("id");
				qScore=questions[i].getElements('properties')[0].getElements('maxScore')[0].getText();

            if ( (user.states.getState(qId)!=1 && user.scores.getQuestionScore(current_qco, qId) != qScore) ||  current_qco==finalExamId){
					user_questions.push(qId);
				}else{
					user.scores.setQuestionScore(current_qco, qId, parseInt(qScore))
				}
			}


			/* *************
			** if state is 0, but all questions have been answered (correctly)
			** (something, that shouldn't happen, but will, if you update a course in, i.e., www.viversa.net),
			** there will be no questions in array user_questions.
			** so, since the party is always right: do another round resetting cookie-score:
			************** */
			if (user_questions.length==0){
				for (var i=0; i<questions.length; i++) {
					qId=questions[i].getAttribute("id");
					user.scores.setQuestionScore(current_qco, qId, 0);  //set score 2 zero
					user.states.setState(qId, 'unknown') //reset internal state
					if(SCORM_MODE && USE_COOKIES){
						scoCookieStates[questions[i].getAttribute("cookieIndex")]='0' ; //reset cookie state
					}
					user_questions.push(qId);
				}
			}

			user_score=user.scores.getScore(current_qco);

			if(SCORM_MODE){
				//initialize as new...
				doLMSSetValue("cmi.core.score.raw", user_score) ; //userScore
				doLMSSetValue("cmi.core.score.min", mastery_treshold); //!carefull, this is percentage!
				doLMSCommit();
			}

			$("current_points").innerHTML = user_score;
			$("total_points").innerHTML = max_score;
			$("current_tasks").innerHTML = user_questions.length;
/*
            var qco_navigation = buildTabNavigation('QCO');
            var buffer = '';
            //for (var i=0; i<tcos.length; i++) { //hook for more than one qco... see TestCenter
                buffer = buffer + buildOneTab(current_qco,  qcodom.getElements("title")[0].getText(), 'QCO');
            //}
            $("qco_tab_area").innerHTML = qco_navigation[0] + buffer + qco_navigation[1];
*/
			showQCO(user_questions[0]);
		}
	}


	//done with qco, show screen
	regulateHeights();

    tabsTotalWidth=content_width - $('mco_logo').offsetWidth - 25 // 25 is a prox-value for scroll-navigation plus a little....
    init_rotatingTabs()
/*
    if(display_mco){
        //set available space for tabs and fill up:
        tabsTotalWidth=content_width - $('mco_logo').offsetWidth - 25 // 25 is a prox-value for scroll-navigation plus a little....
        tabsFillUp(0,1);
        tabsScrollerImages();
    }
*/
    //just make sure....
    $('LoadWrapper').style.display='none';

    if(DEBUG_MODE){db(0,-1, 'done: handleNCO')}
}


/* ---------------------------------------------------------------------------------------------
 * Screen Hook & Content Display Functions
 */


//the following should also set href...
function show_navbutton(id){
	try{ //IE race-condition
		$(id).style.visibility = "visible";
		$(id).style.cursor = "pointer";
		$(id).blur();
	}
	catch(e){
		var a=1;
	}
}
function hide_navbutton(id){
	try{ //IE race-condition
		$(id).style.visibility = "hidden";
		$(id).style.cursor = "default";
		$(id).blur();
	}
	catch(e){
		var a=1;
	}
}



 function showTCO(tco_id) {
    if(DEBUG_MODE){db(0,1, 'call: showTCO')}
    //Displays the contents of the specified TCO.

    //set last tco_XofY-element invisible
    if(current_tco && $('XofY_' + current_tco.getAttribute("id"))){
        currentTCOid = current_tco.getAttribute("id");
        $('XofY_' + currentTCOid).style.visibility='hidden';
        //hide_navbutton("nav_container_next_button_" + currentTCOid);
        //hide_navbutton("nav_container_previous_button_" + currentTCOid);
        hide_navbutton("mco-nav-next-content_" + currentTCOid);
        hide_navbutton("mco-nav-previous-content_" + currentTCOid);
    }

    // Find TCO element to store it globally (yes, it will be used somewhere. use ctrl+f.)
    current_tco = current_nco.getElementById(tco_id);

    //only display XofY-element if there is more than one MCO
    if(current_tco.getElements("MCO").length > 1){$('XofY_' + tco_id).style.visibility='visible';}

    // Clear MCO area to make room for the new shit that's coming along
    $("mco_content").innerHTML = "";

    // Jump to first MCO in this TCO
    requestMCO(current_tco.getElements("MCO")[0].getAttribute("id"));

    updateTCOTabs(); // << change colors
    if(DEBUG_MODE){db(0,-1, 'done: showTCO')}
}


function showTabQCO(tco_id){
    //XXX
    alert('showTabQCO - ' + tco_id);
}


function updateMCONavigationBar(mco_id) {
    /* Feeds the MCO navigation bar with information, such as "page n of x" */
    if(DEBUG_MODE){db(0,1, 'call: updateMCONavigationBar')}

    var mcos = current_tco.getElements("MCO");
    var current_page;
    var currentTCOid=current_tco.getAttribute("id");

    // Calculate total page amount and current page index
    for (var i=0; i<mcos.length; i++) {
        if (mcos[i].getAttribute("id") == mco_id) {
            current_page = i;  // save position
            break;
        }
    }

    // Display amount and index
    $("current_page_" + currentTCOid).innerHTML = current_page+1;  // +1 because counting starts at 0
    $("total_pages_" + currentTCOid).innerHTML = mcos.length;

    // Check if we have to suppress "next page" and/or "previous page"
    // and put the right links to the next/previous MCO.
    if (current_page == 0) {
        hide_navbutton("mco-nav-previous-content_" + currentTCOid);
    } else {
        show_navbutton("mco-nav-previous-content_" + currentTCOid);
        $("mco-nav-previous-content_" + currentTCOid).href = "javascript: requestMCO('" + mcos[current_page-1].getAttribute("id") + "')";
    }

    if (current_page+1 == mcos.length) {
        hide_navbutton("mco-nav-next-content_" + currentTCOid);
    } else {
        show_navbutton("mco-nav-next-content_" + currentTCOid);
        $("mco-nav-next-content_" + currentTCOid).href = "javascript: requestMCO('" + mcos[current_page+1].getAttribute("id") + "')";
    }

    if(DEBUG_MODE){db(0,-1, 'done: updateMCONavigationBar')}
}

function updateTCOTabs() {
    var tco, tco_id;
    var tcos = current_nco.getElements("TCO");
    for (var i=0; i<tcos.length; i++) {
        tco = tcos[i];
        tco_id = tco.getAttribute("id");
        if (tco_id == current_tco.getAttribute("id")) {  // if TCO is current
                //#TODO: change array css_states to get values from there!
                $(tco_id +'_lnk').style.color = COL_FC_ACTIVE;
                for(var te=1; te<5; te++){
                        $(tco_id +'_'+te).style.backgroundColor = COL_TAB_ACTIVE;
                }
        } else if (tcoCompleted(tco)) {  // if TCO is not current but completed
                $(tco_id +'_lnk').style.color = COL_FC_VISITED;
                for(var te=1; te<5; te++){
                $(tco_id +'_'+te).style.backgroundColor = COL_TAB_VISITED;
                }
        } else {  // ... everything else
                $(tco_id +'_lnk').style.color = COL_FC_NOTVISITED;
                for(var te=1; te<5; te++){
                $(tco_id +'_'+te).style.backgroundColor = COL_TAB_NOTVISITED;
                }
        }
    }

}

function showQCO(qco_id) {
    if(DEBUG_MODE){db(0,1, 'call: showQCO');}
    requestFile("../SCO_for_"+current_nco.getAttribute("id")+"/"+qco_id+".html", "qco_content");
    current_question = current_nco.getElementById(qco_id);
    //regulateHeights();
    if(DEBUG_MODE){db(0,-1, 'done: showQCO');}
}

function progressBarUp(){
    done_progRelevant++;
    percent = Math.round(done_progRelevant * 100 / progRelevantItemsCount);
    newProgress(percent);
    //setCookieUserVal(user_name, "done_mcos", String(doneMCOs));
}
function progressBarDown(){
    done_progRelevant--;
    percent = Math.round(done_progRelevant * 100 / progRelevantItemsCount);
    newProgress(percent);
    //setCookieUserVal(user_name, "done_mcos", String(doneMCOs));
}


function newProgress(xpercent){
    if (percent > 100) { percent = 100; } //who-ho !! not honestly!

    $("progbar").style.width = percent.toString() + "%";
    $("prog_counter").innerHTML = TXT_PROGRESS + " " + percent.toString() + "%";
}

function blendCourseWrapper() {
    //should read: display:none.....
    //$("LoadWrapper").style.zIndex = -1;
}



/* ---------------------------------------------------------------------------------------------
 * Recursive Functions
 */

function _collectCookieStoreableItems(domobj){
        //collects all content (NCO, TCO, QCO)
        //into a flat list (indexCookiePosition)
        if(DEBUG_MODE){db(0,1,'call: _collectCookieStoreableItems');}
        var i, j, k;
        var ncos=domobj.getElements("item");
        for(i=0;i<ncos.length; i++){
                //NCO:
                //we do not store NCOS;
                //NCO can go and determine its state by itself...

                var tcos=ncos[i].getElements('TCO')
                for(j=0;j<tcos.length; j++){
                        //TCO:
                        //if(DEBUG_MODE){db(0,0,tcos[j].getAttribute('id'));}
                        indexCookiePosition.push(tcos[j].getAttribute('identifier'))

                        if(ncos[i].getAttribute('isACO')=="false" && tcos[j].getAttribute('always_completed')=="False"){
							progRelevantItemsCount+=1;
						}
						if(tcos[j].getAttribute('always_completed')=="True"){
							user.states.setState(tcos[j].getAttribute("identifier"), 'completed');
						}
                }
                var qcos=ncos[i].getElements('QCO')
                for(k=0;k<qcos.length; k++){
                        //QCO:
                        //if(DEBUG_MODE){db(0,0,qcos[k].getAttribute('id'));}
                        //store position of the exam; scores are simply ordered by appearance
                        indexExamPosition.push(indexCookiePosition.length)
                        indexCookiePosition.push(qcos[k].getAttribute('identifier'))

					qs=qcos[k].getElements('Q')
					for(var n=0; n < qs.length; n++){
						indexCookiePosition.push(qs[n].getAttribute('identifier'))
					}

                }

                //store finalExam as well... (but push out of progRelevantItemsCount !)
                if(ncos[i].getAttribute('isFinalQuest')=='true'){
                        finalExamId=ncos[i].getAttribute('identifier')
                        indexExamPosition.push(indexCookiePosition.length);
                        indexCookiePosition.push(finalExamId)
                }

                //subitems?
                if(ncos[i].getElements('item').length>0){
                        _collectCookieStoreableItems(ncos[i])
                }
        }
        if(DEBUG_MODE){db(0,-1,'done: _collectCookieStoreableItems');}
}

function closeCourse(){
    window.top.close();
}

function insertEndFunction(){
    //$$DISPLAY_ENDFUNCTION$$
    var aco_row = document.createElement('tr');
    var aco_icon_cell = document.createElement('td');
    aco_icon_cell.innerHTML = '<img src="../../resources/' + ICON_ACO + '" border="0" heigth="18" width="18"/>';
    var aco_node = document.createElement('td');
    var aco_href = document.createElement('a');
    aco_href.setAttribute('id', 'aco_ENDCOURSE');
    aco_href.setAttribute('href','javascript:closeCourse();');
    aco_href.appendChild(document.createTextNode(TXT_ENDFUNCTION));
    aco_node.appendChild(aco_href);
    aco_row.appendChild(aco_icon_cell);
    aco_row.appendChild(aco_node);
    aco_table.appendChild(aco_row);
}



function _fillTree(domobj, parentId) {
    var identifier, id, title;
    var icon = nco_state_images['unknown'];

    identifier = domobj.getAttribute("identifier");
    //id= domobj.getAttribute("id");
    title = domobj.getElements("title")[0].getText();

    if(OFFLINE_MODE && domobj.getAttribute('isACO')=='true'){
        //insert item in ACO-area

        var aco_row = document.createElement('tr');
		var aco_icon_cell = document.createElement('td');
		aco_icon_cell.innerHTML = '<img src="../../resources/' + ICON_ACO + '" border="0" heigth="18" width="18"/>';
        var aco_node = document.createElement('td');
        var aco_href = document.createElement('a');
		aco_href.setAttribute('id', 'aco_' + identifier);
        aco_href.setAttribute('href','javascript:fireTreeElement(\'' + identifier + '\')');
        aco_href.appendChild(document.createTextNode(title));
        aco_node.appendChild(aco_href);
		aco_row.appendChild(aco_icon_cell);
		aco_row.appendChild(aco_node);
        aco_table.appendChild(aco_row);

    }else{
        //insert tree item
        tree.insertNewChild(parentId, identifier, title, fireTreeElement, icon, icon, icon);
    }

    // Continue recursion
    var items = domobj.getElements("item");
    if (items.length > 0) {
        for (var i=0; i<items.length; i++) {
            _fillTree(items[i], identifier);
        }
    }
}



/* ---------------------------------------------------------------------------------------------
 * Screen Positioning
 */

function isIE(){
        if(document.all){return true;}else{return false;}
}


function getDocHeight(){
        if (window.innerHeight){
                return self.innerHeight;
        }else if (document.documentElement && document.documentElement.clientHeight){
                // Explorer 6 Strict Mode
                return document.documentElement.clientHeight;
        } else if (document.body){ // other Explorers
                return  document.body.clientHeight;
        }
}

function getDocWidth(){
        if (window.innerWidth){
                return self.innerWidth;
        }else if (document.documentElement && document.documentElement.clientWidth){
                // Explorer 6 Strict Mode
                return document.documentElement.clientWidth;
        } else if (document.body){ // other Explorers
                return  document.body.clientWidth;
        }
}


/* ---------------------------------------------------------------------------------------------
 * Cookies & Internal DOM
 */


function redrawTree(){
        //runs through every tree-item and sets icons according to user.states
         if(DEBUG_MODE){db(0,1, 'call: redrawTree')}

        var state;
        var items = tree.getAllSubItems(0).split(",");
        for (var i=0; i<items.length; i++) {
                state=state2String(user.states.getState(items[i]));
                tree.setItemImage2(items[i], nco_state_images[state], nco_state_images[state], nco_state_images[state]);
    }

         if(DEBUG_MODE){db(0,-1, 'done: redrawTree')}
}

function _setTreeStates(){
        //runs through every tree-item and sets user.states for NCOs/finalExam
         if(DEBUG_MODE){db(0,1, 'call: _setTreeStates')}

        var state, item;
        var items = tree.getAllSubItems(0).split(",").reverse(); //walk tree upside down to determine states properly...

        for (var i=0; i<items.length; i++) {
                //ID// item=xmldom.getElementById(items[i]);
                item=getElementByIdentifier(xmldom, items[i]);
                user.states.setState(items[i], ncoDetermineState(item))
    }

         if(DEBUG_MODE){db(0,-1, 'done: _setTreeStates')}

}


function changeNCOStates(nco_id){
    //recursively walk up the tree:
    if(DEBUG_MODE){db(0,1, 'call: changeNCOStates')}

    //#TODO:SCORM Mode
    if(OFFLINE_MODE){
        if(nco_id != course_identifier) {  // item is not root of the tree
                var parent = tree.getParentId(nco_id)
                //if self is incomplete, so are all parents !
                if(user.states.getState(nco_id)==0){
					user.states.setState(parent, 'incomplete')
				}else{
					//check, if parent fullfills completeness-conditions
					//and set state accordingly
					user.states.setState(parent, (ncoCompletedById(parent)) ? 'completed' : 'incomplete');
				}
            if(DEBUG_MODE){db(1,0, 'recurse: changeNCOStates')}
            changeNCOStates(parent)
		}
    }

	if(SCORM_MODE){
        if(DEBUG_MODE){db(0,0, '!!! scorm for changeNCOStates !!!')}
        //doLMSSetValue('cmi.core.lesson_status', user.states.getState(nco_id))

    }

    if(DEBUG_MODE){db(0,-1, 'done: changeNCOStates')}
}





function setMCOState(mco_id, state) {

    if(DEBUG_MODE){db(0,1, 'call: setMCOState')}

    // Set state in internal DOM tree
    mco = current_tco.getElementById(mco_id);
    if(DEBUG_MODE){db(1,0, mco_id + '->' + state + '(dom_attribute!!)')}

    mco.addAttribute("state", state); //should we not store this in user.states as well?! mmmh.
    if(state=='completed'){
            mco_index[mco.getAttribute('id')]=1;
    }

    var tcos = current_nco.getElements("TCO");
    var mcos = current_tco.getElements("MCO");

    // Check if TCO is completed
    var tco_completed = tcoCompleted(current_tco);
    //set TCO-State accordingly:
    old_tco_state=user.states.getState(current_tco.getAttribute("id"))
    user.states.setState(current_tco.getAttribute("id"), (tco_completed) ? 'completed' : 'incomplete');
	if(SCORM_MODE && USE_COOKIES){
		scoCookieStates[current_tco.getAttribute("cookieIndex")]=(tco_completed) ? '1' : '0';
	}

	if(tco_completed && old_tco_state != 1 && DISPLAY_PROGRESS){
			progressBarUp();
	}

    //check, if NCO is completed as well
    current_nco_id=current_nco.getAttribute("id");
	var completeness=ncoCompleted(current_nco);
    //old_nco_state=user.states.getState(current_nco_id);
    new_nco_state= (completeness) ? 'completed' : 'incomplete';
	//new (more) states
	if (completeness=='passed' && PASSED2COMPLETED==false){
		new_nco_state='passed';
	}
    user.states.setState(current_nco_id, new_nco_state);

    if(SCORM_MODE){
		//alert('before: ' + doLMSGetValue('cmi.core.lesson_status'));

        doLMSSetValue('cmi.core.lesson_status', new_nco_state);

        //alert('aft: ' + doLMSGetValue('cmi.core.lesson_status'));
		var result=doLMSCommit();
        db(3,0,'setMCOState -- LMS.core.lesson_status is now ' + new_nco_state )
    }
    if(OFFLINE_MODE){
        changeNCOStates(current_nco_id);
        redrawTree();
    }

    if(DEBUG_MODE){db(0,-1, 'done: setMCOState')}
}



//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------
function _setMCOState(mcoId, state, dataXMLDoc){

    if(DEBUG_MODE){db(0,1, 'call: _setMCOState')}

    if(state=='completed'){
            mco_index[mcoId]=1;
    }

    var _NCO = dataXMLDoc;
    var _TCO = _NCO.getElementById(mcoId).parent

    // Check if TCO is completed
    var tco_completed = tcoCompleted(_TCO);
    var old_tco_state = user.states.getState(_TCO.getAttribute("id"))
    user.states.setState(_TCO.getAttribute("id"), (tco_completed) ? 'completed' : 'incomplete');
	if(SCORM_MODE && USE_COOKIES){
		scoCookieStates[_TCO.getAttribute("cookieIndex")]=(tco_completed) ? '1' : '0';
	}

	if(tco_completed && old_tco_state != 1 && DISPLAY_PROGRESS){
			progressBarUp();
	}

    //check, if NCO is completed as well
	//var completeness=ncoCompleted(_NCO.getAttribute("id"));
    var completeness=ncoCompleted(_NCO);
    new_nco_state= (completeness) ? 'completed' : 'incomplete';
	if (completeness=='passed' && PASSED2COMPLETED==false){
		new_nco_state='passed';
	}
    user.states.setState(_NCO.getAttribute("id"), new_nco_state);

    if(SCORM_MODE){
        doLMSSetValue('cmi.core.lesson_status', new_nco_state);
		var result=doLMSCommit();
        db(3,0,'setMCOState -- LMS.core.lesson_status is now ' + new_nco_state )
    }
    if(OFFLINE_MODE){
        changeNCOStates(_NCO.getAttribute("id"));
        redrawTree();
    }

    if(DEBUG_MODE){db(0,-1, 'done: _setMCOState')}
}
//-----------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------



/* ---------------------------------------------------------------------------------------------
 * Various Helper Functions
 */

 function getSuffix(fname){
    return fname.substr(fname.indexOf('.') + 1);
}

function fireTreeElement(element) {
    if(DEBUG_MODE){db(0,1, 'call: fireTreeElement')}

    if (element == course_identifier) { //top node
        if(DEBUG_MODE){db(0,-1, 'ret: fireTreeElement: top node')}
        tree._unselectItem(tree._globalIdStorageFind(course_identifier))
        if(current_nco.getAttribute('isACO')!="true"){
            tree._selectItem(tree._globalIdStorageFind(current_nco.getAttribute('id')))
        }
        return;
    }else{
		$('LoadWrapper').style.display='block';
	}

    //change State (if "unknown") to "incomplete"
    if(user.states.getState(element)==-1){
            user.states.setState(element, 'incomplete');
            if(element==finalExamId){
                    redrawTree();
            }
    }

	if(current_nco){
		if(current_nco.getAttribute('isACO')=="true"){ //unselect former ACO
			$('aco_' + current_nco.getAttribute('id')).style.backgroundColor="transparent";
			$('aco_' + current_nco.getAttribute('id')).style.color= COL_TREE_STD_FC;
		}
	}
    requestNCO("../SCO_for_"+element+"/data.xml");


    //we can use xmldom here, since this will not be called in SCORM-Mode...
    if(getElementByIdentifier(xmldom, element).getAttribute('isACO') != 'true'){
        //close siblings
        var siblings = tree.getSubItems(tree.getParentId(element)).split(",");
        for (var i=0; i<siblings.length; i++) {
            tree.closeItem(siblings[i]);
        }

        tree.openItem(element);

    }else{
		tree._unselectItems()
		//$('aco_'+ element).style.backgroundColor = COL_TAB_NOTVISITED;
		$('aco_'+ element).style.backgroundColor = COL_TREE_HIGHLIGHT_BG;
		//$('aco_'+ element).style.color="white";
		$('aco_'+ element).style.color = COL_TREE_HIGHLIGHT_FC;
	}

    if(DEBUG_MODE){db(0,-1, 'done: fireTreeElement')}
}



function tcoCompleted(tco) {

	if(user.states.getState(tco.getAttribute('id'))==1 || tco.getAttribute('always_completed')=='True'){
		return true;
	}else{
		//determine by mcos...
		var mcos = tco.getElements("MCO");
		for (var i=0; i<mcos.length; i++) {
			if (mco_index[mcos[i].getAttribute("id")] != 1) {
				return false;
			}
		}
		//user.states.setState(tco.getAttribute('id'), 'completed')
		return true;
	}
}




function ncoDetermineState(nco){

    if(DEBUG_MODE){db(0,0, 'call: ncoDetermineState - ' + nco.getAttribute('identifier'));}

        var ncoState='unknown';
        var qcosDone=0;
        var tcosDone=0;
        var ncosDone=0;

        if(nco.getAttribute('isFinalQuest')=='true'){
                ncoState = user.states.getState(nco.getAttribute('identifier'));
                   if(DEBUG_MODE){db(0,-1, 'done: ncoDetermineState (finalexam) - ' + ncoState)}
            return state2String(ncoState);
        }

        //check QCO
        var qcos = nco.getElements('QCO');
        if(! qcos.length){
			qcos=new Array();
		}else{
			var qId=qcos[0].getAttribute('identifier');
			if(user.states.getState(qId) ==1 ){ //marked as done - evaluate score
				var uScore=user.scores.getOverallScore(qId);
				var mScore=parseInt(qcos[0].getAttribute('max_score'));
				if(uScore * 100 / mScore >= parseInt(qcos[0].getAttribute('mastery_threshold'))){
					user.states.setState(qId, 4)
					return 4;
				}else{
					user.states.setState(qId, 3)
					return 3;
				}
			}

		}

        for(i=0; i < qcos.length; i++){
            if(user.states.getState(qcos[i].getAttribute('identifier'))==1){
                    qcosDone += 1;
            }
        }

    //get TCOs
    var tcos = nco.getElements('TCO');
    var i;
    var tcos_NotDoneButAlwaysComplete = 0;
    if(! tcos.length){tcos=new Array();}
    for(i=0; i < tcos.length; i++){
            if(user.states.getState(tcos[i].getAttribute('identifier'))==1 && tcos[i].getAttribute('always_completed')=="False"){
                    tcosDone += 1;
            }
            if(tcos[i].getAttribute('always_completed')=="True"){
                    tcos_NotDoneButAlwaysComplete += 1;
            }


    }

    var ncos = nco.getElements('item'); //TODO: kill finalExam from this list
    if(! ncos.length){ncos=new Array();}
        for(i=0; i < ncos.length; i++){
                if (user.states.getState(ncos[i].getAttribute('identifier'))==0){ //incomplete
                         if(DEBUG_MODE){db(0,-1, 'ret (break): ncoDetermineState - incomplete')}
                        return 'incomplete'
                }
                if(user.states.getState(ncos[i].getAttribute('identifier'))==1|| user.states.getState(ncos[i].getAttribute('identifier'))==3|| user.states.getState(ncos[i].getAttribute('identifier'))==4){
                        ncosDone += 1;
                }
        }

    /*if(DEBUG_MODE){

            db(3,0, 'qcos.length ' + qcos.length)
            db(3,0, 'qcosDone ' + qcosDone)
            db(3,0, 'tcos.length ' + tcos.length)
            db(3,0, 'tcosDone ' + tcosDone)
            db(3,0, 'ncos.length ' + ncos.length)
                db(3,0, 'ncosDone ' + ncosDone)
    }*/

    if( (ncosDone==ncos.length && qcosDone==qcos.length && qcos.length > 0) || (tcosDone + tcos_NotDoneButAlwaysComplete == tcos.length && ncosDone == ncos.length && qcos.length==0) ){
            ncoState='completed'
    }else{
            ncoState=(ncosDone==0 && tcosDone==0) ? 'unknown' : 'incomplete';
    }


    //if(DEBUG_MODE){db(0,-1, 'done: ncoDetermineState - ' + ncoState)}
    return ncoState;
}


function ncoCompleted(nco) {
    if(DEBUG_MODE){db(0,1, 'call: ncoCompleted');
                   //tree.selectItem(nco.getAttribute('id'))
    }

	var qcos = nco.getElements('QCO');

    if(SCORM_MODE){
        nco_subitems=new Array();
		if(qcos.length==0 && doLMSGetValue("cmi.core.lesson_status") == 'completed') {
			if(DEBUG_MODE){db(0,-1, 'ret byLMS - true')}
				return true
		}
    }

    if(OFFLINE_MODE){
		itemId=(nco.getAttribute('id')) ? nco.getAttribute('id') : nco.getAttribute('identifier') //organization
        nco_subitems=tree.getSubItems(itemId);
        nco_subitems=(nco_subitems==0 || nco_subitems.length==0) ? new Array() : nco_subitems.split(',');
    }

    if(nco.getAttribute('isFinalQuest')=='true'){
        var retval = (user.states.getState(nco.getAttribute('id'))==1) ? true : false;
           if(DEBUG_MODE){db(0,-1, 'ret: nco is final exam. completed:' + retval)}
        return retval;
    }

    if(qcos.length>0){
		 if(SCORM_MODE){
			user.states.setState(qcos[0].getAttribute('id'), doLMSGetValue("cmi.core.lesson_status"));
		}
		var retval = (user.states.getState(qcos[0].getAttribute('id'))==1) ? true : false;
		//new (more) states
		if (user.states.getState(qcos[0].getAttribute('id'))==4){
			if(DEBUG_MODE){db(3,-1, 'ret: nco has qco. -> passed')}
			return 'passed';
		}
		if(DEBUG_MODE){db(3,-1, 'ret: nco has qco. completed:' + retval)}
        return retval;
    }

    //get TCOs as well
    //in the recursion, which runs over the tree in offline-mode,
    //this only works with TCO/QCO-Tags under <item> in imsmanifest.xml !!!
    var tcos = nco.getElements('TCO');
    for(i=0; i < tcos.length; i++){
		var tcoId= (tcos[i].getAttribute('identifier'))? tcos[i].getAttribute('identifier') : tcos[i].getAttribute('id');
		nco_subitems.push(tcoId)
	}

    //#TODO: put NCOs in nco_subimtes as well for SCORM-Mode


    for (var i=0; i < nco_subitems.length; i++) {
        if(user.states.getState(nco_subitems[i]) != 1 && user.states.getState(nco_subitems[i]) != 4){ //completed, passed
			//we do not have states in the tree for SCORM-Mode....
			//yet, we want to set them and use them here to determine completeness.
            if(DEBUG_MODE){db(0,-1, 'ret: ncoCompleted=false')}
            return false;
        }
    }
    if(DEBUG_MODE){db(0,-1, 'ret: ncoCompleted=true')}
    return true;
}

function ncoCompletedById(nco_id) {
    //ID//nco=xmldom.getElementById(nco_id);
    nco=getElementByIdentifier(xmldom, nco_id);
    ret=ncoCompleted(nco);
    return ret;
}



function reportError(message) {

    //alert("Error:\n"+message);
    if(message && message != ''){
        alert(msg);
     }

}

/* ---------------------------------WE NEED MORE CORE--------------------------------- */

function showFeedbackPage() {
    if(DEBUG_MODE){db(0,1, 'call: showFeedbackPage')}

    //DEBUG
    //user_questions = 0;



    if(!user_questions){user_questions=0;}
    if (user_questions == 0) {

        $('nav_button_current_tasks').style.display='none';

        if (OFFLINE_MODE) {
            var course_identifier = course.getAttribute("identifier");
        } else {
            var course_identifier = "morecore";
        }

        $("qco_content").innerHTML = "";

        user_score_percent = parseInt(user_score * 100 / max_score);  // Calculate percent
        var _fb = (user_score_percent >= parseInt(mastery_treshold)) ? 'finalFB_passedOrSimple' : 'finalFB_failed';

        if(DEBUG_MODE){db(2,0, 'user_score_percent: ' + user_score_percent)
                                           db(2,0, 'final_feedback: ' + final_feedback)}

        if (final_feedback == "simple") {
            requestFileCB("../../" + current_nco.getElements('QCO')[0].getElements('finalFB_passedOrSimple')[0].getText(), onShowFeedback);
            //requestFileCB("../../" + questions[0].getElements("properties")[0].getElements("href_fb_simple")[0].getText(), onShowFeedback);
        }
        else if (final_feedback == "result") {
            requestFileCB("../../" + current_nco.getElements('QCO')[0].getElements(_fb)[0].getText(), onShowFeedback);
        }
        else if (final_feedback == "detailed") {
                var fb_buffer, fb_headline, fb_state_icon, q_icon;
                fb_buffer='';
                /*
                if(user_score_percent >= parseInt(mastery_treshold)){
                        fb_headline='Herzlichen Gl&uuml;ckwunsch!<br>Sie haben den Abschlusstest bestanden.';
                        fb_state_icon='<img src="../../resources/icon_passed.gif" />';
                }else{
                        fb_headline='Sie haben den Abschlusstest leider nicht bestanden.';
                        fb_state_icon='<img src="../../resources/icon_failed.gif" />';
                }
                */
                fb_buffer=fb_buffer +'<center>'
                /*
                fb_buffer=fb_buffer + '<table border=0><tr><td valign=top>' + fb_state_icon + '</td>';
                fb_buffer=fb_buffer + '<td valign=top align=center><bR><bR><h2>' + fb_headline + '</h2>';

                fb_buffer=fb_buffer + '</td></tr></table><br><br>';
                */


                fb_buffer=fb_buffer + '<div id="feedback_header"></div><br>';
                fb_buffer=fb_buffer + '<h3>Sie haben ' + user_score + ' von ' + max_score + ' Punkten erreicht.</h3>';
                fb_buffer=fb_buffer + '<table border=0><tr><td valign="top" align="left">';

                var i =0;
                var _cols=3;


                for (var v = 0; v  < _cols; v++){
                    for (i; i<questions.length/_cols * (v+1); i++) {
                        q_score=parseInt(questions[i].getElements("properties")[0].getElements("maxScore")[0].getText());
                        user_q_score=user.scores.getQuestionScore(current_qco, questions[i].getAttribute('id'));
                        questiontext = questions[i].getElements("properties")[0].getElements("question")[0].getText();

                        /*
                        if(user_q_score==q_score)  {q_icon='Icon_feedback_positive_20.gif';}
                        if(user_q_score < q_score) {q_icon='Icon_feedback_mixed_20.gif';}
                        if(user_q_score == 0)           {q_icon='Icon_feedback_negative_20.gif';}
                        */
                        if(user_q_score==q_score)  {q_icon=ICON_DETAILEDFB_CORRECT;}
                        if(user_q_score < q_score) {q_icon=ICON_DETAILEDFB_SEMI;}
                        if(user_q_score == 0)           {q_icon=ICON_DETAILEDFB_WRONG;}

                        fb_buffer=fb_buffer + '<nobr><img style="float:left;" width=20 height=20 src="../../resources/' + q_icon + '"/>';
                        fb_buffer=fb_buffer + '&nbsp; <b>Frage ' + (i+1) + '</b></nobr><br />';
                        fb_buffer=fb_buffer + '&nbsp; Punkte: ' + user_q_score + ' von ' + q_score;

                        fb_buffer=fb_buffer + '<br><br> ';

                    }

                    fb_buffer=fb_buffer + '</td><td>&nbsp;&nbsp;&nbsp;&nbsp;</td><td valign="top" align="left">';
                }

                fb_buffer=fb_buffer + '</td></tr></table>';
                fb_buffer=fb_buffer + '</center>';

                $("qco_content").innerHTML = fb_buffer;
                requestFileCB("../../" + current_nco.getElements('QCO')[0].getElements(_fb)[0].getText(), onShowFeedback_detailed);

        }
       //displayQCOButtons();

        //set state according to the users results if this exam was not done before:
        if(user.states.getState(current_qco) != 1 && user.states.getState(current_qco) != 3 && user.states.getState(current_qco) != 4) {
            if (user_score_percent >= mastery_treshold) {
                //set qco-state to completed
                user.states.setState(current_qco, 'passed');
                //set nco-state to completed
                user.states.setState(current_nco.getAttribute("id"), 'passed');

				if(SCORM_MODE || (_OFFLINE_SCORM && final_exam)){
                    newQCOState=(PASSED2COMPLETED) ? 'completed' : 'passed';
					doLMSSetValue("cmi.core.lesson_status",  newQCOState);
					doLMSCommit();

					if(DEBUG_MODE){db(3,0, 'cmi.core.lesson_status is now <' + newQCOState + '>')}
				}

				//move progressBar, if not final exam
                //if(!final_exam && DISPLAY_PROGRESS){progressBarUp();}
				//well, or don't, according to newer decisions

            } else {
                user.states.setState(current_nco.getAttribute("id"), 'failed');
				if(SCORM_MODE || (_OFFLINE_SCORM && final_exam)){
							newQCOState=(PASSED2COMPLETED) ? 'completed' : 'failed';
							doLMSSetValue("cmi.core.lesson_status", newQCOState);
							doLMSCommit();
							if(DEBUG_MODE){db(3,0, 'cmi.core.lesson_status is now <' + newQCOState + '>')}
				}
            }
        }

        if (OFFLINE_MODE){
            changeNCOStates(current_nco.getAttribute('id'));
            redrawTree();
        }


    } else { //user_questions != 0

        if (show_feedback) {
            if (answered_correct == -1) {
                // Show feedback page for incorrect answer
                requestFile("../../" + current_question.getElements("properties")[0].getElements("href_FB_wrong")[0].getText(), "qco_content");
            }
            else if (answered_correct == 2) {
                // Show feedback page for semi correct answer
                requestFile("../../" + current_question.getElements("properties")[0].getElements("href_FB_semi")[0].getText(), "qco_content");
            }
            else if (answered_correct == 3) {
                // Show feedback page for correct answer
                requestFile("../../" + current_question.getElements("properties")[0].getElements("href_FB_correct")[0].getText(), "qco_content");
            } else {
                showQCO(user_questions[0]);
            }

        } else {
            showQCO(user_questions[0]);
        }

    }

    $("current_tasks").innerHTML = user_questions.length;
    if(DEBUG_MODE){db(0,-1, 'done: showFeedbackPage')}
}


function onShowFeedback(response) {
    $("qco_content").innerHTML = response.responseText;
    displayQCOButtons();
}

function onShowFeedback_detailed(response) {
    $("feedback_header").innerHTML = response.responseText;
    displayQCOButtons();
}


function onMCOLoaded(response){
    if(DEBUG_MODE){db(0,1,'call: onMCOLoaded')}
    $("mco_content").innerHTML=response.responseText;

    if(SCORM_MODE && USE_FINISH_LU_BUTTON && mco_type != 'flash'){
        if(user.states.getState(current_nco.getAttribute('id'))==1){
            displayFinishLU();
        }
    }

	//$('LoadWrapper').style.zIndex=-1;
	//$('LoadWrapper').style.visibility='hidden';

	//Hide flashscreen
	$('LoadWrapper').style.display='none';

    if(DEBUG_MODE){db(0,-1,'done: onMCOLoaded')}
}


function displayQCOButtons() {
    if(DEBUG_MODE){db(0,1,'call: displayQCOButtons');}
    var button_code;

    button_code='<p style="float:right; margin-right:10px; padding:5px;">';
    button_code=button_code + '<a class="body_button" id="nav_button_rewind" href="javascript:rewindQCOCycle();"><span id="rewind_button">' + EXAMBUTTON_REPEAT + '</span></a>';



    if(final_exam){
            if(user_score_percent >= mastery_treshold){

                    //button_code=button_code + '&nbsp; &nbsp; <a class="body_button" id="nav_button_certificate" href="javascript:certificatePreview();"><span id="certificate_button">' + EXAMBUTTON_CERTIFICATE + '</span></a>';

                if(USE_CERTCENTER){
                    var certCenterURL = mkCertCenterURL();
                    var certCode='<br><br><center><small><fieldset style="width:96%;">' + certCenterURL + '</fieldset></small></center><bR/>';
                    button_code=button_code + '&nbsp; &nbsp; <a class="body_button" id="nav_button_certificate" href="'+certCenterURL+'" target="_blank"><span id="certificate_button">' + EXAMBUTTON_CERTIFICATE + '</span></a>';
                    button_code = certCode  + button_code;
                }

                if(USE_CERTIFICATE){

                    //transmit values?!

                    button_code=button_code + '&nbsp; &nbsp; <a class="body_button" id="nav_button_certificate" href="../../resources/certificate_fs.html" target="_blank"><span id="certificate_button">' + EXAMBUTTON_CERTIFICATE + '</span></a>';
                    //button_code =  button_code;


                }



            }
    }else{
            if($('nav_button_save')){
                    $('nav_button_save').style.display='none';
            }

    }

    button_code = button_code + "</p>";
    $("qco_content").innerHTML = $("qco_content").innerHTML + button_code;


	//silently alert certificate-center (should be online...))
	if(final_exam && CERTCENTER_URL != '' && CERTCENTER_RUNSILENT=='True' && user_score_percent >= mastery_treshold){
        db(0,0, 'running CertCenter silently');
	    $("qco_content").innerHTML = $("qco_content").innerHTML + '<br><center><iframe id="cert_msg" style="visibility:hidden;"> </iframe></center>';
		var cert_url = CERTCENTER_URL+ '?key=' +CERTCENTER_PREFIX + '-' + COURSE_ID.substr(0,12) + '&id=' + user.username;
		//alert(cert_url)
		//rpc-call ist not allowed: requestFile(cert_url, 'cert_msg');
		//so iframe:
		$('cert_msg').src=cert_url;
	}

    if(DEBUG_MODE){db(0,-1,'done: displayQCOButtons');}
}


function displayFinishLU(){
    if(DEBUG_MODE){db(0,1,'call: displayFinishLU');}
    var button_code;

    button_code='<p style="float:right; margin-right:10px;">';
    button_code=button_code + '<a class="body_button" id="nav_button_finishLU" href="javascript:finishLearningUnit();"><span id="finishLU_button">Lerneinheit beenden</span></a>';
    button_code=button_code + '</p>';

    $("mco_content").innerHTML = $("mco_content").innerHTML + button_code;

    if(DEBUG_MODE){db(0,-1,'done: displayFinishLU');}
}


function rewindQCOCycle() {
    user.scores.resetScore(current_qco);
    user.states.setState(current_qco, 'incomplete');
	user.states.setState(current_nco.getAttribute('id'), 'incomplete');
    //if(!final_exam && DISPLAY_PROGRESS){
    //        progressBarDown();
    //}
    changeNCOStates(current_nco.getAttribute('id'));

    if (OFFLINE_MODE) {
        redrawTree();
    }

    if(SCORM_MODE){
        doLMSSetValue('cmi.core.score.raw', 0);
        doLMSSetValue('cmi.core.lesson_status', 'incomplete');
        doLMSCommit();
	}
	user_questions = new Array();
	for (var i=0; i<questions.length; i++) {
		// Build cycle
		user_questions.push(questions[i].getAttribute("id"));
		user.states.setState(questions[i].getAttribute("id"),-1)

		if (USE_COOKIES){
			scoCookieStates[questions[i].getAttribute("cookieIndex")]='0' ;
		}
	}

	max_score=parseInt(qcodom.getAttribute("maxScore"));
	$("current_points").innerHTML = '0';
	$("total_points").innerHTML = max_score;
	$("current_tasks").innerHTML = user_questions.length;


    if (qcodom.getElements("param_showRemainingTasks")[0].getText() == "True") {
            $("nav_button_current_tasks").style.display = "inline";
    } else { $("nav_button_current_tasks").style.display = "none"; }

	showQCO(user_questions[0]);

}




function getQuestionContent(uid) {
    current_question = qcodom.getElementById(uid);
    new Ajax.Updater("qco_content",
        current_question.getAttribute("href"),
        {
            method: "get",
            //onComplete: onGetMCOContent,
            onFailure: reportError
        }
    );
    $("current_tasks").innerHTML = user_questions.length;
}

function evaluateQuestion() {
    if(DEBUG_MODE){db(0,1, 'call: evaluateQuestion')}

    if (document.getElementById("dxQuestForm") != null) {
        var type, answers, checked_item;
        var properties = current_question.getElements("properties")[0];
        type = properties.getElements("type")[0].getText();
        answers = current_question.getElements("answers")[0].getElements("answer");
        answered_correct = 0;
        var user_score_question=0;
        var correct=0;
        /*
            ~ answered_correct values ~
           -1 = incorrect
            0 = unknown
            1 = correct so far (only needed for certain question types)
            2 = particially correct (semi correct)
            3 = correct
        */

        // Evaluate question by determining the question type first
        if (type == "dxQSingleChoice") {
            var alternatives="1"; // string:has length=1.
            for (var i=0; i<answers.length; i++) {
                if ($(answers[i].getAttribute("id")).checked == true) {
                    correct=1;
                }
            }
        }

        else if (type == "dxQTrueFalse") {

            var uAnswers=$("dxQuestForm").elements;
            var alternatives =  new Array();
            for (var i=0; i<uAnswers.length; i++) {
                var uAnswer = uAnswers[i].getAttribute("id").split('##');
                //check only one side (here: false)
                if (uAnswer[2] == 0){
                    alternatives.push('x'); // write just anything, it's only length that counts ;)
                    var dxAnswer_id = uAnswer[1];
                    //has the user answered at all?
                    if($(uAnswer[0]+'##'+uAnswer[1] +'##0').checked || $(uAnswer[0]+'##'+uAnswer[1] +'##1').checked){
                        var realUserAnswer = (uAnswers[i].checked) ? false : true; //something is chekced, we  only look at the "False"-side -- so: if "false" is not checked, "true" is.
                        if(current_question.getElements("answers")[0].getElementById(dxAnswer_id)){
                            /*
                            alternative = current_question.getElements("answers")[0].getElementById(dxAnswer_id).getElements("alternatives")[0].getElements("alternative")[0].getText(); // this should always be true, since only true alternatives are exported....
                            alert(realUserAnswer == alternative);
                            if (realUserAnswer == alternative){
                                correct++;
                            }
                            */
                            if (realUserAnswer) correct++;
                        }else{
                            if (! realUserAnswer) correct++;
                        }
                    }
                }
            }

        }
/*
        else if (type == "MathQuestion") {
            var alternatives = $("dxQuestForm").elements;
            var tolerance = parseFloat(answers[0].getAttribute("tolerance"));
            var correct_answer = parseFloat(answers[0].getElements("alternatives")[0].getElements("alternative")[0].getText());
            var user_answer = parseFloat(alternatives[0].value.replace(",", "."));

            if (((correct_answer-tolerance) <= user_answer) && (user_answer <= (correct_answer+tolerance))) {
                correct=1;
            } else {
                correct=0;
            }
        }
*/
        else if (type == "dxQMatching") {
            var alternatives = $("dxQuestForm").elements;
            var answer_id;
            for (var i=0; i<alternatives.length; i++) {
                answer_id = alternatives[i].getAttribute("id");
                if (alternatives[i].value == current_question.getElements("answers")[0].getElementById(answer_id).getElements("alternatives")[0].getElements("alternative")[0].getText()) {
                    correct++;
                }
            }
        }

        else if (type == "dxQMultipleChoice") {
            var alternatives = $("dxQuestForm").elements;
            var answer_id;
            for (var i=0; i<alternatives.length; i++) {  // go through form collection
                answer_id = alternatives[i].getAttribute("id");
                if (current_question.getElements("answers")[0].getElementById(answer_id)) {
                    if (alternatives[i].checked) {
                        correct++
                    }
                } else {
                    if (!alternatives[i].checked) {
                        correct++;
                    }
                }
            }
        }

        /*
            TODO
            add id for each FG answer alternative
        */
        else if (type == "dxQFillGap") {
            var alternatives = $("dxQuestForm").elements;
            var answer_id, correct_alternatives, answer_correct, case_sensitive;

            for (var i=0; i<alternatives.length; i++) {
                answer_id = alternatives[i].getAttribute("id");
                case_sensitive = current_question.getElements("answers")[0].getElementById(answer_id).getAttribute("caseSensitive");
                correct_alternatives = current_question.getElements("answers")[0].getElementById(answer_id).getElements("alternatives")[0].getElements("alternative");
                answer_correct = false;
                for (var j=0; j<correct_alternatives.length; j++) {
                    if ((case_sensitive == "True") && (alternatives[i].value == correct_alternatives[j].getText())) {
                        answer_correct = true;
                    }
                    if ((case_sensitive != "True") && (alternatives[i].value.toLowerCase() == correct_alternatives[j].getText().toLowerCase())) {
                        answer_correct = true;
                    }
                }
                if (answer_correct) {
                    correct++;
                }
            }
        }


        //done with the questions;
        //calculate score.
        if (correct == alternatives.length) {
            answered_correct = 3;
            user_score_question=parseInt(properties.getElements("maxScore")[0].getText());
        }
        else if (correct != 0) {
            answered_correct = 2;
            user_score_question=parseInt(properties.getElements("maxScore")[0].getText() / alternatives.length * correct);
        }
        else {
            answered_correct = -1;
            user_score_question=parseInt(properties.getElements("maxScore")[0].getText() / alternatives.length * correct);
        }
        var __strict =properties.getElements("strict")[0].getText()
        if (__strict == "True") {
            if (answered_correct == 3) {
                user_score_question=parseInt(properties.getElements("maxScore")[0].getText());
            }else{
                answered_correct = -1;
            }
        }



        //store score for each question; objScore can add by itself...
        user.scores.setQuestionScore(current_qco, current_question.getAttribute('id'), user_score_question)
        user_score=user.scores.getScore(current_qco);
        user_score_percent=parseInt(user_score * 100 / max_score);

	if(SCORM_MODE){
	    //send user score to LMS
	    doLMSSetValue('cmi.core.score.raw', user_score);
	    doLMSCommit();
	}



		if (current_nco.getAttribute('id')==current_qco){	// is finalExam
			user.states.setState(current_question.getAttribute('id'), 'completed')
			if(SCORM_MODE && USE_COOKIES){
				scoCookieStates[current_question.getAttribute("cookieIndex")]='1' ;
			}
			user_questions.shift();
		}else{

			// Move first item to the end of the user array if he answered the
			// question wrong, otherwise just delete the item.
			if (answered_correct != 3) {

				user.states.setState(current_question.getAttribute('id'), 'incomplete')
				var question_id_buffer;
				question_id_buffer = user_questions.shift();
				if (append_to_cycle) {
					user_questions.push(question_id_buffer);
				}
			} else {
				user.states.setState(current_question.getAttribute('id'), 'completed')
				if(SCORM_MODE && USE_COOKIES){
					scoCookieStates[current_question.getAttribute("cookieIndex")]='1' ;
				}
				user_questions.shift();
			}
		}


                //setting overall score for  a finished exam.
                if(user_questions.length==0){
                        user.scores.setOverallScore(current_qco, user_score)
                }

                //update Screen
                if(DEBUG_MODE){
                        db(1,0, 'current points : ' + user_score);
                        db(1,0, 'total points : ' + max_score);
                        db(1,0, 'current tasks : ' + user_questions.length);
                }
                //update Screen:
                $("current_points").innerHTML = user_score;
                $("total_points").innerHTML = max_score;
                $("current_tasks").innerHTML = user_questions.length;

        showFeedbackPage();

    }

    else {
        // Load next question
        showQCO(user_questions[0]);
    }


    if(DEBUG_MODE){db(0,-1, 'done: evaluateQuestion')}
}

function skipQuestion() {
    var question_id_buffer;
    question_id_buffer = user_questions.shift();
    user_questions.push(question_id_buffer);
    showQCO(user_questions[0]);
}

/* ---------------------------------------------------------------------------------------------
 * DHTML-Windows
 */

function zoomOut(id){
    $(id).style.display='none';
}

function maximize(id){
    $('iWinMaxButton').src='../../resources/btn_up2_w.gif'; //downarrow
    $('iWinMaxFunction').href="javascript:minimize(\'internallink\');";
    $(id).style.height=px(getDocHeight() - 50);
    $(id).style.width=px(getDocWidth() - 50);
     if(id=='internallink'){
        $('iWin_content').style.height=px(getDocHeight() - 120);
        $('iWin_content').style.width=px(getDocWidth() - 60);
    }
}
function minimize(id){
    $('iWinMaxButton').src='../../resources/btn_up1_w.gif'; //uparrow
    $('iWinMaxFunction').href="javascript:maximize(\'internallink\');";
    $(id).style.height='400px';
    $(id).style.width='500px';
    if(id=='internallink'){
        $('iWin_content').style.height="330px";
        $('iWin_content').style.width="490px";
    }
}

function zoomImage(id){
    img=$(id);
    img_buffer='<table border="0" cellpadding="0" cellspacing="0"><tr><td class="imagezoom_bg" align="right"><a class="imagezoom_a" href="javascript:zoomOut(\'imagezoom\');">';
    img_buffer=img_buffer + '<img src="../../resources/dx_close_layer.gif" border="0">';
    img_buffer=img_buffer + '</a>&nbsp;</td></tr>'
    img_buffer=img_buffer + '<tr><td>';
    img_buffer=img_buffer + '<img border=1 src="' + img.src + '">'
    img_buffer=img_buffer + '</td></tr></table>';
    $('imagezoom').innerHTML = img_buffer;
    $('imagezoom').style.display='block';
    $('imagezoom').style.top = px(0);
    $('imagezoom').style.left = px(0);
}


function removeAllLinks(baseNode){
    while(baseNode.getElementsByTagName('a')){
       var _element = baseNode.getElementsByTagName('a')[0];
       _element.parentNode.replaceChild(_element.firstChild, _element);
    }
}




function internalLinkWindow(scoPath, tcoId, mcoId){
    //mcoId==mco to be displayed first;
    internalLinkWindow_v2('MCO', scoPath, tcoId, mcoId, 'internal', 490, 330, 'true');
    /*
    var path='../../'  +scoPath + '/data.xml';
    $('internallink').setAttribute('tcoId', tcoId); //transfer tcoId into html-dom
    $('internallink').setAttribute('mcoId', mcoId);
    requestFileCB(path, onInternalLinkXMLLoaded);
    */
}

var __internalLinkWindow;

function onInternalLinkWinLoaded(response){
    __internalLinkWindow.document.body.innerHTML = response.responseText;
    removeAllLinks(__internalLinkWindow.document.body);
}

function internalLinkWindow_v2(mode, scoPath, tcoId, mcoId, target, w, h, resizeable){
    /*
    mode = MCO | FILE
    target =  'window' | 'internal' | 'cascadingWindow'
    w = width
    h = height

               |       internal                   |        window
    --------------------------------------------------------------------------
    FILE  |  iframe, singleFile       |  _blank, singleFile
    --------------------------------------------------------------------------
    MCO  |  load TCO                       |  load TCO in _blank
    --------------------------------------------------------------------------
    */
    /*
    var msg = 'mode: ' + mode;
    msg = msg + '\n'  + 'scoPath: ' + scoPath;
    msg = msg + '\n'  + 'tcoId: ' + tcoId;
    msg = msg + '\n'  + 'mcoId :' + mcoId;
    msg = msg + '\n'  + 'target :' + target;
    msg = msg + '\n'  + 'w: ' + w;
    msg = msg + '\n'  + 'h: ' + h;
    alert(msg)
    */

    var _entityPopup = false;
    if (target == 'cascadingWindow'){
        _entityPopup = true;
        target = 'window';
    }

    var iWin = $('internallinkV2');
    iWin.setAttribute('tcoId', tcoId); //transfer params into html-dom
    iWin.setAttribute('mcoId', mcoId);
    iWin.setAttribute('_w', w);
    iWin.setAttribute('_h', h);
    iWin.setAttribute('target', target);
    iWin.setAttribute('_resizeable', resizeable);

    //prepare window
    if(target=='window'){
        if(mode=='FILE'){
            var fPath = '../../' + scoPath + '/' + mcoId;
            var _params='screenX=0, screenY=0, top=0, left=0';
            if (w != '') {_params = _params + ',width=' + w;}
            if (h != '') {_params = _params + ',height=' + h;}

            if(resizeable == 'true' || resizeable == 'True' || resizeable == '1'){
                _params = _params + ',resizable=yes';}
            else{
                _params = _params + ',resizable=no';
             }

            var s = getSuffix(mcoId);
            isImage = false;
            for (var i=0; i < imageSuffixes.length; i++){
                if (imageSuffixes[i] == s){
                    isImage = true;
                }
            }

            if (isImage){
                var internalWin = window.open('about:blank', 'intWinV2', _params);

                var _pre = '<html><head><style type="text/css">body {margin:0px;';
                if (isIE()){ _pre = _pre + 'text-align:center;';}
                _pre = _pre  + '} </style></head><body>';
                var _post = '<body></html>'
                var _body = '<img src="' + fPath + '" border=0">';

                __internalLinkWindow = internalWin;
                internalWin.document.open();
                internalWin.document.write(_pre + _body +_post);
                internalWin.document.close();
            }else{
                var internalWin = window.open(fPath, 'intWinV2', _params);
           }

        }else if (mode=='MCO'){

            var fPath = '../../' + scoPath + '/' + mcoId  + '.html';
              var _params='location=no, scrollbars=yes';
            if (w != '') {_params = _params + ',width=' + w;}
            if (h != '') {_params = _params + ',height=' + h;}
            if(resizeable == 'true' || resizeable == 'True' || resizeable == '1'){
                _params = _params + ',resizable=yes';}
            else{
                _params = _params + ',resizable=no';
             }

            var internalWin = window.open(fPath, 'intWinV2', _params);

            var _pre = '<html><head><link rel="stylesheet" type="text/css" href="../../resources/css-custom.css" />';
            var _middle= '</head><body id="mco_content" style="border:none;">'
            var _post = '</body></html>'
            __internalLinkWindow = internalWin;

            if(_entityPopup){
                __customPopReferrerDiv = false;
                var _buffer = '<script language="javascript">';
                    _buffer = _buffer +'var popup_params;\n';
                    _buffer = _buffer +'var __customPopReferrerDiv = false;\n';
                    _buffer = _buffer + openCustomPopup.toString().replace('mco_content', 'mco_content_pop');
                    _buffer = _buffer + popupOnBlur.toString().replace('mco_content', 'mco_content_pop');
                    //propably some more....
                _buffer = _buffer +'</script>';

                _middle = _middle  + '<div id="mco_content_pop"></div>';
                _middle = _middle  + '<script language="javascript">';
                _middle = _middle  + "openCustomPopup('../../" + scoPath + '/' + mcoId  + ".html', true);</script>";
                _middle = _middle  + '</script>';
                internalWin.document.open();
                internalWin.document.write(_pre + _buffer  + _middle + _post);
                internalWin.document.close();

            }else{
                internalWin.document.open();
                internalWin.document.write(_pre + _middle + _post);
                internalWin.document.close();
                requestFileCB('../../' + scoPath + '/' + mcoId  + '.html', onInternalLinkWinLoaded);
             }
        }

    }else if(target=='internal'){

        var _buffer= '';
        _buffer=_buffer + '<p class="internallink_bg" align="right">';
        _buffer=_buffer + '<a class="internallink_a" href="javascript:zoomOut(\'internallinkV2\');">(X)</a>&nbsp;&nbsp;'
        _buffer=_buffer + '</p>';

        //window prepared; insert content

        var fPath = '../../' + scoPath + '/'
        if(mode=='FILE'){
            fPath = fPath + mcoId;
            _buffer=_buffer + '<iframe width="' + px(w) + '" height="' + px(h) + '" src="' + fPath +'"></iframe>';
        }else if (mode=='MCO'){

            _buffer=_buffer + '<div id="_iLink2_innerDiv" style="';
            _buffer=_buffer + 'width:' +  px(eval(w) + 12)  +  ';height:' + px(eval(h) + 42) + ';">'
            _buffer=_buffer + '</div>';
        }

        iWin.innerHTML = _buffer;
        iWin.style.display = 'block';
    }

    if (mode == 'MCO'){
        requestFileCB('../../' + scoPath + '/data.xml', onInternalLinkXMLLoaded);
    }

}


var internalLinkNCO;
var internalLinkTCO;

function onInternalLinkXMLLoaded(response){
	if(DEBUG_MODE){db(0,1,'call:onInternalLinkXMLLoaded')}
    var iWin        = $('internallinkV2');
    var iDiv        = $('_iLink2_innerDiv');
    var objDom      = new XMLDoc(response.responseText, reportError);
    var idom        = objDom.docNode;

    //var ncoId   = idom.getAttribute('ncoId');
    var tcoId    = iWin.getAttribute('tcoId');
    var mcoId  = iWin.getAttribute('mcoId');


    internalLinkNCO = idom;
    internalLinkTCO = idom.getElementById(tcoId);


    if (iWin.getAttribute('target') == 'internal'){

        var h       = iWin.getAttribute('_h');
        var w       = iWin.getAttribute('_w');
        var tcoTitle    = internalLinkTCO.getAttribute('title');
        var _buffer='';

        //window-functions
        /*_buffer=_buffer + '<p class="internallink_bg" align="right">';
        _buffer=_buffer + '<a class="internallink_a" id="iWinMaxFunction" href="javascript:maximize(\'internallink\');"><img id="iWinMaxButton" src="../../resources/btn_up1_w.gif" border=0></a>&nbsp;&nbsp;'
        _buffer=_buffer + '<a class="internallink_a" href="javascript:zoomOut(\'internallink\');">(X)</a>&nbsp;&nbsp;'
        _buffer=_buffer + '</p>';
    */
        //tab-wrapper
        _buffer=_buffer + '<table border="0" cellspacing="0" cellpadding="0" width="100%">';
        _buffer=_buffer + '<tr><td rowspan=2 width="80px" valign="bottom">';

        _buffer=_buffer + buildOneTab(tcoId, tcoTitle, 'IWIN')

        _buffer=_buffer + '</td><td width="10000">&nbsp;</td></tr>'; //brrh.
        _buffer=_buffer + '<tr><td height="18px" class="mco_bar" align="right" valign="top">';
        _buffer=_buffer + '    <span style="display: block;">';
        _buffer=_buffer + '        <i style="overflow: hidden; display: block; height: 1px; background-color:white; width:4px;"></i>';
        _buffer=_buffer + '        <i style="overflow: hidden; display: block; height: 1px; background-color:white; width:2px;"></i>';
        _buffer=_buffer + '        <i style="overflow: hidden; display: block; height: 1px; background-color:white; width:1px;"></i>';
        _buffer=_buffer + '    </span>\n';
        _buffer=_buffer + '</td></tr>';
        _buffer=_buffer + '<tr><td colspan=2><div id="iWin_content" style="z-index:2000; height:' + px(h) + ';width:' + px(w) + '"></div></td></tr>';
        _buffer=_buffer + '</table>';

        iDiv.innerHTML=_buffer;
        //minimize('internallink');
        iWin = px(h);
        iWin = px(w);

        showInternalWinMCO(mcoId);

    }else{

        _setMCOState(mcoId, 'completed', idom);

    }


	if(DEBUG_MODE){db(0,-1,'done:onInternalLinkXMLLoaded')}
}

var __customPopReferrerDiv;

function showInternalWinMCO(mcoId){

    var mcos  = internalLinkTCO.getElements('MCO');
    var tcoId = internalLinkTCO.getAttribute("id");

    if(mcos.length>1){
        //mco switcher
        for (var mcoPos=0; mcoPos < mcos.length; mcoPos++){
            if(mcos[mcoPos].getAttribute('id')==mcoId){
                prev_href=(mcoPos==0) ? '#': 'javascript:showInternalWinMCO(\''+ mcos[mcoPos-1].getAttribute('id') + '\')';
                next_href=(mcoPos==mcos.length-1) ? '#': 'javascript:showInternalWinMCO(\''+ mcos[mcoPos+1].getAttribute('id') +'\')';
                break;
            }
        }

        var _prev='mco-nav-previous-content_iWin_' + tcoId;
        var _next='mco-nav-next-content_iWin_' + tcoId;
        $(_prev).href=prev_href;
        $(_next).href=next_href;
        if(prev_href=='#'){hide_navbutton(_prev)}else{show_navbutton(_prev)}
        if(next_href=='#'){hide_navbutton(_next)}else{show_navbutton(_next)}

        $('current_page_iWin_'+tcoId).innerHTML=mcoPos+1;
        $('total_pages_iWin_'+tcoId).innerHTML=mcos.length;

        $('XofY_iWin_' + tcoId).style.visibility='visible';

    }else{
        var mcoPos=0;
        $('XofY_iWin_' + tcoId).style.visibility='hidden';
    }

    var mcoPath='../../' + mcos[mcoPos].getElements('href')[0].getText();
    if(mcos[mcoPos].getAttribute('fullscreen')){
        //open in popup...

        $('iWin_content').innerHTML = '... Sequenz in neuem  Fenster ...'
        __customPopReferrerDiv = $('iWin_content');

        //we have mco-values: use them !

        openCustomPopup(mcoPath, true);

    }else{
        //requestFile(mcoPath, 'iWin_content');
        //instead: call a function when finished, trigger removeAllLinks
        requestFileCB(mcoPath, intenalMCO_CrippleLayerLinks);
    }

    _setMCOState(mcoId, 'completed', internalLinkNCO);

}


function intenalMCO_CrippleLayerLinks(response){
    $('iWin_content').innerHTML = response.responseText;
    removeAllLinks($('iWin_content'));
}


function buildOneTab(tcoId, tco_title, area){
    /*area: IWIN, MCO, QCO
    */

    var tco_id = tcoId;
    if (area == 'IWIN'){
        tco_id = 'iWin_' + tco_id;
    }

    var _buffer='';
    if (area != 'IWIN'){
        _buffer = _buffer +'<td rowspan="2" width="10" valign="bottom" class="tab">\n';
    }

    _buffer=_buffer + '    <table class="tab_table_states" cellpadding="0" cellspacing="0" border="0" id="'+tco_id+'" style="padding:0px; margin:0px"><tr><td align="center">';
    _buffer=_buffer + '                <span style="display: block;">';
    _buffer=_buffer + '                    <b id="'+tco_id+'_1" style="margin: 0pt 4px; padding:0px; overflow: hidden; display: block; height: 1px;  background-color:' + COL_TAB_ACTIVE + ';"></b>';
    _buffer=_buffer + '                    <b id="'+tco_id+'_2" style="margin: 0pt 2px; padding:0px; overflow: hidden; display: block; height: 1px;  background-color:' + COL_TAB_ACTIVE + ';"></b>';
    _buffer=_buffer + '                    <b id="'+tco_id+'_3" style="margin: 0pt 1px; padding:0px; overflow: hidden; display: block; height: 1px;  background-color:' + COL_TAB_ACTIVE + ';"></b>';
    _buffer=_buffer + '                </span>';
    if (area == 'IWIN'){
        _buffer=_buffer + '                <div id="'+tco_id+'_4"><nobr>&nbsp;&nbsp;';
        _buffer = _buffer + tco_title;
    }else{
        var tabLnkFunction = (area=='MCO')  ? 'showTCO' : 'showTabQCO'
        _buffer=_buffer + '                <div id="'+tco_id+'_4" onClick="javascript:' + tabLnkFunction + '(\''+tco_id+'\')"  style="cursor:pointer;  background-color:' + COL_TAB_ACTIVE + ';"><nobr>&nbsp;&nbsp;';
        _buffer = _buffer + '                   <span class="tab_lnk" id="'+tco_id+'_lnk">'+tco_title+'</span>';
    }
    _buffer=_buffer + '                 	&nbsp;&nbsp;</nobr></div>';
    _buffer=_buffer + '            </td>';
    _buffer=_buffer + '			<td valign="bottom" width="3"> <!-- shadow -->';
    _buffer=_buffer + '                <span style="display: block;">';

    _buffer = _buffer + '                <i style="width: 1px; overflow: hidden; display: block; height: 1px;"></i>';
    _buffer = _buffer + '                <i style="width: 2px; overflow: hidden; display: block; height: 1px;"></i>';
    _buffer = _buffer + '                <i style="width: 3px; overflow: hidden; display: block; height: 1px;"></i>';

    _buffer=_buffer + '                </span>';
    _buffer=_buffer + '                <i style="display:block; height:9px; width:3px; background-color:white;"><!-- --></i>';
    _buffer=_buffer + '            </td>';

    _buffer=_buffer + '        </tr><tr><td height="18px" class="mco_bar" align="center">';
    _buffer=_buffer + '                <nobr>';

    _buffer=_buffer + '                &nbsp;<b class="nav_status" id="XofY_'+tco_id+'" style="visibility:hidden;">';
    _buffer=_buffer + '                    <a href="#" id="mco-nav-previous-content_'+tco_id+'"><img src="../../resources/' + ARROW_PREV + '" id="nav_container_previous_button_'+tco_id+'" class="nav_mco_arrow"></a>';
    _buffer=_buffer + '                    <span id="current_page_'+tco_id+'">X</span> ' + TXT_XofY  + ' <span id="total_pages_'+tco_id+'">YY</span>';
    _buffer=_buffer + '                    <a href="#" id="mco-nav-next-content_'+tco_id+'"><img src="../../resources/' + ARROW_NEXT + '"  id="nav_container_next_button_'+tco_id+'" class="nav_mco_arrow"></a>';
    _buffer=_buffer + '                </b>&nbsp;';

    _buffer=_buffer + '                </nobr>';
    _buffer=_buffer + '            </td><td class="mco_bar" width="4"></td></tr>';
    _buffer=_buffer + '            </table>';

    if (area != 'IWIN'){
        _buffer = _buffer + '</td>\n';
    }
    return _buffer;
}


function buildTabNavigation(area){

    var tabAreaId  = (area == 'MCO')? 'tabsMain' : 'tabsQCO';
    var tco_navigation_prefix='<table border="0" width="100%" cellspacing="0" cellpadding="0" style="padding:0px; margin:0px" id="'+tabAreaId+'"><tr>\n';

    var tco_navigation_suffix='';

    tco_navigation_suffix=tco_navigation_suffix + '<td>&nbsp;&nbsp;';
    if(area == 'MCO'){ //XXX or QCO with more than one tab?!
        // texts (TTSCROLL...) are switched, aren't they ?!
        tco_navigation_suffix=tco_navigation_suffix + '<a href="javascript:tabsScrollLeft()" id="tabImgScrollLeft"  title="' + TTSCROLLRIGHT+ '"><img src="../../resources/' + ICON_TREE_DOWNSIZE+ '" border="0" height="11" width="7"></a> &nbsp;';
        tco_navigation_suffix=tco_navigation_suffix + '<a href="javascript:tabsScrollRight()" id="tabImgScrollRight"title="' + TTSCROLLLEFT + '"><img src="../../resources/' + ICON_TREE_UPSIZE + '" border="0" height="11" width="7"></a>';
    }
    tco_navigation_suffix=tco_navigation_suffix + '</td></tr>';

    //tco_navigation_suffix=tco_navigation_suffix + '<tr><td class="mco_bar" align="right" valign="top" height="' + mcoBarHeight.toString()+ 'px">';
    tco_navigation_suffix=tco_navigation_suffix + '<tr><td class="mco_bar" align="right" valign="top" height="18px">';

    tco_navigation_suffix=tco_navigation_suffix + '    <span style="display: block;">';
    tco_navigation_suffix=tco_navigation_suffix + '        <i style="overflow: hidden; display: block; height: 1px; background-color:white; width:4px;"></i>';
    tco_navigation_suffix=tco_navigation_suffix + '        <i style="overflow: hidden; display: block; height: 1px; background-color:white; width:2px;"></i>';
    tco_navigation_suffix=tco_navigation_suffix + '        <i style="overflow: hidden; display: block; height: 1px; background-color:white; width:1px;"></i>';
    tco_navigation_suffix=tco_navigation_suffix + '    </span>\n';

    tco_navigation_suffix=tco_navigation_suffix + '							<a id="' + area.toLowerCase() + '_up" href="javascript:sizetoggle(\''+ area.toLowerCase() +'\', \'full\')" title="' + eval('TTMAX' + area) +'" style="float:right; margin-right:5px; margin-top:3px;"><img src="../../resources/' + eval('ICON_' + area + '_UPSIZE') + '" border="0" height="7" width="11"></a>'
    tco_navigation_suffix=tco_navigation_suffix + '							<a id="' + area.toLowerCase() + '_down" href="javascript:sizetoggle(\''+ area.toLowerCase() +'\', \'semi\')" title="' + eval('TTMIN' + area) + '" style="float:right; margin-right:5px; margin-top:3px;"><img src="../../resources/' + eval('ICON_' + area + '_DOWNSIZE')  +'" border="0" height="7" width="11"></a>'

    tco_navigation_suffix=tco_navigation_suffix + '</td></tr></table>';

    return new Array(tco_navigation_prefix,  tco_navigation_suffix)

}




    function mkCertCenterURL(){
        var params=dxGetCookie(user.username,0) ;
        __url = CERTCENTER_LOCATION + '?id=' + CERTCENTER_COURSEIDENT + '-' + mkCertificateKey() + '&' + params;
        return encodeURI(__url);
    }


function mkCertificateKey(){
    var certFields = CERTCENTER_USEFIELDSFORKEY.split('##');
    var keyBase='';
    for (var i=0; i < certFields.length; i++){
        keyBase = keyBase + user[certFields[i]] + ' ';
    }
    keyBase=trim(keyBase) + CERTCENTER_COURSEIDENT;
    _key =  hex_md5(keyBase);
    //now rotate ascii by 13

   var src=new String(_key) ;
   var dst=new String('') ;
   var len=src.length ;
   var b ;
   var t=new String('') ;
    if(len > 0){
        for(var ctr=0; ctr<len ; ctr++)
        {
         b=src.charCodeAt(ctr)
         if( ( (b>64) && (b<78) ) || ( (b>96) && (b<110) ) )
         { b=b+13 }
         else
         { if( ( (b>77) && (b<91) ) || ( (b>109) && (b<123) ) )
          { b=b-13 }
         }
         t=String.fromCharCode(b) ;
         dst=dst.concat(t) ;
        }
   }

    //and crop to 12 digits
    _key=dst.substr(0,12);
    return _key
}



//---------------------------------------------------

function checkOpener(){
    try{
       window.opener.location.reload();
       //! GAD-Header ?!
    }
    catch(err){
        //pass
       // alert(err)
    }
}


