<?php
/*
 * PiAnoS (Picture Annotation System), A fingerprint examiner training tool
 * Copyright (C) 2011-2021 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()->addScriptForceReload( Application::get( 'jsforcereload' ) );
        
        $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()->addStyleSheet( Application::get( 'csslib_toastr' ) );
        $rs->getPage()->addScript( Application::get( 'jslib_toastr' ) );
        $rs->getPage()->addScript( Application::get( 'jslib_easing' ) );
        
        $rs->getPage()->addScript( Application::get( 'TPS' ) );
        
        $rs->getPage()->addScript( Application::get( 'jslib_d3' ) );
        
        $rs->getPage()->addScript( Application::get( 'jslib_jquery_tablesorter' ) );
        $rs->getPage()->addStyleSheet( Application::get( 'csslib_jquery_tablesorter' ) );
        
        $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_TPS.js' );
            
            if( Application::get( 'imageeditor' ) )
                $rs->getPage()->addScript( $base . 'js/pianos4_tool_imageeditor.js' );
            
            $rs->getPage()->addScript( $base . 'js/pianos4_tool_measure.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' );

            $rs->getPage()->addScript( $base . 'js/pinger.js' );
            $rs->getPage()->addScript( $base . 'js/preloader.js' );
            
            if( Application::get( 'viewTracker' ) && ! $_SESSION[ 'user' ][ 'isadmin' ] )
                $rs->getPage()->addScript( $base . 'js/viewTracker.js' );
            
            if( $_SESSION[ 'user' ][ 'isadmin' ] )
                $rs->getPage()->addScript( $base . 'js/pianos4_tool_review.js' );
            
            $rs->getPage()->addScript( $base . 'js/pianos4_tool_LR.js' );
            
            $rs->getPage()->addScript( $base . 'js/pianos4_tool_MD.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' ) );
        
        $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' ], 
                        'username' => $_SESSION[ 'user' ][ 'username' ], 
                        'tutor' => $_SESSION[ 'user' ][ 'isadmin' ], 
                        'switchedUser' => isset( $_SESSION[ 'user' ][ 'switchedUser' ] ) ? $_SESSION[ 'user' ][ 'switchedUser' ] : "",
                        'email' => isset( $_SESSION[ 'user' ][ 'email' ] ) ? $_SESSION[ 'user' ][ 'email' ]: "" 
                ), 
                'tutor_can_delete_lrs' => Application::get( "tutor_can_delete_lrs" ),
                'mark' => array (
                		'id' => $images[ 'mark' ][ 'id' ],
                        'href' => '?action=get_image&id=' . $images[ 'mark' ][ 'id' ], 
                        'width' => ( int ) $images[ 'mark' ][ 'width' ], 
                        'height' => ( int ) $images[ 'mark' ][ 'height' ], 
                        'resolution' => ( int ) $images[ 'mark' ][ 'resolution' ],
                		'name' => $images[ 'mark' ][ 'name' ]
                ), 
                'print' => array (
                		'id' => $images[ 'print' ][ 'id' ],
                        'href' => '?action=get_image&id=' . $images[ 'print' ][ 'id' ], 
                        'width' => ( int ) $images[ 'print' ][ 'width' ], 
                        'height' => ( int ) $images[ 'print' ][ 'height' ], 
                        'resolution' => ( int ) $images[ 'print' ][ 'resolution' ],
                		'name' => $images[ 'print' ][ 'name' ]
                ), 
                'caseName' => $ex[ 'name' ], 
                'exid' => $exid, 
                'title' => $ex['name'],

                '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', 
                
                'skip_mendatory_fields_and_set_default' => Application::get( "skip_mendatory_fields_and_set_default" ),
                'skip_quality_and_minutiae_checks__manualconfig' => Application::get( "skip_quality_and_minutiae_checks" ),
        	
                'show_marker_size_slider' => Application::get( "show_marker_size_slider" ),
                'makerSizeMin' => Application::get( "makerSizeMin" ),
                'makerSizeMax' => Application::get( "makerSizeMax" ),
        	
        		'show_marker_opacity_slider' => Application::get('show_marker_opacity_slider'),
        	
        		'markCanHaveCenter' => Application::get('markCanHaveCenter'),
                
                'initialTool' => Application::get('initialTool'),
            
                'TPS_grid_url' => Application::get( 'TPS_grid_url' ),
                'TPS_scale_limit_notification' => Application::get( 'TPS_scale_limit_notification' ),
                
                'imageeditor' => Application::get( 'imageeditor' ),
                
                'Xena_api_state' => Application::get( 'Xena_api_state' ),
            
                'python_api_export_case' => Application::get( 'python_api_export_case' ),
                'python_api_export_case_callback' => Application::get( 'python_api_export_case_callback' )
        );
        // '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' ] );
            
            if( isset( $_GET[ 'step' ] ) && in_array( strtolower( $_GET[ 'step' ] ), array( 'analysis', 'comparison' ) ) )
                $progress = array( 'status' => 1, 'step' => strtoupper( $_GET[ 'step' ] ) );
            else
                $progress = $db->getAssignmentProgress( $aid );
        }
        
        $settings[ 'phase' ] = strtolower( $progress[ 'step' ] );
        $settings[ 'loadResults' ] = '?action=rpc&method=getResults&type=LATEST&step=' . $progress[ 'step' ] . '&aid=' . $aid;
        
        if( isset( $_GET[ 'multiCaseViewer' ] ) )
            $settings[ 'loadResults' ] .= "&multiCaseViewer=" . $_GET[ 'multiCaseViewer' ];
        
        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=getExerciseAssignments&id=' . $ex[ 'id' ] . '&extended=true';
            
            if( isset( $_GET[ 'multiCaseViewer' ] ) )
                $moreSettings[ 'getConclusionsScript' ] .= "&multiCaseViewer=" . $_GET[ 'multiCaseViewer' ];
            
            if( Application::get( 'anonymous_review' ) )
            {
                if( isset( $_GET[ 'anonymousreview' ] ) )
                {
                    $anonymous_review = ( int ) $_GET[ 'anonymousreview' ];
                    if( $anonymous_review )
                    {
                        $moreSettings[ 'getConclusionsScript' ] .= '&anonymousreview=1';
                        $moreSettings[ 'anonymous_review' ] = true;
                        $settings[ 'loadResults' ] .= '&anonymousreview=1';
                        
                        try {
                            if( count( $settings[ 'title' ][ 0 ] ) )
                                $settings[ 'title' ][ 0 ][ 1 ] .= '&anonymousreview=1';
                        } catch( Exception $e ){}
                        try {
                            if( count( $settings[ 'title' ][ 2 ] ) )
                                $settings[ 'title' ][ 2 ][ 1 ] .= '&anonymousreview=1';
                        } catch( Exception $e ){}
                    } else {
                        $moreSettings[ 'anonymous_review' ] = false;
                    }
                } else {
                    $moreSettings[ 'anonymous_review' ] = false;
                }
            }
        } 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 ) && Application::get( "novalue_comparison_startup_dialog" ) )
                {
                    $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 );
    }
}
