//
//  Licensed Materials - Property of IBM
//  5724I83
//  (C) Copyright IBM Corp. 1995, 2006 All Rights Reserved.
//
/*
■ イベントで呼び出す関数

HpbELTInit()	- BODY の onload で呼び出す
HpbELTExit()	- BODY の onunload で呼び出す
HpbELTStart()	- テスト開始ボタンで呼び出す（必ず ELTInit の後で)
HpbELTCheck()	- 採点ボタンで呼び出す
HpbELTSendResult()	- 送信ボタンで呼び出す

■ JavaScript の拡張なしの場合使用する HTML 部品の ID

HPB_ELT_Start		- 開始ボタン
HPB_ELT_Check		- 採点ボタン
HPB_ELT_NotQuestion	- テスト時に隠すオブジェクト
HPB_ELT_Question	- テスト時のみに表示するオブジェクト
HPB_ELT_RestTime	- 残り時間を表示するエリア

■ JavaScript で拡張可能な関数

ELT_SetEnabled		指定されたオブジェクトのアクティブ状態を切り替える
ELT_SetVisible		指定されたオブジェクトを表示・非表示にする
ELT_GetResultColor	正解・不正解 を表示するための色を返す
ELT_ShowResult		テストの採点結果を表示する
ELT_ShowResultEach	それぞれの問題の結果を表示する
ELT_GetQ		id で指定されるオブジェクトを返す

*/

var _debug = false;

//
// EXPORT FUNCTIONS
//
function HpbELTInit()
{
	if(navigator.appName == "Netscape"){
		alert("Netscape ブラウザでテストを行うことはできません。");
		return;
	}
	if(typeof HpbELTData == "object"){
		HpbELTObj = new ELTState(HpbELTData);
		HpbELTObj.doInit();
	} else {
		alert("テスト用のデータが定義されていません。\nテストを実行できません。");
	}
}

function HpbELTStart()
{
	if(HpbELTObj != null)
		HpbELTObj.doStart();
}

function HpbELTCheck()
{
	if(HpbELTObj != null){
		HpbELTObj.doCheck();
		HpbELTObj.showResult();
	}
}

function HpbELTSendResult()
{
	HpbELTObj.sendResult();
}

function HpbELTExit()
{
	if(HpbELTObj != null)
		HpbELTObj.doExit();
	if(HpbELTCommentWindow != null)
		HpbELTCommentWindow.close();
}

function HpbELTCorrectAnswer()
{
	var q = HpbELTObj.data.questions;
	for(var i=0; i<q.length; i++) {
		var objQ = q[i];
		if (objQ.type == "Description") {
			for(var j=0; j<objQ.answer.length; j++) {
				objQ.answer[j] = unescape(objQ.answer[j]);
			}
		}
	}
}

//
// instance of this test
//
var HpbELTObj = null;
var HpbELTCommentWindow = null;

//====---- STATE
function ELTState(data)
{
	// Attributes
	this.eltState = "";
	this.data = data;
	this.doc  = new ELTDoc();
	this.sco  = (typeof HPB_USING_SCORM_MODE != "undefined") ? new ELTSco() : new ELTwoSco();
	this.test = new ELTest(data, this.sco, this.doc);
	
	//-----------------------------------------
	// Events for State Transition
	//-----------------------------------------
	this.doInit = function()
	{
		this.doc.setVisible("question", false);	// hide questions
		this.doc.setVisible("resultmsg", false);
		
		var v = "";
		if(!decodeBase64AnswerData(HpbELTData)) v = "テスト用のデータが壊れています。";
		if( v == "" ) v = this.test.validate();
		
		if( v != "" ){
			alert("問題が壊れています！テストを中止します。\n\n" + v);
			this.doc.setEnabled("start", false);
			this.doc.setEnabled("check", false);
			this.doc.setEnabled("submit", false);
			HpbELTObj = null;
			return;
		}
		
		this.setState("loading");
		this.doc.setString("resttime", this.test.getRestTimeInString());
		
		if(this.data.waitforLoad != true){
			this.doReady();
			return;
		}
		this.startTimer();
	}
	this.doReady = function()
	{
		this.setState("waiting");
		this.stopTimer();
		this.test.clearAnswer();
	}
	this.doStart = function()
	{
		this.setState("testing");
		this.doc.setVisible("question", true);
		this.test.startTimer();
		this.startTimer();
	}
	this.doCheck = function()
	{
		this.stopTimer();
		this.test.stopTimer();
		this.test.check();
		this.setState("checked");
		this.doc.setEnabled("submit", true);
	}
	this.doExit = function()
	{
		if(this.getState() == "testing"){
			if( this.data.forceChecking != false ){
				// check before finishing test
				this.test.check();
				this.setState("checked");
			}
		}
		
		if(_debug && this.getState() != "checked")
			alert("Exit test without checking.");
	}
	this.showResult = function()
	{
		this.doc.showResult(this.data.score, this.data.mastery_score);
	}
	this.sendResult = function()
	{
		//結果をメールで送信
		var resultform = this.doc.getQ("HPB_ELT_RESULT");
		if (resultform != null
		 && resultform.disabled == false) {				//未送信か
			if (typeof resultform.action != "undefined"	//送信方法
			 && resultform.action.length > 0) {
				resultform.Score.value = this.data.score;
				resultform.Result.value = this.data.mastery_score > 0 ? (this.data.score >= this.data.mastery_score ? "合格" : "不合格") : "";
				resultform.submit();						//送信実行
			} else {
				alert("送信方法が定義されていません。");
			}
		}
		this.doc.setEnabled("submit", false);
	}

	//-----------------------------------------
	// Timer Events
	//-----------------------------------------
	this.onTimer = function()
	{
		switch(this.getState()){
		case "loading":
			if(!this.doc.isLoading())
				this.doReady();
			break;
		case "testing":
			if( this.test.isTimeExpired() ){
				alert("制限時間がきたので採点します。");
				this.doCheck();
				this.showResult();
			}
			this.doc.setString("resttime", this.test.getRestTimeInString());
		}
		if(this.timerId > 0)
			this.startTimer();
	}
	
	//-----------------------------------------
	// protected
	//-----------------------------------------
	
	//---------------------------------- state
	this.setState = function(mode)
	{
		var restr = {
			none	: "loading",
			loading	: "waiting",
			waiting	: "testing",
			testing	: "checked",
			checked	: ""
		};
		var mode2sco = {
			loading : { sco : "browsed",	btnStart : false, btnCheck : false, btnSubmit : false },
			waiting : { sco : "browsed",	btnStart : true,  btnCheck : false, btnSubmit : false },
			testing : { sco : "incomplete",	btnStart : false, btnCheck : true,  btnSubmit : false  },
			checked : { sco : "",		btnStart : false, btnCheck : false, btnSubmit : true }
		};
		
		var old_state = this.getState();
		if( old_state == "" ) old_state = "none";
		if( restr[old_state].indexOf(mode) == -1 ){
			if(_debug) alter("Illegal state change: " + old_state + " to " + mode);
			return;
		}
		
		var n = mode2sco[mode];
		
		this.eltState = mode;
		this.sco.updateLessonStatus(n.sco);
		this.doc.setEnabled("start", n.btnStart);
		this.doc.setEnabled("check", n.btnCheck);
		this.doc.setEnabled("submit",n.btnSubmit);
	}
	this.getState = function()
	{
		return this.eltState; 
	}
	
	//------------------------------- timer
	this.startTimer = function()
	{
		this.timerId = setTimeout("HpbELTOnTimer();", 1000);
	}
	this.stopTimer = function()
	{
		if(this.timerId > 0){
			clearTimeout(this.timerId);
		}
		this.timerId = 0;
	}
}

function HpbELTOnTimer()
{
	HpbELTObj.onTimer();
}
//====---- STATE

//====---- TEST
function ELTest(data, sco, doc)
{
	this.data = data;
	this.sco = sco;
	this.doc = doc;
	
	//-----------------------------------------------------------
	// for Checking Answers
	//-----------------------------------------------------------
	this.check = function()
	{
		var score = 0;
		var nQ = this.data.questions.length;
		for(var i=0; i<nQ; i++){
			var objQ = this.data.questions[i];
			var func = eval("this.checkEach" + objQ.type);
			if(typeof func == "function"){
				var id = this.data.idPrefix + (i+1).toString();
				var sc = func(this.doc, objQ, id);
				score += sc;
				// show result
				this.doc.fShowAns = this.data.showAnsEach;
				this.doc.bShowAns = this.data.showAnsEach;
				
				this.doc.showResultEach(objQ, id, sc>0 ? true : false);
			} else {
				if(_debug) alert("テストの採点をする関数がありません:  "+objQ.type);
			}
		}
		this.data.result = this.sco.judgeScore(score, this.data.max_score, this.data.mastery_score);
		this.data.score = score;
	}
	this.checkEachSelection = function(doc, obj, id)
	{
		obj.score = 0;
		if(obj.single){
			// Single Selection
			obj.result = false;
			var ansObj = doc.getQ(id);
			var ans;
			for(var i=0; i<ansObj.length; i++){
				if(ansObj[i].checked)
					ans = ansObj[i].value;
				ansObj[i].disabled = true;
			}
			if( ans == obj.answer ){		// judge
				obj.score = obj.gain;
				obj.result = true;
			}
		} else {
			// Multiple Selection
			obj.result = new Array();
			var nChecked = 0;
			var nMatched = 0;
			for(var i=1; i<=obj.n_selection; i++){
				var iid = id + "_" + i;
				var checked = doc.getQ(iid).checked;
				doc.getQ(iid).disabled = true;
				if(checked){
					nChecked ++;
					for(var j=0; j<obj.answer.length; j++){
						if( i == obj.answer[j] ){
							obj.result[i] = true;
							nMatched ++;
							break;
						}
					}
				}
				if(obj.result[i] != true) obj.result[i] = false;
			}
			if(nChecked == obj.answer.length && nMatched == obj.answer.length)
				obj.score = obj.gain;
		}
		
		return obj.score;
	}
	this.checkEachDescription = function(doc, obj, id)
	{
		obj.score = 0;
		
		var ans = doc.getQ(id).value;
		doc.getQ(id).disabled = true;
		
		for(var i=0; i<obj.answer.length; i++){
			if(ans == obj.answer[i]){
				obj.score = obj.gain;
				obj.result = true;
				break;
			}
		}
		return obj.score;
	}
	this.checkEachCloze = function(doc, obj, id)
	{
		obj.score = 0;
		obj.result = new Array();
		
		var nMatch = 0;
		var nQ = obj.answer.length;
		for(var i=0; i<nQ; i++){
			var o = doc.getQ(id+"_"+(i+1));
			
			if(o.selectedIndex == obj.answer[i]){
				nMatch ++;
				obj.result[i] = true;
			}
			o.disabled = true;
		}
		
		obj.score = Math.floor((nMatch*obj.gain)/obj.answer.length);
		return obj.score;
	}
	
	//-----------------------------------------------------------
	// for Cleaing the paper
	//-----------------------------------------------------------
	this.clearAnswer = function()
	{
		var nQ = this.data.questions.length;
		for(var i=0; i<nQ; i++){
			var objQ = this.data.questions[i];
			var func = eval("this.clearEach" + objQ.type);
			if(typeof func == "function"){
				var id = this.data.idPrefix + (i+1).toString();
				func(this.doc, objQ, id);
			} else {
				if(_debug) alert("テストの回答をクリアする関数がありません:  "+objQ.type);
			}
		}
	}
	this.clearEachSelection = function(doc, obj, id)
	{
		if(obj.single){
			var ansObj = doc.getQ(id);
			for(var i=0; i<ansObj.length; i++)
				ansObj[i].checked = false;
		} else {
			for(var i=1; i<=obj.n_selection; i++){
				var iid = id + "_" + i;
				doc.getQ(iid).checked = false;
			}
		}
	}
	this.clearEachDescription = function(doc, obj, id)
	{
		doc.getQ(id).value = "";
	}
	this.clearEachCloze = function(doc, obj, id)
	{
		var nQ = obj.answer.length;
		for(var i=1; i<=nQ; i++){
			var iid = id + "_" + i;
			doc.getQ(iid).selectedIndex = 0;
		}
	}
	//-----------------------------------------------------------
	// for Validation
	//-----------------------------------------------------------
	this.validate = function()
	{
		var r = "";
		var nQ = this.data.questions.length;
		for(var i=0; i<nQ; i++){
			var objQ = this.data.questions[i];
			var func = eval("this.validateEach" + objQ.type);
			if(typeof func == "function"){
				var id = this.data.idPrefix + (i+1).toString();
				r += func(this.doc, objQ, id);
			} else {
				if(_debug) alert("テストをvalidateする関数がありません: "+objQ.type);
			}
		}
		return r;
	}
	
	this.validateEachSelection = function(doc, q, id)
	{
		var r = "";
		if(q.single == true){
			var o = doc.getQ(id);
			if(o == null){
				r += "選択問題(単一)の "+id+" ラジオボタンが見つかりません\n";
			} else if(o.length != q.n_selection){
				r += "選択問題(単一)の "+id+" ラジオボタンの個数が違います。本来の個数: " + q.n_selection + "\n";
			}
		} else {
			for(var i=0; i<q.n_selection; i++){
				var iid = id + "_" + (i+1);
				if(doc.getQ(iid) == null || typeof doc.getQ(iid).checked == "undefined" )
					r += "選択問題(複数)の "+iid+" チェックボックスがないか、複製されています。\n";
			}
		}
		return r;
	}
	this.validateEachDescription = function(doc, q, id)
	{
		var r = "";
		if(doc.getQ(id) == null || typeof doc.getQ(id).value == "undefined"){
			r = "記述問題の "+id+" に対応する回答入力エリアがないか、複製されています。\n";
		}
		return r;
	}
	this.validateEachCloze = function(doc, q, id)
	{
		var r = "";
		for(var i=0; i<q.answer.length; i++){
			var iid = id + "_" + (i+1);
			var obj = doc.getQ(iid);
			if(obj == null || typeof obj.value == "undefined" ){
				r += "穴埋め問題の "+iid+" に対応する入力エリアないか、複製されています。\n";
			}
		}
		return r;
	}
	//-----------------------------------------------------------
	// for Timer
	//-----------------------------------------------------------
	this.startTimer = function(){
		this.rtTimeStarted = (new Date()).getTime();
	}
	this.stopTimer = function(){ 
		this.rtTimeFinished = (new Date()).getTime();
	}
	this.isTimeExpired = function()
	{
		if( this.getLimitTime() <= 0)
			return false;
		
		this.rtTimeFinished = (new Date()).getTime();
		if( this.rtTimeFinished - this.rtTimeStarted > this.getLimitTime()*60*1000 )
			return true;
		return false;
	}
	this.getLimitTime = function()
	{
		if(typeof this.data.limit_time != "undefined")
			return this.data.limit_time;
		return 0;
	}
	this.getRestTimeInString = function()
	{
		if(this.getLimitTime() <= 0)
				return "(時間制限なし)";
		
		var r = 0;
		if(typeof this.rtTimeStarted == "undefined"){
				r = this.getLimitTime()*60*1000;
		} else {
			r = this.getLimitTime()*60*1000
			 - ( (new Date()).getTime() - this.rtTimeStarted );
		}
		
		if( r <= 0) return "0:00";
		
		var rm = Math.floor(r/60000);
		var rs = Math.floor((r%60000)/1000);
		
		return rm.toString() + ":" + (rs<10 ? "0":"") + rs.toString();
	}
}
//====---- TEST

//====---- SCORM

//---------------
// for NOT SCROM mode
function ELTwoSco()
{
	this.updateLessonStatus = function(){};
	this.judgeScore = woscoJudgeScore;
}
function woscoJudgeScore(score, max_score, mastery_score)
{
	return (score < mastery_score) ? "failed" : "passed";
}

//---------------
// for SCROM mode
function ELTSco()
{
	this.updateLessonStatus = scoUpdateLessonStatus;
	this.judgeScore = scoJudgeScore;
}
var SCO_LESSON_STATUS_ORDER = [
	"",
	"not attempted",
	"browsed",
	"incomplete",
	"completed",
	"failed",
	"passed"
];
var scoLessonStatus = -1;
function scoUpdateLessonStatus(newStatus)
{
	if(scoLessonStatus == -1){
		var v = doLMSGetValue("cmi.core.lesson_status");
		scoLessonStatus = scoFindLessonStatusId(v);
	}

	var newId = newStatus;
	
	if(typeof newId == "string")
		newId = scoFindLessonStatusId(newId);
	
	if(_debug) alert("scoUpdateId: "+scoGetLessonStatusId()+" -> "+newId);
	
	if( newId <= scoGetLessonStatusId() )
		return false; // no need to update
	
	scoLessonStatus = newId; //scoUpdateLessonStatus(newId);
	var s = scoFindLessonStatusString(scoLessonStatus);
	doLMSSetValue("cmi.core.lesson_status", s);
	doLMSCommit();
	
	return true;
}
function scoGetLessonStatusId()
{
	if(typeof scoLessonStatus != "number"){
		var s = doLMSGetValue("cmi.core.lesson_status");
		scoLessonStatus = scoFindLessonStatusId(s);
	}
	
	return scoLessonStatus;
}
function scoGetLessonStatusString()
{
	return scoFindLessonStatusString(scoGetLessonStatusId());
}
function scoFindLessonStatusId(status)
{
	for(var i=0; i<SCO_LESSON_STATUS_ORDER.length; i++){
		if( status == SCO_LESSON_STATUS_ORDER[i])
			return i;
	}
	return 0;
}
function scoFindLessonStatusString(id)
{
	return SCO_LESSON_STATUS_ORDER[id];
}
function scoJudgeScore(score, max_score, mastery_score)
{
	if(_debug) alert("scoJudgeScore：" + score + " " + max_score + " " + mastery_score);
	if(isNaN(max_score) || max_score <= 0) max_score = 100;
	
	// get server score...
	var server_max_score = parseInt(doLMSGetValue("cmi.core.score.max"));
	var server_mas_score = parseInt(doLMSGetValue("cmi.student_data.mastery_score"));
	var server_raw_score;
	if( !isNaN(server_max_score) && server_max_score > 0){
		if( max_score <= 0 ) max_score = 100;
		server_raw_score = Math.round(score * max_score / server_max_score);
		if(server_raw_score < 0)		server_raw_score = 0;
		if(server_raw_score > server_max_score)	server_raw_score = server_max_score;
		
		if( isNaN(server_mas_score) )
			server_mas_score = Math.round(mastery_score * max_score / server_max_score);
	} else
	if( !isNaN(server_mas_score) ){
		server_max_score = max_score;
		server_raw_score = score;
	} else {
		server_raw_score = score;
		server_max_score = max_score;
		server_mas_score = mastery_score;
	}
	
	// judgement...
	var result;
	if(server_mas_score <= server_raw_score)	result = "passed";
	else						result = "failed";
	
	var old_score = parseInt(doLMSGetValue("cmi.core.score.raw"));

	if(_debug)
		alert(" server_max_score:" + server_max_score +
			" server_mas_score:" + server_mas_score +
			" server_raw_score:" + server_raw_score +
			" old_score: " + old_score);

	if( isNaN(old_score) || score > old_score ){
		// send the raw score
		doLMSSetValue("cmi.core.score.raw", server_raw_score);
		// update status (and commit)
		scoUpdateLessonStatus(result);
	} else if( score != old_score ){
		alert("残念ながら前回の得点を下回ってしまいました。\n今回の得点は記録されません。");
	}
	
	return result;
}
//====---- SCORM

//====---- DOCUMENT
function ELTDoc()
{
	/////////////////////////////////////////////////////////
	// EXTENTION POINT
	this.setExtention = function()
	{
		if(typeof ELT_SetEnabled == "function")
			this.setEnabled = ELT_SetEnabled;
			// 
			// ■ void ELT_SetEnabled(string name, bool bEnabled)
			// name: 
			//	"start"  - 開始ボタン 
			//	"check"  - 採点ボタン 
			//	"submit" - 送信ボタン
		
		if(typeof ELT_SetVisible == "function")
			this.setVisible = ELT_SetVisible;
			//
			// ■ void ELT_SetVisible(string name, bool bEnabled)
			// name:
			//	"question" - 問題 
		
		if(typeof ELT_GetResultColor == "function")
			this.getResultColor = ELT_GetResultColor;
			//
			// ■ string ELT_GetResultColor(bool bSuccess)
			// bSuccess:
			//	true - 問題に正解した 
		
		if(typeof ELT_ShowResult == "function")
			this.showResult = ELT_ShowResult;
			//
			// ■ void ELT_ShowResult(string result, int score)
			// result:
			//	"passed" - 合格
			//	"failed" - 不合格
			// score:
			//	得点
		
		if(typeof ELT_ShowResultEach == "function")
			this.showResultEach = ELT_ShowResult;
			//
			// ■ void ELT_ShowResultEach(Question q, string id, bool bSuccess)
			// q:
			//	Question オブジェクト 
			// id: 
			//	問題の id 
			// bSuccess: 
			//	true - 問題に正解した 
		
		if(typeof ELT_GetQ == "function")
			this.getQ = ELT_GetQ;
			//
			// ■ Object ELT_GetQ(string id) 
			// id: 
			//	Get するオブジェクトの id 
	}
	
	//-----------------------------------------------------------
	// for Object
	//-----------------------------------------------------------
	this.getQ = function(id)
	{
		if( eval("typeof "+id) == "undefined" )
			return null;
		return eval(id);
	}
	this.setEnabled = function(name, bEnabled)
	{
		var obj = null;
		switch(name){
		case "start":	obj = this.getQ("HPB_ELT_START"); break;
		case "check":	obj = this.getQ("HPB_ELT_CHECK"); break;
		case "submit":	obj = this.getQ("HPB_ELT_SEND");  break;
		default:
			if(_debug) alter("setEnabled: Unknown name: "+name);
			break;
		}
		
		if(obj != null) obj.disabled = !bEnabled;
	}
	this.setVisible = function(name, bVisible)
	{
		switch(name){
		case "question":
			var N = this.getQ("HPB_ELT_NOTQUESTION");
			var Q = this.getQ("HPB_ELT_QUESTION");
			if(N != null) N.style.display = bVisible ? "none" : "";
			if(Q != null) Q.style.display = bVisible ? "" : "none";
			break;
		case "resultmsg":
			var R = this.getQ("HPB_ELT_RESULTMSG");
			if (R != null) R.style.display = bVisible ? "" : "none";
			break;
		default:
			if(_debug) alert("setVisible: Unknown name: "+name);
		}
	}
	this.setString = function(name, str)
	{
		switch(name){
		case "resttime":
			var T = this.getQ("HPB_ELT_RESTTIME");
			if(T != null) T.value = str;
			break;
		default:
			if(_debug) alert("setString: unknown name: "+name);
		}
	}
	
	//-----------------------------------------------------------
	// for Showing result
	//-----------------------------------------------------------
	this.showResult = function(score, mastery_score)
	{
		var rp = "";	// popup message
		var rd = "";	// document
		var bPassed = true;	// Pass or fail
		if (mastery_score > 0) {
			if(score >= mastery_score) {
				rp = "\n結果: 合格";
				rd = " (合格) "
			} else {
				rp = "\n結果: 不合格";
				rd = " (不合格) "
				bPassed = false;
			}
		}

		this.setVisible("resultmsg", true);
		var T = this.getQ("HPB_ELT_RESULTMSG");
		T.innerHTML = T.innerHTML + "<b><font color=\"" + this.getResultColor(bPassed) + "\">" + score + " 点" + rd + "</font></b>";

		alert("得点: " + score + " 点です" + rp);
	}
	this.getResultColor = function(bOK)
	{
		if(bOK){
			if(typeof HpbELTData.colorCorrectAns != "undefined")
				return HpbELTData.colorCorrectAns;
			return "#8080ff";
		} else {
			if(typeof HpbELTData.colorIncorrectAns != "undefined")
				return HpbELTData.colorIncorrectAns;
			return "#ff8080";
		}
	}
	this.showResultEach = function(q, id, bOK)
	{
		eval("this.showResult" + q.type + "(q, id, bOK)");
	}
	this.showResultSelection = function(q, id, bOk)
	{
		var color = this.getResultColor(bOk);
		
		var title = this.getQ(id + "_head");
		if(title != null && typeof title.innerHTML != "undefined"){
			var html;
			if(bOk)	html = "<font color=\"" + color + "\">○</font> ";
			else	html = "<font color=\"" + color + "\">×</font> ";
			title.innerHTML = html + title.innerHTML;
		}
		
		// show answer with color...
		if(this.bShowAns == false){
			if(q.single == true){
				var objs = this.getQ(id);
				for(var i=0; i<objs.length; i++){
					if(objs[i].checked)
						objs[i].style.background = this.getResultColor(q.result);
				}
			} else {
				for(var i=0; i<q.n_selection; i++){
					var obj = this.getQ(id + "_" + (i+1));
					if(obj.checked){
						obj.style.background = this.getResultColor(q.result[i+1]);
					}
				}
			}
			return;
		}
		
		if(q.single == true ){
			var objs = this.getQ(id);
			for(var i=0; i<objs.length; i++){
				if(objs[i].value == q.answer){
					objs[i].style.background = color;
					var ca = this.getQ(id+"_"+(i+1)+"_ca");
					if(ca != null)
						ca.innerHTML = "(正解) "+ ca.innerHTML;
				}
			}
		} else {
			for(var i=0; i<q.answer.length; i++){
				this.getQ(id+"_"+q.answer[i]).style.background = 
					this.getResultColor(q.result[q.answer[i]]);
				var ca = this.getQ(id+"_"+q.answer[i]+"_ca");
				if(ca != null)
					ca.innerHTML = "(正解) " + ca.innerHTML;
			}
		}

		this.showComment(q, id);
	}
	this.showResultDescription = function(q, id, bOK)
	{
		var obj = this.getQ(id);
		var color = this.getResultColor(bOK);
		var bResult = false;
		
		var title = this.getQ(id + "_head");
		if(title != null){
			var html;
			if(bOK)	html = "<font color=\"" + color + "\">○</font> ";
			else	html = "<font color=\"" + color + "\">×</font> ";
			title.innerHTML = html + title.innerHTML;
			bResult = true;
		}
		
		obj.style.background = color;
		
		var text = obj.value;
		if(!bResult) text = (q.result ? "○ " : "× ") + text;
		if(this.bShowAns && !q.result)
			text += " (答え " + q.answer.join(", ") + ")";
		
		obj.value = text;

		this.showComment(q, id);
	}
	this.showResultCloze = function(q, id, bOK)
	{
		var color = this.getResultColor(bOK);
		var bResult = false;
		
		var title = this.getQ(id + "_head");
		if(title != null){
			var corrects = 0;
			for(var i=0; i<q.answer.length; i++) {
				if (q.result[i]) corrects++;
			}
			var html;
			var mark;
			if(corrects == q.answer.length)	mark = "○";
			else if (corrects > 0)	mark = "△";
			else	mark = "×";
			html = "<font color=\"" + color + "\">" + mark + "</font> ";
			title.innerHTML = html + title.innerHTML;
			bResult = true;
		}
		
		for(var i=0; i<q.answer.length; i++){
			var obj = this.getQ(id+"_"+(i+1));
			obj.style.background = this.getResultColor(q.result[i]);
			
			var text = obj.options[obj.selectedIndex].text;
			if (!bResult) {
				if (q.result[i]) {
					text = "○ " + text;
				} else {
					text = "× " + text;
				}
			}
			if(this.bShowAns && !q.result[i])
				text += " (答え " + obj.options[q.answer[i]].text + ")";
			
			obj.options[obj.selectedIndex].text = text;
		}

		this.showComment(q, id);
	}
	this.showComment = function(q, id)
	{
		if (typeof(q.comment) == "undefined")
			return;
		var comment;
		comment = this.getQ(id + "_answer");
		if (comment == null)
			return ;
		var strComment = "<A href=\"#\" onclick=\"HpbELTCommentWindow = window.open('" + q.comment + "','comment','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes, resizable=no');\">解説</A>";
		if (comment.tagName == "P")
		{
			comment.insertAdjacentHTML("AfterEnd", strComment);
		}
		else if (comment.tagName == "TABLE")
		{
			comment.insertAdjacentHTML("AfterEnd", strComment);
		}
		else if (comment.tagName == "TD")
		{
			var trParent = comment.parentElement;
			if (trParent != null)
			{
				var newTd = trParent.insertCell();
				if (newTd != null)
					newTd.innerHTML = strComment;
			}
		}
	}
	
	//--------------------------
	// Initialize
	//--------------------------
	this.setExtention();
}
//====---- DOCUMENT

function decodeBase64AnswerData(obj)
{
	var q = obj.questions;
	for(var i=0; i<q.length; i++){
		var e = q[i];
		if (typeof (e.comment) == "string")
		{
			e.comment = decEvalBase64(e.comment, 0);
		}
		if(typeof e.answer == "string"){
			e.answer = decEvalBase64(e.answer, 1);
			if(e.answer == null){
				return false;
			}
		} else {
			return false;
		}
	}
	return true;
}

function decEvalBase64(src, fEval)
{
	var obj = new Object();
	obj.src = src;
	if(src.length % 4 != 0) return null;
	
	obj.toBinArray = function()
	{
		this.iIndex = 0;
		this.oIndex = 0;
		this.dst = new Array();
		this.prev = 0;
		this.state = 0;
		
		while(this.enQue()){}
	}
	obj.enQue = function(special)
	{
		var ch = 0;
		if(!special){
			if(this.src.length <= this.iIndex) return false;
			ch = this.src.charAt(this.iIndex++);
			if(ch == '=') return false;
			ch = this.getValue(ch);
		} else {
		    ch = 0;
		}
		switch(this.state){
		case 0:
			this.prev = ch; this.state++;
			break;
		case 1:
			this.submit((this.prev<<2)|(ch>>4)); this.prev = ch; this.state++;
			break;
		case 2:
			this.submit((this.prev<<4)|(ch>>2)); this.prev = ch; this.state++;
			break;
		case 3:
			this.submit((this.prev<<6)|ch); this.state = 0;
			break;
		}
		return true;
	}
	obj.submit = function(val)
	{
		this.dst[this.oIndex++] = val & 0xff;
	}
	obj.getValue = function(ch)
	{
		var offset = 0;
		if('A'<=ch && ch<='Z' ){ return ch.charCodeAt(0)-'A'.charCodeAt(0)+offset; } offset += 26;
		if('a'<=ch && ch<='z' ){ return ch.charCodeAt(0)-'a'.charCodeAt(0)+offset; } offset += 26;
		if('0'<=ch && ch<='9' ){ return ch.charCodeAt(0)-'0'.charCodeAt(0)+offset; } offset += 10;
		if( ch == '+' ){ return offset; } offset += 1;
		if( ch == '/' ){ return offset; } offset += 1;
		this.fail = true;
		if(_debug) alert("Invalid char: "+ch);
	}
	obj.toStr = function()
	{
		if(this.dst.length%2 != 0) this.fail = true;
		
		var result = "";
		for(var i=0; i<this.dst.length/2; i++)
			result += String.fromCharCode(this.dst[2*i] | (this.dst[2*i+1]<<8) );
		this.result = result;
	}
	
	obj.toBinArray();
	obj.toStr();
	
	if(_debug) alert("Base64 Decoder:\nsrc: "+src+"\ndst: "+obj.result);
	
	if(obj.fail) return null;
	if (fEval == 0)
		return (obj.result);
	return eval(obj.result);
}

