package bk;

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

import animation.AnimatedAlgorithm;
import animation.AnimationController;
import animation.CodeLine;
import animation.ControlFlow;
import animation.Memory;
import animation.PseudoCodeNode;
import animation.StackFrame;
import animation.StackFrame.FrameType;
import codelines.FunctionCall;
import codelines.FunctionDefinition;
import graph.LayeredGraphNode;
import lib.TextLayoutHelper;

/**
 * The main stage of the BK node placement algorithm.
 * @author kolja
 *
 */
public class BKNodePlacement extends AnimatedAlgorithm {

    /*
     * Private data structures to store the process of the algorithm
     */

    public enum State
    {
        CONFLICTS,
        LAYOUT1,
        LAYOUT2,
        LAYOUT3,
        LAYOUT4,
        COMBINE
    }

    private ConflictDetection conftion;
    private State state;
    private ExtremalLayoutCalc layouts[];
    private Combine combine;

    public BKNodePlacement(AnimationController controller, LayeredGraphNode graph, JFrame view) {
        super(controller, graph, view);
        state = State.CONFLICTS;
        conftion = new ConflictDetection( this );
        layouts = new ExtremalLayoutCalc[ 4 ];
        layouts[ 0 ] = new ExtremalLayoutCalc( graph, this );
        layouts[ 1 ] = new ExtremalLayoutCalc( graph, this );
        layouts[ 2 ] = new ExtremalLayoutCalc( graph, this );
        layouts[ 3 ] = new ExtremalLayoutCalc( graph, this );
        combine = new Combine( graph, this );
    }
    
    public State getAlgorithmState()
    {
        return state;
    }

    @Override
    public PseudoCodeNode createPseudocodeTree( JTree tree )
    {
    	String[] vars = { "graph" };
    	PseudoCodeNode mainFunction = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode("function bkNodePlacement( graph )", vars ), tree, new FunctionDefinition( new String[]{"graph"} ), this );
    	root = new PseudoCodeNode( TextLayoutHelper.setupPseudoCodeStage("-- BK Node Placement Algorithm --" ), tree, new CodeLine() {

			@Override
			public ControlFlow runForward(Memory m) {
				m.declare( "param1", graph, true );
				actions.push( (Memory mem) -> {
					return new ControlFlow( mainFunction );
				} );
				return new ControlFlow( mainFunction );
			}
        	
        }, this );
        root.setSelected( true );
    	
        PseudoCodeNode conflictDetectionFunction = conftion.createPseudocodeTree( tree );
        PseudoCodeNode node1 = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call detectConflicts( graph )", vars ), tree, new FunctionCall( conflictDetectionFunction, new String[]{ "graph" } ), this );
        root.add( mainFunction );
        mainFunction.add( node1 );
        root.add( conflictDetectionFunction );
        this.addActiveFunction( root );
        return root;
    }

    @Override
    public String getDebugString()
    {
        switch( state )
        {
        case CONFLICTS:
            return conftion.getDebugString();
        case LAYOUT1:
            return layouts[ 0 ].getDebugString();
        case LAYOUT2:
            return layouts[ 1 ].getDebugString();
        case LAYOUT3:
            return layouts[ 2 ].getDebugString();
        case LAYOUT4:
            return layouts[ 3 ].getDebugString();
        case COMBINE:
            return combine.getDebugString();
        }
        return "";
    }
}
