<?xml version="1.0" encoding="UTF-8"?>
<rmml>
<!--
$RCSfile: rnmc_result_manager.xml,v $
$Revision: 845 $

last change: $Date: 2008-11-19 16:46:47 +0300 (Ср, 19 ноя 2008) $
             $Author: toha $

	Lacerta Project
	version 1.0.0.1
	Copyright (C) 2008 RNMC
-->

<composition name="rnmc_ResultManager">
<xml name="exportSettingsXML"/>
<script><![CDATA[
	//	настройки экспорта
	this.exportColumnName = true;
	this.exportColumnStartTime = true;
	this.exportColumnDuration = true;
	this.exportColumnErrors = true;
	this.exportColumnHelps = true;
	this.exportColumnResult = true;

	//	в лаюе ведётся подсчёт результатов
	this.labworkResultCount = false;
	
	// список названий шагов
	this.stepNames = null;
	// список посещений шагов
	this.stepVisited = null;
	// типы шаблонов
	this.stepTypes = null;
	// ведётся ли подчет результатов в шагах
	this.stepResultCount = null;
	// ведётся ли подчет результатов в шагах
	this.stepResultSelectRule = null;
	// количество попыток для каждого шага
	this.stepAttempts = null;
	// время начала работы в каждой попытке каждого шага
	this.stepAttemptsStart = null;
	// длительность работы в каждой попытке
	this.stepAttemptsDurations = null;
	//	количество ошибок в шаге (отдельно для каждой попытки)
	this.stepAttemptsErrors = null;
	//	результаты в процентах для каждой попытки
	this.stepAttemptsResult = null;
	//	количество подсказок в шаге (отдельно для каждой попытки)
	this.stepAttemptsHelps = null;

	// номер текущего шага и попытки
	this.currentStep = null;
	this.currentAttempt = null;	

//	константы выбора результатов для шага
//	SELECT_RESULT_LAST = 0;			-	последний
//	SELECT_RESULT_BEST = 1;			-	лучший
//	SELECT_RESULT_AVERAGE = 2;		-	средний
	this.defaultResultSelectRule = SELECT_RESULT_LAST;


	//	начальная инициализация
	function initResultManager(){
		//
		this.stepNames = new Array();
		this.stepTypes = new Array();
		this.stepResultCount = new Array();
		this.stepResultSelectRule = new Array();
		this.stepVisited = new Array();
		this.stepAttempts = new Array();
		this.stepAttemptsStart = new Array();
		this.stepAttemptsDurations = new Array();
		this.stepAttemptsResult = new Array();
		this.stepAttemptsErrors = new Array();
		this.stepAttemptsHelps = new Array();
	}

	//	добавление шага
	function addStep(stepName, stepType, stepResultCount, resultSelectRule){
//trace("ResultManager.addStep: " + stepName);
		this.stepNames.push(stepName);
		this.stepTypes.push(stepType);
		if(stepResultCount){
			this.labworkResultCount = true;
		}
		this.stepResultCount.push(stepResultCount);
		if(resultSelectRule != undefined && resultSelectRule != null){
			this.stepResultSelectRule.push(resultSelectRule);
		} else {
			this.stepResultSelectRule.push(this.defaultResultSelectRule);
		}
		this.stepVisited.push(false);
		this.stepAttempts.push(0);
		var newStepAttemptStart = new Array();
		this.stepAttemptsStart.push(newStepAttemptStart);
		var newStepAttemptDuration = new Array();
		this.stepAttemptsDurations.push(newStepAttemptDuration);
		var newStepAttemptResult = new Array();
		this.stepAttemptsResult.push(newStepAttemptResult);
		var newStepAttemptErrors = new Array();
		this.stepAttemptsErrors.push(newStepAttemptErrors);
		var newStepAttemptHelp = new Array();
		this.stepAttemptsHelps.push(newStepAttemptHelp);
	}

	// вызывается при начале работы в шаге с номером stepId
	function onStartStep(stepId){
		// запоминаем номер текущей попытки
		this.currentStep = stepId;
		this.stepVisited[this.currentStep] = true;
		// запоминаем номер текущей попытки
		this.currentAttempt = this.stepAttempts[stepId];
		var startDate = new Date();
		// сохраняем время старта текущей попытки
		this.stepAttemptsStart[this.currentStep].push(startDate.getHours()*3600 + startDate.getMinutes()*60 + startDate.getSeconds());
		//
		this.stepAttemptsErrors[this.currentStep][this.currentAttempt] = 0;
		this.stepAttemptsHelps[this.currentStep][this.currentAttempt] = 0;
	//	TRACE DEBUG INFO
	//	trace("ResultManager.onStartStep:  " + this.id + "========================================================");
	//	trace("Всего попыток: " + this.stepAttempts[this.currentStep]);
	//	trace("Ошибок: " + this.stepAttemptsErrors[this.currentStep]);
	}

	// вызывается при окончании работы в шаге
	function onFinishStep(curAttemptResult, curAttemptErrors, curAttemptHelps){
		// увеличиваем число попыток текущего шага
		var finishedAttempt = this.stepAttempts[this.currentStep];
		finishedAttempt++;
		this.stepAttempts[this.currentStep] = finishedAttempt;

		//	записываем число ошибок, подсказок и прочего
		if(curAttemptResult){
		//	вычисляем результат шага
			var newResult = 0;
			if(curAttemptResult.length > 0){
				var totalCoefficient = 0;
				var normalizedCoefficient = 0;
				for(var i = 0; i < curAttemptResult.length; i++){
					var objectStat = curAttemptResult[i].split(";");
					var objectResult = parseInt(objectStat[0]);
					var objectWeight = parseFloat(objectStat[1]);
					totalCoefficient += objectWeight;
				}
				normalizedCoefficient = 1/totalCoefficient;
				for(var i = 0; i < curAttemptResult.length; i++){
					var objectStat = curAttemptResult[i].split(";");
					var objectResult = parseInt(objectStat[0]);
					var objectWeight = parseFloat(objectStat[1]);
					newResult += objectWeight*objectResult*normalizedCoefficient;
          //trace("#FF0000objectWeight*objectResult*normalizedCoefficient = "+objectWeight+"*"+objectResult+"*"+normalizedCoefficient);
				}
			} else {
				newResult = 100;
			}
      
      newResult = Math.round(newResult);
			
trace("RESULT == " + newResult);			

			this.stepAttemptsResult[this.currentStep].push(parseInt(newResult));
		} else {
			this.stepAttemptsResult[this.currentStep].push(0);
		}
		if(curAttemptErrors){
			var currentErrors = this.stepAttemptsErrors[this.currentStep][this.currentAttempt];
			currentErrors += curAttemptErrors;
			this.stepAttemptsErrors[this.currentStep][this.currentAttempt] = currentErrors;
		}
		if(curAttemptHelps){
			var currentHelps = this.stepAttemptsHelps[this.currentStep][this.currentAttempt];
			currentHelps += curAttemptHelps;
			this.stepAttemptsHelps[this.currentStep][this.currentAttempt] = currentHelps;
		}
		// вычисляем и сохраняем длительность текущей попытки, если тип != summary
		if(this.stepTypes[this.currentStep] != "summary"){
			var finishDate = new Date();
			var attemptDuration = Math.round((finishDate.getHours()*3600 + finishDate.getMinutes()*60 + finishDate.getSeconds()) - this.stepAttemptsStart[this.currentStep][this.currentAttempt] + 0.5);
			this.stepAttemptsDurations[this.currentStep].push(attemptDuration);
		} else {
			this.stepAttemptsDurations[this.currentStep].push(0);
		}
	}

//	==================================================================================
//	функции запроса статистики отдельного шага
//	==================================================================================

	//	название шага
	function getStepName(stepId){
		return this.stepNames[stepId];
	}

	//	тип шага
	function getStepType(stepId){
		return this.stepTypes[stepId];
	}

	//	посещался ли данный шаг
	function getStepVisited(stepId){
		return this.stepVisited[stepId];
	}

	//	ведётся ли подсчёт результатов в данном шаге
	function getStepResultCount(stepId){
		return this.stepResultCount[stepId];
	}

	//	время начала работы в шаге
	function getStepStartTime(stepId){
		// в данной реализации временнем начала шага считается время первого входа в шаг
		if(this.stepAttemptsStart[stepId].length > 0){
			return this.stepAttemptsStart[stepId][0];
		} else {
			return -1;
		}
	}

	//	длительность работы в шаге
	function getStepDuration(stepId){
		var totalDuration = 0;
		for(var i = 0; i < this.stepAttemptsDurations[stepId].length; i++){
			totalDuration += this.stepAttemptsDurations[stepId][i];
		}
		return totalDuration;
	}

	//	количество ошибок в шаге
	function getStepErrors(stepId){
		var totalErrors = 0;
		for(var i = 0; i < this.stepAttemptsErrors[stepId].length; i++){
			totalErrors += this.stepAttemptsErrors[stepId][i];
		}
		return totalErrors;
	}

	//	количество подсказок в шаге
	function getStepHelps(stepId){
		var totalHelps = 0;
		for(var i = 0; i < this.stepAttemptsHelps[stepId].length; i++){
			totalHelps += this.stepAttemptsHelps[stepId][i];
		}
		//trace("totalHelps == " +totalHelps);
		return totalHelps;
	}

	//	результат выполнения шага
	function getStepResult(stepId){
		var newStepResult = 0;
		
		if(this.stepTypes[i] == "summary"){
			return 0;
		}

		if(this.stepResultCount[stepId]){
			switch(this.stepResultSelectRule[stepId]){
			case SELECT_RESULT_LAST:
				if(this.stepAttemptsResult[stepId] && this.stepAttemptsResult[stepId].length > 0){
					var attemptIndex = this.stepAttemptsResult[stepId].length;
					newStepResult = this.stepAttemptsResult[stepId][attemptIndex - 1];
				} else {
					newStepResult = 0;
				}
				break;
			case SELECT_RESULT_BEST:
				if(this.stepAttemptsResult[stepId] && this.stepAttemptsResult[stepId].length > 0){
					var bestResult = 0;
					for(var i = 0; i < this.stepAttemptsResult[stepId].length; i++){
						if(this.stepAttemptsResult[stepId][i] > bestResult)
							bestResult = this.stepAttemptsResult[stepId][i];
					}
					newStepResult = bestResult;
				} else {
					newStepResult = 0;
				}

				break;
			case SELECT_RESULT_AVERAGE:
				if(this.stepAttemptsResult[stepId] && this.stepAttemptsResult[stepId].length > 0){
					var currentResult = 0;
					var attemptsCount = 0;
					for(var i = 0; i < this.stepAttemptsResult[stepId].length; i++){
						currentResult += this.stepAttemptsResult[stepId][i];
						attemptsCount++;
					}
					newStepResult = parseInt(currentResult/attemptsCount);
				} else {
					newStepResult = 0;
				}
				break;
			}
		} else {
			newStepResult = -1;
		}
		return newStepResult;
	}

//	===============================================================================
//	суммарные параметры для всей лабораторной работы
//	===============================================================================

	//	общее количество шагов
	function getStepsTotal(){
		return this.stepNames.length;
	}

	//	суммарное время выполнения работы
	function getTotalDuration(){
		var totalDuration = 0;
		for(var i = 0; i < this.stepAttemptsDurations.length; i++){
			for(var j = 0; j < this.stepAttemptsDurations[i].length; j++){
				totalDuration += this.stepAttemptsDurations[i][j];
			}
		}
		return totalDuration;
	}

	//	суммарное количество ошибок в работе
	function getTotalErrors(){
		var totalErrors = 0;
		for(var i = 0; i < this.stepAttemptsErrors.length; i++){
			for(var j = 0; j < this.stepAttemptsErrors[i].length; j++){
				totalErrors += this.stepAttemptsErrors[i][j];
			}
		}
		return totalErrors;
	}

	//	суммарное количество подсказок в работе
	function getTotalHelps(){
		var totalHelps = 0;
		for(var i = 0; i < this.stepAttemptsHelps.length; i++){
			for(var j = 0; j < this.stepAttemptsHelps[i].length; j++){
				totalHelps += this.stepAttemptsHelps[i][j];
			}
		}
		return totalHelps;
	}

	//	суммарный процент выполнения за лабораторную работу (считается среднее арифметическое)
	function getTotalResult(){
		var stepsTotal = this.getStepsTotal();
		var stepsCount = 0;
		var percent =  0;

		for(var i = 0; i < stepsTotal; i++){
			if(this.stepTypes[i] == "summary"){
				continue;
			}
			//	если в каом то шаге не считается результат (resultCount==false)
			if(this.stepResultCount[i]){
				stepsCount++;
				var newStepRes = this.getStepResult(i);
				percent += newStepRes;
			}
		}
		return Math.round(percent/stepsCount);
	}

	//	функция сохранения результатов во внешний файл
	function saveResultsToFile(targetFile){
	//trace("#FF0000ResultManager.saveResultsToFile()");
		var headerString  = "";
		var footerString  = "";
		var oddItemString  = "";
		var evenItemString  = "";
		var summaryItemString  = "";
		var defaultItemString = "";

		var textResult = new Text();
		textResult.visible = false;
		textResult.parent = this;

		var settingsSrc = scene.result_export_xml;

		if(!resourceExists(settingsSrc)){
			//	FOR COMPATIBILITY
			//	случай, когда настройки экспорта отсутствуют (выводится простая HTML таблица без оформления)
			textResult.value = "<html><body><center><table border=\"1\"><tr><td align=\"center\">Название шага</td><td align=\"center\">Время начала выполнения</td><td align=\"center\">Время выполнения</td><td align=\"center\">Ошибок/Подсказок</td><td align=\"center\">Результат выполнения</td></tr>"
			var totalSteps = this.getStepsTotal();
			for(var i = 0; i  < totalSteps; i++){
				var stepName = (i + 1) + ".  " + this.getStepName(i);
				var stepStartTime = scene.Utils.translateSecondsToString(this.getStepStartTime(i), true);
				var stepDuration = scene.Utils.translateSecondsToString(this.getStepDuration(i), true);
				var stepErrorsHelps = this.getStepErrors(i) + " / " + this.getStepHelps(i);
				var stepResult = "";
				if(this.getStepVisited(i)){
					stepResult = "Выполнялся";
				} else {
					stepResult = "Не выполнялся";
				}
				var newStepInfo = "<tr><td>" + stepName + "</td><td align=\"center\">" + stepStartTime + "</td><td align=\"center\">" + stepDuration + "</td><td align=\"center\">" + stepErrorsHelps + "</td><td align=\"center\">" + stepResult + "</td></tr>";
				textResult.value = textResult.value + newStepInfo;
			}
			//	суммарные параметры
			var stepName = "Общий результат";
			var stepStartTime = "";
			var stepDuration = scene.Utils.translateSecondsToString(this.getTotalDuration(), true);
			var stepErrorsHelps = this.getTotalErrors() + " / " + this.getTotalHelps();
			var stepResult = "";
			var newStepInfo = "<tr><td>" + stepName + "</td><td align=\"center\">" + stepStartTime + "</td><td align=\"center\">" + stepDuration + "</td><td align=\"center\">" + stepErrorsHelps + "</td><td align=\"center\">" + stepResult + "</td></tr>";
			textResult.value = textResult.value + newStepInfo;
			textResult.saveAs("result.htm");
			textResult.parent = null;
		
			return false;
		}
		exportSettingsXML.src = settingsSrc;
		if (!exportSettingsXML.XMLDocument){
			return false;
		} else {
			exportSettingsXML.XMLDocument.source = exportSettingsXML.src;
			xmlNode = exportSettingsXML.XMLDocument.firstChild.firstChild;
			while(xmlNode){	
				if(xmlNode.nodeName == "header" && xmlNode.textContent){
					headerString = xmlNode.textContent;
				} else if(xmlNode.nodeName == "step" && xmlNode.textContent){
					xmlAttributeMap = xmlNode.attributes;
					if (xmlAttributeMap){
						xmlAttribute = xmlAttributeMap.getNamedItem("index");
						if (xmlAttribute != null && xmlAttribute.specified){
							switch((xmlAttribute.value).toLowerCase()){
							case "even":
								evenItemString  = xmlNode.textContent;	
								break;
							case "odd":
								oddItemString  = xmlNode.textContent;
								break;
							case "summary":
								summaryItemString  = xmlNode.textContent;
								break;
							}
						} else {
							defaultItemString = xmlNode.textContent;
						}
					}
				} else if(xmlNode.nodeName == "footer" && xmlNode.textContent){
					footerString = xmlNode.textContent;
				}
				xmlNode = xmlNode.nextSibling;
			}
			textResult.value = headerString;

			var totalSteps = this.getStepsTotal();
			for(var i = 0; i  < totalSteps; i++){
				if(this.stepTypes[i] == "summary"){
					continue;
				}
				var srcItemStr = "";
				if(evenItemString && oddItemString){
					if(((i + 1) % 2) == 0){
						srcItemStr = "\n" + evenItemString;
					} else {
						srcItemStr = "\n" + oddItemString;
					}
				} else {
					srcItemStr = defaultItemString;
				}
				var re = new RegExp("(%StepIndex%)", "g");
				srcItemStr = srcItemStr.replace(re, (i+1));
				re = null;
				re = new RegExp("(%StepName%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getStepName(i));
				re = null;
				var re = new RegExp("(%StartTime%)", "g");
				srcItemStr = srcItemStr.replace(re, scene.Utils.translateSecondsToString(this.getStepStartTime(i), true));
				re = null;
				var re = new RegExp("(%Duration%)", "g");
				srcItemStr = srcItemStr.replace(re, scene.Utils.translateSecondsToString(this.getStepDuration(i), true));
				re = null;
				var re = new RegExp("(%Errors%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getStepErrors(i));
				re = null;
				var re = new RegExp("(%Helps%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getStepHelps(i));
				re = null;
				var re = new RegExp("(%Result%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getStepResult(i));
				re = null;
				textResult.value = textResult.value + srcItemStr;
			}
			if(summaryItemString){
				//	суммарные параметры
				if(summaryItemString){
					srcItemStr = "\n" + summaryItemString;
				} else {
					srcItemStr = defaultItemString;
				}
				var re = null;
				re = new RegExp("(%StepIndex%)", "g");
				srcItemStr = srcItemStr.replace(re, "");
				re = null;
				re = new RegExp("(%StepName%)", "g");
				srcItemStr = srcItemStr.replace(re, "Общий результат");
				re = null;
				//var re = new RegExp("(%StartTime%)", "g");
				//srcItemStr = srcItemStr.replace(re, "");
				//re = null;
				//var re = new RegExp("(%Duration%)", "g");
				//srcItemStr = srcItemStr.replace(re, this.getTotalDuration());
				//re = null;
				var re = new RegExp("(%Errors%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getTotalErrors());
				re = null;
				var re = new RegExp("(%Helps%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getTotalHelps());
				re = null;
				var re = new RegExp("(%Result%)", "g");
				srcItemStr = srcItemStr.replace(re, this.getTotalResult());
				re = null;
				textResult.value = textResult.value + srcItemStr;
			}
		}
		textResult.value = textResult.value + footerString;
		textResult.saveAs("result.htm");
		textResult.parent = null;
		
	}

	function addErrors(errorsIncrement){
		//trace("#FF0000Errors Before INcrement:" + this.stepAttemptsErrors[this.currentStep][this.currentAttempt]);
		var currentErrors = this.stepAttemptsErrors[this.currentStep][this.currentAttempt];
		currentErrors += errorsIncrement;
		if(currentErrors >= 0){
			this.stepAttemptsErrors[this.currentStep][this.currentAttempt] = currentErrors;
		} else {
			trace("#FF0000Уменьшение количества ошибок некорректно. Их не может быть меньше 0.");
			this.stepAttemptsErrors[this.currentStep][this.currentAttempt] = 0;
		}
		//trace("#FF0000Errors After INcrement:" + this.stepAttemptsErrors[this.currentStep][this.currentAttempt]);
	}

	function addHelps(helpsIncrement){
		//trace("#FF0000Helps Before INcrement:" + this.stepAttemptsHelps[this.currentStep][this.currentAttempt]);
		var currentHelps = this.stepAttemptsHelps[this.currentStep][this.currentAttempt];
		currentHelps += helpsIncrement;
		if(currentHelps >= 0){
			this.stepAttemptsHelps[this.currentStep][this.currentAttempt] = currentHelps;
		} else {
			trace("#FF0000Уменьшение количества подсказок некорректно. Их не может быть меньше 0.");
			this.stepAttemptsHelps[this.currentStep][this.currentAttempt] = 0;
		}
		//trace("#FF0000Helps After INcrement:" + this.stepAttemptsHelps[this.currentStep][this.currentAttempt]);
	}

	function updateStatistics(newResult, newErrors, newHelps){
		if(parent.localStepIndicator){
			parent.localStepIndicator.onResultManagerEventOccuried(ON_STEP_RESULT_CHANGED, newResult);
			parent.localStepIndicator.onResultManagerEventOccuried(ON_STEP_ERRORS_CHANGED, newErrors);
			parent.localStepIndicator.onResultManagerEventOccuried(ON_STEP_HELPS_CHANGED, newHelps);
		}
	}

	function traceStepStatistics(){
		var stepsTotal = this.getStepsTotal();

		for(var i = 0; i < stepsTotal; i++){
			trace(i + ": " + this.stepNames[i]);
			trace("\tТип шага: " + this.stepTypes[i]);
			trace("\tВыполнялся: " + this.stepVisited[i]);
			trace("\tПопыток: " + this.stepAttempts[i]);
			switch(this.stepResultSelectRule[i]){
			case SELECT_RESULT_LAST:
				trace("\tПравило выбора результата: ПОСЛЕДНИЙ");
				break;
			case SELECT_RESULT_BEST:
				trace("\tПравило выбора результата: ЛУЧШИЙ");
				break;
			case SELECT_RESULT_AVERAGE:
				trace("\tПравило выбора результата: СРЕДНИЙ");
				break;
			}
			trace("\tРезультат: " + this.getStepResult(i));
		}
	}

		/*	this.stepNames = new Array();
		this.stepTypes = new Array();
		this.stepResultCount = new Array();
		this.stepResultSelectRule = new Array();
		this.stepVisited = new Array();
		this.stepAttempts = new Array();
		this.stepAttemptsStart = new Array();
		this.stepAttemptsDurations = new Array();
		this.stepAttemptsResult = new Array();
		this.stepAttemptsErrors = new Array();
		this.stepAttemptsHelps = new Array();

	SELECT_RESULT_LAST:
				if(this.stepAttemptsResult[stepId] && this.stepAttemptsResult[stepId].length > 0){
					var attemptIndex = this.stepAttemptsResult[stepId].length;
					newStepResult = this.stepAttemptsResult[stepId][attemptIndex - 1];
				} else {
					newStepResult = 0;
				}
				break;
			case SELECT_RESULT_BEST:
				if(this.stepAttemptsResult[stepId] && this.stepAttemptsResult[stepId].length > 0){
					var bestResult = 0;
					for(var i = 0; i < this.stepAttemptsResult[stepId].length; i++){
						if(this.stepAttemptsResult[stepId][i] > bestResult)
							bestResult = this.stepAttemptsResult[stepId][i];
					}
					newStepResult = bestResult;
				} else {
					newStepResult = 0;
				}
				break;
			case SELECT_RESULT_AVERAGE:
	*/
]]></script>
</composition>
</rmml>