<?php
/*
PiAnoS (Picture Annotation System), A fingerprint examiner training tool
Copyright (C) 2011-2012 University of Lausanne, Switzerland
https://ips-labs.unil.ch/pianos

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see http://www.gnu.org/licenses/.
*/


require_once("unil/Node.php");
require_once("unil/Sizer.php");

class ExerciseFrame extends Node
{
	function prepareRS(&$rs)
	{
		$isIE = strpos($_SERVER['HTTP_USER_AGENT'],'MSIE');

		$base = '';

		$rs->getPage()->addScript(Application::get('jslib_jquery_layout'));
		$rs->getPage()->addScript(Application::get('jslib_jquery_hotkeys'));
		$rs->getPage()->addScript(Application::get('jslib_jquery_mousewheel'));

		$rs->getPage()->addScript(Application::get('jslib_d3'));

		$p4JS = Application::get('use_minified_pianos4');
		if ($p4JS)
		{
			$rs->getPage()->addScript($p4JS);
		}
		else
		{
			$rs->getPage()->addScript($base.'js/pianos4_common.js');
			$rs->getPage()->addScript($base.'js/pianos4_ui.js');
			$rs->getPage()->addScript($base.'js/pianos4.js');
			$rs->getPage()->addScript($base.'js/pianos4_view.js');
			$rs->getPage()->addScript($base.'js/pianos4_annotation.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_edit.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_minutia.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_ridge.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_comment.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_pan.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_pairing.js');
			$rs->getPage()->addScript($base.'js/pianos4_tool_group.js');
			$rs->getPage()->addScript($base.'js/pianos4_action.js');
			$rs->getPage()->addScript($base.'js/pianos4_constants.js');
			$rs->getPage()->addScript($base.'js/pianos4_report.js');
			$rs->getPage()->addScript($base.'js/pianos4_help.js');
			if ($_SESSION['user']['isadmin'])
				$rs->getPage()->addScript($base.'js/pianos4_tool_review.js');

			$rs->getPage()->addScript($base.'js/imageeditor.js');
			$rs->getPage()->addScript($base.'js/imageeditor_brightness_contrast.js');
			$rs->getPage()->addScript($base.'js/imageeditor_invert.js');
		}
		

		$rs->getPage()->addStyleSheet(Application::get('csslib_jquery_ui'));
		$rs->setJQueryStyleSheet(Application::get('jqueryui_theme'), 'theme-pianos4.css');
		$rs->getPage()->addStyleSheet($base.'css/app.css');
		$rs->getPage()->addStyleSheet($base.'css/app-svg'.($isIE?'.ie':'').'.css');
		$rs->getPage()->addStyleSheet(Application::get('csslib_jquery_layout'));

		$rs->getPage()->addStyleSheet($base.'css/imageeditor.css');
		
		if ($_SESSION['user']['isadmin'])
		{
			$udbPath = Application::get('microdb_path');
			if ($udbPath)
			{
				$rs->getPage()->addScript($udbPath.'/js/jqui-qtable.js');
				$rs->getPage()->addStyleSheet($udbPath.'/css/udb.css');
			}
			else
			{
				$rs->getPage()->addScript(Application::get('jslib_microdb'));
				$rs->getPage()->addStyleSheet(Application::get('csslib_microdb'));
			}
		}
	}
	
	function render(&$rs)
	{
		$this->prepareRS($rs);
		
		$exid = (int)$this->getExerciseID();
		
		$db = Application::instance()->getDB();

		$ex = $db->getExercise($exid);
		
		$images = array(
			'mark' => $db->getImageInfo($ex['mark']),
			'print' => $db->getImageInfo($ex['print'])
		);
		//var_dump_pre($images);

		$settings = array(
			'version' => Application::get('version'),
			'divid' => 'pianos',
			'user' => array('id'=>$_SESSION['user']['id'], 'name'=>$_SESSION['user']['name'], 'tutor'=>$_SESSION['user']['isadmin']),
			'mark' => array(
				'href' => '?action=get_image&id='.$images['mark']['id'],
				'width' => (int)$images['mark']['width'],
				'height' => (int)$images['mark']['height'],
				'resolution' => (int)$images['mark']['resolution'],
			),
			'print' => array(
				'href' => '?action=get_image&id='.$images['print']['id'],
				'width' => (int)$images['print']['width'],
				'height' => (int)$images['print']['height'],
				'resolution' => (int)$images['print']['resolution'],
			),
			'useWCSTool' => true,
			'useQualityTool' => true,
			'useAreaTool' => false,
			'useCommentTool' => false,
			'phases' => array('analysis'=>true,'comparison'=>true),
			'editToolHotkey' => 'shift',
			'layerNames' => array('areas'=>'Quality'),
			'layoutBorderWidth' => 4,
			'checkedSubmit' => true,
			'loadResultsLabel' => 'Revert',
			'minutiaToolAutoPairing' => false,
			'phase' => 'analysis',
			'inferEditTool' => true,
			'resultsFilterScript' => '?action=rpc&method=manageResultsFilter',
			//'initialTool' => 'pan',
			//'showTimestampsInProperties' => true,
		);

		if (Application::get('user_manual_url'))
			$settings['userManualURL'] = Application::get('user_manual_url');
		
		$moreJSCode = '';
		$this->adjustSettings($ex, $settings, $moreJSCode);
		
		$configOverrides = Application::get('pianos_app_settings');
		if ($configOverrides && count($configOverrides))
			$settings = array_merge($settings, $configOverrides);

		$this->domStart('div', 'pianos');
		$this->domClose();
		
		$this->domStartJS();
		echo "
		$(document).ready(function() {
			var settings = ".json_encode($settings).";
			".$moreJSCode."\n
			$('body').css('height','100%').append($('<div />').css('height','100%').attr('id', settings.divid));
			pianos = new Pianos4(settings);
			// If the full microdb framework is loaded we need to call udb.run() at application startup.
			// Since the Pianos4 interface is not actually a microdb application (unlike the administration
			// backend, which is) it provides a small wrapper (pianos.run()) that satisfies microdb.
			// When using only the qtable component (the only required component for Pianos4) the udb object
			// is not defined and the regular pianos.init() function must be used. 
			// This is a temporary fix that will be made unnecessary in a (medium-far) future release.
			if (typeof(udb) == 'object' && typeof(udb.getVersion) == 'function')
				udb.run(pianos);
			else
				pianos.init();
		});";
		$this->domClose();
	}
}

class TakeExerciseFrame extends ExerciseFrame
{
	function getExerciseID()
	{	
		return (int)$_GET['id'];
	}
	
	function adjustSettings($ex, &$settings, &$jsCode)
	{
		$isTutorPreview = $_SESSION['user']['isadmin'] && isset($_GET['preview']) && $_GET['preview'];
		$isTutorReview = $_SESSION['user']['isadmin'] && !$isTutorPreview;
		
		$db = Application::instance()->getDB();
		if ($isTutorReview)
		{
			$aid = -$ex['id'];
			$progress = array('status'=>3, 'step'=>'ANALYSIS');
			if (isset($_GET['step']) && strtolower($_GET['step']) == 'comparison')
				$progress['step'] = 'COMPARISON';
			$title = array(NULL, $ex['name'], NULL);
			$neighbours = $db->getExerciseNeighbours($ex['id']);
			if (count($neighbours[0]))
				$title[0] = array($neighbours[0][0]['name'], '?action=take&id='.(int)$neighbours[0][0]['id']);
			if (count($neighbours[2]))
				$title[2] = array($neighbours[2][0]['name'], '?action=take&id='.(int)$neighbours[2][0]['id']);
			$settings['title'] = $title;
		}
		else
		{
			$aid = $db->getOrCreateAssignment($ex['id']);
			$progress = $db->getAssignmentProgress($aid);
		}
		
		$settings['phase'] = strtolower($progress['step']);
		$settings['loadResults'] = '?action=rpc&method=getResults&type=LATEST&step='.$progress['step'].'&aid='.$aid;
		
		if ($progress['status'] < 4)
		{
			// Can still load/save before the exercise is finished
			$moreSettings = array(
				'saveResults' => '?action=rpc&method=saveResults&type=CURRENT&step='.$progress['step'].'&aid='.$aid,
				'submitResults' => '?action=rpc&method=saveResults&type=VALIDATED&step='.$progress['step'].'&aid='.$aid,
			);
		}
		else
		{
			// Review mode: can not load/save
			$moreSettings = array(
				'hasClearButton' => false,
				'hasLoadButton' => false,
			);
		}

		if ($isTutorReview)
		{
			$moreSettings['showModifiedMinutiae'] = true;
			$moreSettings['getConclusionsScript'] = '?action=rpc&method=getAllConclusions&step='.$progress['step'].'&exid='.$ex['id'].'&type=conclusion';
		}
		elseif ($progress['status'] > 2)
		{
			// After the analysis step, all modifications to the minutiae will be visually
			// reported to the user. The submission date is used as the barrier to tell if
			// an annotation has been modified before or after the analysis was submitted.
			$moreSettings['showModifiedMinutiae'] = true;
			$moreSettings['updatedMinutiaeTimestamp'] = $db->getAssignmentSubmissionTime($aid, 'ANALYSIS');
		}
		
		if (!$isTutorReview)
		{
			if ($progress['step'] == 'ANALYSIS')
			{
				$moreSettings['defaultSuitabilityApproach'] = $db->getSuitabilityApproach();
			}
			else if ($progress['step'] == 'COMPARISON' && $progress['status'] < 4)
			{
				if ($db->isMarkOfNoValue($aid))
				{
					$jsCode .= "
					settings['onExerciseStartup'] = function(pianos, params) 
					{
						if (params.phase == 'comparison')
						{
							var dlg = $('<div />').text('For the purpose of this exercise, we invite you to process further to the comparison stage even though the conclusion of your analysis for that mark is “no value”.');
							pianos.dialog(dlg, {
								modal: true,
								title: 'Information',
								close: function() { $(this).remove(); },
								buttons: {
									'OK': function() { $(this).dialog('close'); }
								}
							});
						}
					};";
				}
			}
		}
		
		if (isset($moreSettings))
			$settings = array_merge($settings, $moreSettings);
	}
}

class ExerciseReportFrame extends ExerciseFrame
{
	private $byEID, $byAID;
	
	function __construct()
	{
		parent::__construct();
		$this->byEID = NULL;
		$this->byAID = NULL;
		if (isset($_GET['id']))
			$this->byEID = (int)$_GET['id'];
		elseif (isset($_GET['aid']))
			$this->byAID = (int)$_GET['aid'];
		if (($this->byEID === NULL && $this->byAID === NULL) || ($this->byEID !== NULL && $this->byAID !== NULL))
			throw new Exception("Invalid parameters");
	}
	
	function getExerciseID()
	{
		if ($this->byEID)
		{
			return $this->byEID;
		}
		else
		{
			$a = Application::instance()->getDB()->getAssignment($this->byAID);
			return (int)$a['exercise'];
		}
	}
	
	function adjustSettings($ex, &$settings, &$jsCode)
	{
		$isTutorPreview = $_SESSION['user']['isadmin'] && isset($_GET['preview']) && $_GET['preview'];
		$isTutorReview = $_SESSION['user']['isadmin'] && !$isTutorPreview;
		
		$steps = array('ANALYSIS','COMPARISON');
		
		if (isset($_GET['step']) && in_array(strtoupper($_GET['step']), $steps))
			$step = strtoupper($_GET['step']);
		else
			$step = 'ANALYSIS';

		if ($isTutorReview)
		{
			$aid = -$ex['id'];
			$progress = array('status'=>3, 'step'=>$step);
		}
		else
		{
			$db = Application::instance()->getDB();
			$aid = $db->tryGetAssignment($ex['id']);
			$progress = $db->getAssignmentProgress($aid);
		}
		
		$moreSettings = array(
			'phase' => strtolower($step),
			'loadResults' => '?action=rpc&method=getResults&type=LATEST&step='.$step.'&aid='.$aid,
			'hasLoadButton' => false,
			'hasClearButton' => false,
			'startsFullscreen' => true,
			'inferEditTool' => false,
			'initialTool' => 'pan',
			'useHotkeys' => false,
			'showToolbox' => false,
		);
		
		if ($isTutorReview)
		{
			$moreSettings['showModifiedMinutiae'] = true;
			//$moreSettings['getConclusionsScript'] = '?action=rpc&method=getAllConclusions&step='.$progress['step'].'&exid='.$ex['id'].'&type=conclusion';
		}
		elseif ($progress['status'] > 2)
		{
			// After the analysis step, all modifications to the minutiae will be visually
			// reported to the user. The submission date is used as the barrier to tell if
			// an annotation has been modified before or after the analysis was submitted.
			$moreSettings['showModifiedMinutiae'] = true;
			$moreSettings['updatedMinutiaeTimestamp'] = $db->getAssignmentSubmissionTime($aid, 'ANALYSIS');
		}
		
		if (isset($moreSettings))
			$settings = array_merge($settings, $moreSettings);
	}
}
