
package de.ugoe.cs.quest.eventcore.gui;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;

import de.ugoe.cs.quest.eventcore.Event;
import de.ugoe.cs.tasktree.keyboardmaps.VirtualKey;
import de.ugoe.cs.util.console.Console;

/**
 * <p>
 * Because often not all events are recorded properly, it is possible that there is not always a
 * KEYDOWN interaction each KEYUP interaction. This class provides the functionality to correct
 * these mismatches with one of the following two strategies:
 * <ul>
 * <li>Removal: each interaction that does not form a proper KEYDOWN/KEYUP pair is removed.</li>
 * <li>Addition: for each interaction that does not form a proper KEYDOWN/KEYUP pair, the missing
 * message is added to the sequence directly before/after the existing message.</li>
 * </ul>
 * </p>
 * 
 * @version $Revision: $ $Date: Sep 3, 2012$
 * @author 2012, last modified by $Author: sherbold$
 */
public class KeyInteractionCleaner {

    /**
     * <p>
     * Describes the clean-up mode.
     * </p>
     * 
     * @version $Revision: $ $Date: Sep 3, 2012$
     * @author 2012, last modified by $Author: sherbold$
     */
    public enum CleanupMode {
        REMOVAL, ADDITION
    };

    /**
     * <p>
     * Creates a copy of the passed sequence and performs the clean-up (see class description) on
     * the copy.
     * </p>
     * 
     * @param sequence
     *            sequence on which the clean-up is performed
     * @param mode
     *            defines whether removal or addition mode is used
     * @return copy of sequence with cleaned up key interactions
     */
    public List<Event> cleanupKeyInteractions(List<Event> sequence, CleanupMode mode) {
        List<Event> sequenceCopy = new LinkedList<Event>(sequence);
        List<VirtualKey> pressedKeys = new LinkedList<VirtualKey>();
        
        for( int i=0 ; i<sequenceCopy.size() ; i++ ) {
            Event event = sequenceCopy.get(i);
            if( event.getType() instanceof KeyPressed ) {
                pressedKeys.add(((KeyPressed) event.getType()).getKey());
            }
            if( event.getType() instanceof KeyReleased ) {
                VirtualKey key = ((KeyReleased) event.getType()).getKey();
                if( pressedKeys.contains(key)) {
                    pressedKeys.remove(key);
                }
                else {
                    Console.traceln(Level.INFO, "KeyReleased without KeyDown for key " + key + " found at index " + i);
                    switch(mode) {
                        case REMOVAL:
                            sequenceCopy.remove(i);
                            i--;
                            break;
                        case ADDITION:
                            KeyPressed pressed = new KeyPressed(key);
                            Event keyPressedEvent = new Event(pressed, event.getTarget());
                            sequenceCopy.add(i, keyPressedEvent);
                            i++;
                            break;
                        default:
                            throw new AssertionError("reached source code that should be unreachable");
                    }
                }
            }
        }
        return sequenceCopy;
    }
}
