/*
 * 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/.
 */

/**
 * @constructor
 */
function Pianos4ToolPairing( params )
{
    // ------------------------------
    // Constructor
    // ------------------------------
    
    params = params || {};
    
    // ------------------------------
    // Public methods
    // ------------------------------
    
    this.getName = function()
    {
        return 'pairing';
    }

    this.getLabel = function()
    {
        return 'Pairing';
    }

    this.getIcon = function()
    {
        return 'icons/tool_pairing.png';
    }

    this.bind = function( aView )
    {
        assert( !view );
        view = aView;
    }

    this.unbind = function()
    {
        assert( view );
        view = null;
    }

    this.activate = function()
    {
        assert( !popups );
        
        popups = [];
        
        var views = [
            pianos.getView( 'mark' ), pianos.getView( 'print' )
        ];
        w = $( '<div class="pianos4_pairing_hint ui-widget ui-widget-content" />' );
        
        for( var i in views )
        {
            var canvas = views[ i ].getDOM();
            var p = canvas.offset();
            p.left += parseInt( canvas.css( 'border-left-width' ) );
            var node = w.clone();
            node.css( 'left', p.left ).css( 'top', p.top ).outerWidth( canvas.width() )
            // .append('<span class="ui-icon ui-icon-arrowthick-1-s
            // ui-inline-icon" />')
            .append( '<span class="_text">Pick a minutia to start pairing</span>' )
            // .append('<span class="ui-icon ui-icon-arrowthick-1-s
            // ui-inline-icon" />')
            ;
            $( 'body' ).append( node );
            popups.push( node );
            
            var minutiae = views[ i ].getData().minutiae;
            for( var j in minutiae )
            {
                var m = minutiae[ j ];
                if( 'pairing' in m )
                {
                    var g = views[ i ].getSVG().select( '#minutia_' + m.id );
                    assert( g.length == 1 );
                    g.attr( 'stroke-opacity', 0.3 );
                }
            }
        }
        pianos.toggleLayer( 'pairing', true );
    }

    this.deactivate = function()
    {
        assert( popups );
        for( var i in popups )
            popups[ i ].remove();
        popups = null;
        
        var views = [
            pianos.getView( 'mark' ), pianos.getView( 'print' )
        ];
        for( var i in views )
        {
            var minutiae = views[ i ].getData().minutiae;
            for( var j in minutiae )
            {
                var m = minutiae[ j ];
                if( 'pairing' in m )
                {
                    var g = views[ i ].getSVG().select( '#minutia_' + m.id );
                    assert( g.length == 1 );
                    g.attr( 'stroke-opacity', 1.0 );
                }
            }
        }
        pianos.toggleLayer( 'pairing', false );
    }

    this.onMouseDown = function( pos, target )
    {
        var me = view.isMark() ? 0 : 1;
        var other = 1 - me;
        var paired = null;
        
        if( step == 0 )
        {
            assert( !startView && !startMinutia && !endMinutia );
            
            var picked = view.pickByNode( target );
            if( picked && picked.type == 'minutia' )
            {
                // log('Starting pick in view '+view.getType()+' with
                // minutia:');
                // log(startMinutia);
                
                if( eraser )
                {
                    log( picked );
                    if( 'pairing' in picked.annotation )
                        step = 5;
                    else
                        return true;
                } else
                {
                    assert( options );
                    options.find( 'input' ).attr( 'disabled', 'disabled' );
                    paired = picked;
                    step = 1;
                }
                
                startView = view;
                startMinutia = picked;
                
                popups[ me ].addClass( 'ui-state-highlight' ).find( '._text' ).text( 'Release the button' );
                popups[ other ].find( '._text' ).text( '-' );
            }
        } else if( step == 2 )
        {
            assert( startView && startMinutia && !endMinutia );
            
            if( view.getType() != startView.getType() )
            {
                var picked = view.pickByNode( target );
                if( picked && picked.type == 'minutia' )
                {
                    endMinutia = picked;
                    
                    // log('Paired pick in view '+view.getType()+' with
                    // minutia:');
                    // log(endMinutia);
                    
                    popups[ me ].addClass( 'ui-state-highlight' ).find( '._text' ).text( 'Release the button' );
                    popups[ other ].find( '._text' ).text( '-' );
                    
                    paired = picked;
                    step = 3;
                }
            }
        }
        
        if( paired )
        {
            
        }
    }

    this.onMouseMove = function( pos, target )
    {
    }

    this.onMouseUp = function( pos, target )
    {
        var me = view.isMark() ? 0 : 1;
        var other = 1 - me;
        
        if( step == 1 )
        {
            assert( startView && startMinutia && !endMinutia );
            popups[ me ].removeClass( 'ui-state-highlight' ).find( '._text' ).text( '-' );
            popups[ other ].addClass( 'ui-state-highlight' ).find( '._text' ).text( 'Pick the corresponding minutia' );
            
            step = 2;
        } else if( step == 3 )
        {
            assert( startView && startMinutia && endMinutia && view.getType() != startView.getType() );
            
            var markMin, printMin;
            if( startView.isMark() )
            {
                markMin = startMinutia;
                printMin = endMinutia;
            } else
            {
                markMin = endMinutia;
                printMin = startMinutia;
            }
            var action = new Pianos4Action_PairMinutiae( markMin.annotation, printMin.annotation, Pianos4Annotation._s_pairIds++ );
            
            startView = null;
            startMinutia = null;
            endMinutia = null;
            
            for( var i in popups )
                popups[ i ].removeClass( 'ui-state-highlight' ).find( '._text' ).text( 'Pick a minutia to continue pairing' );
            
            assert( options );
            options.find( 'input' ).removeAttr( 'disabled' );
            
            step = 0;
            
            pianos.exec( action );
        } else if( step == 5 )
        {
            assert( eraser );
            
            var markMin, printMin;
            if( startView.isMark() )
            {
                markMin = startMinutia.annotation;
                printMin = null;
            } else
            {
                markMin = null;
                printMin = startMinutia.annotation;
            }
            var action = new Pianos4Action_PairMinutiae( markMin, printMin, null );
            
            startView = null;
            startMinutia = null;
            endMinutia = null;
            
            for( var i in popups )
                popups[ i ].removeClass( 'ui-state-highlight' ).find( '._text' ).text( 'Pick a minutia to remove its pairing' );
            
            step = 0;
            pianos.exec( action );
        }
        
        return true;
    }

    this.getOptionsPanel = function()
    {
        if( !options )
        {
            var panel = $( '<div class="pianos4_pairing_options" />' );
            
            var randomID = 'pianos4_rid_' + ( new Date().getTime() );
            var eraserBox = $( '<input type="checkbox" ' + ( eraser ? 'checked="checked"' : '' ) + ' id="' + randomID + '" />' );
            eraserBox.bind( 'click', function()
            {
                eraser = this.checked;
                assert( step == 0 && popups && popups.length >= 2 );
                var msg = 'Pick a minutia to ';
                if( eraser )
                    msg += 'remove its pairing';
                else
                    msg += 'start pairing';
                
                for( var i in popups )
                    popups[ i ].find( '._text' ).text( msg );
            } );
            var label = $( '<label for="' + randomID + '" />' ).text( 'Eraser mode' );
            
            panel.append( $( '<div />' ).append( eraserBox ).append( label ) );
            
            var restart = $( '<a />' ).text( 'Restart numbering' ).attr( 'href', '#restart_numbering' ).bind( 'click', function( e )
            {
                e.preventDefault();
                self.restartNumbering();
            } );
            
            var remove = $( '<a />' ).text( 'Remove all pairing' ).attr( 'href', '#remove_all_pairing' ).bind( 'click', function( e )
            {
                e.preventDefault();
                self.removeAllPairing();
            } );
            
            panel.append( $( '<div />' ).css( 'margin-top', '0.5em' ).append( restart ) ).append( $( '<div />' ).css( 'margin-top', '0.5em' ).append( remove ) );
            
            options = panel;
        }
        
        return options;
    }

    this.restartNumbering = function()
    {
        var batch = new Pianos4Action_Batch( 'Restart numbering' );
        var pairs = {};
        Pianos4Annotation._s_pairIds = 1;
        
        var mark = pianos.getView( 'mark' );
        var mannotations = mark.getAllAnnotations();
        for( var id in mannotations )
        {
            var a = mannotations[ id ][ 1 ];
            if( 'pairing' in a )
            {
                assert( mannotations[ id ][ 0 ] == 'minutia' );
                pairs[ a.pairing ] = a;
            }
        }
        
        var print = pianos.getView( 'print' );
        var pannotations = print.getAllAnnotations();
        for( var id in pannotations )
        {
            var a = pannotations[ id ][ 1 ];
            if( 'pairing' in a )
            {
                assert( pannotations[ id ][ 0 ] == 'minutia' );
                assert( a.pairing in pairs );
                var action = new Pianos4Action_PairMinutiae( pairs[ a.pairing ], a, Pianos4Annotation._s_pairIds++ );
                batch.append( action );
            }
        }
        
        pianos.exec( batch );
    }

    this.removeAllPairing = function()
    {
        var batch = new Pianos4Action_Batch( 'Remove all pairing' );
        var pairs = {};
        Pianos4Annotation._s_pairIds = 1;
        
        var mark = pianos.getView( 'mark' );
        var mannotations = mark.getAllAnnotations();
        for( var id in mannotations )
        {
            var a = mannotations[ id ][ 1 ];
            if( 'pairing' in a )
            {
                assert( mannotations[ id ][ 0 ] == 'minutia' );
                var action = new Pianos4Action_PairMinutiae( a, null, null );
                batch.append( action );
            }
        }
        
        pianos.exec( batch );
    }

    this.getHelp = function()
    {
        return Pianos4Help
            .compile( [
                'Use the pairing tool to associate (i.e. "match") minutiae on the mark and on the print.',
                'You normally use the pairing tool after all minutiae have been drawn on both images. When it is activated, you must select pairs of minutiae in sequence: one on the mark, then the corresponding one on the print. You can also start by a minutia print and then one on the mark. Once both minutiae have been selected, they are paired and a number appear on top of them. You can then continue pairing until you are satisfied.',
                'When the \'Eraser mode\' is active, a click will remove the pairing of the minutia pointed to - note that the number disappears from both images. You can also remove all pairing using the appropriate option.',
                'Since you cannot choose the pairing number, you may end up with non consecutive numbers and/or a sequence that does not start at 1. Using the \'Restart numbering\' option will re-assign sequential pairing numbers. You generally want to use this option as a final step to make the result look better.',
                '<<mouse:left>>: select a minutia',
                '<<mouse:left>>: (in eraser mode) remove pairing',
                '<<key:P>>: (shortcut) switch to the pairing tool',
                'Note: the pairing numbers are only shown when the \'Pairing\' layer is visible. It is made visible automatically when the pairing tool is activated, but it can also be shown at any moment by using the Layers window.',
            ] );
    }

    // ------------------------------
    // Private variables
    // ------------------------------
    
    var self = this;
    var view = null;
    var startView = null;
    var startMinutia = null;
    var endMinutia = null;
    var popups = null;
    var step = 0;
    var eraser = false;
    var options = null;
    
    // ------------------------------
    // Private functions
    // ------------------------------
}
