package animation;

import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.Stack;

import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.SwingUtilities;

import animation.PseudoCodeNode.CodeStatus;
import animation.StackFrame.FrameType;
import graph.LayeredGraphNode;

public abstract class AnimatedAlgorithm extends Thread implements AlgorithmStage {

    protected AnimationController ac;
    protected LayeredGraphNode graph;
    private JFrame view;
    protected PseudoCodeNode root;
    protected Stack<PseudoCodeNode> activeFunction;
    protected Memory mem;
    private Memory fstack;

    public AnimatedAlgorithm( AnimationController controller, LayeredGraphNode graph, JFrame view )
    {
        this.ac = controller;
        this.graph = graph;
        this.view = view;
        root = null;
        mem = new Memory();
        mem.declare( "graph", graph, true );
        activeFunction = new Stack<PseudoCodeNode>();
        fstack = new Memory();
    }
    
    public void addActiveFunction( PseudoCodeNode n )
    {
    	if( !activeFunction.empty() )
    		activeFunction.peek().writeToStack( fstack );
        fstack.addFrame( new StackFrame( FrameType.FUNCTION ) );
    	activeFunction.push( n );
    }

    private void update()
    {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                view.repaint();
                for( ComponentListener l : view.getComponentListeners() )
                {
                    l.componentResized( new ComponentEvent(view, 0) );
                }
            }
        });
    }

    @Override
    public void run()
    {
        while( true ) // if this loop would end we could not undo steps any more
        {
        	CodeStatus status = null;
            try {
            	while( activeFunction.size() == 0 )
            		Thread.sleep( 100 );
            	PseudoCodeNode current = activeFunction.peek();
                switch( ac.getNextAction() )
                {
                case FORWARD:
                	status = current.forwardStep( mem );
                    break;
                case FORWARD_OUT:
                    status = current.forwardStepOut( mem );
                    break;
                case FORWARD_OVER:
                    status = current.forwardStepOver( mem );
                    break;
                case BACKWARD:
                    status = current.backwardStep( mem );
                    break;
                case BACKWARD_OUT:
                    status = current.backwardStepOut( mem );
                    break;
                case BACKWARD_OVER:
                    status = current.backwardStepOver( mem );
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                return;
            }
            update();
            if( status == CodeStatus.FINISHED )
            {
            	if( activeFunction.size() > 1 )
            	{
            		fstack.removeFrame();
            		activeFunction.pop();
            		activeFunction.peek().loadFromStack( fstack );
            	}
            }
        }
    }

    @Override
    public abstract PseudoCodeNode createPseudocodeTree( JTree tree );
}
