package codeline;

import processor.ControlFlow;
import processor.Memory;
import processor.StackFrame;
import processor.Memory.ReadOnlyMemory;
import processor.Memory.Visibility;
import processor.StackFrame.FrameType;

public abstract class WhileLoop extends CodeLine {

	@Override
	public ControlFlow runForward(Memory m) {
		boolean declared = false; // prove if it is the first step in the loop
		if( !m.isDefined( "line_" + lineId + "_index", Visibility.LOCAL ) )
		{ // first loop step
			declared = true;
		}
        if( !condition( m.createReadOnlyMemory() ) ) // prove if loop was finished
        {
            if( !declared )
            {
                StackFrame sf = m.removeFrame(); // remove loop stack
                actions.push( (Memory mem) -> {
                    mem.addFrame( sf ); // restore last loop stack
                });
            }
            else
            {
                actions.push( (Memory mem) -> {});
            }
            return new ControlFlow( ControlFlow.STEP_OVER ); // step out of the loop
        }
		if( declared )
		{
			m.addFrame( new StackFrame( FrameType.LOOP ) );
            m.declare( "line_" + lineId + "_index", 0, Visibility.LOCAL );
			actions.push( (Memory mem) -> {
				mem.removeFrame();
			} );
		}
		else
		{
			StackFrame old = m.removeFrame(); // fresh stack frame for loop body
			m.addFrame( new StackFrame( FrameType.LOOP ) );
            m.declare( "line_" + lineId + "_index", 0, Visibility.LOCAL );
			actions.push( (Memory mem) -> {
				mem.removeFrame();
				mem.addFrame( old );
			});
		}
		return new ControlFlow( ControlFlow.STEP_INTO );
	}

	abstract protected boolean condition( ReadOnlyMemory m );
}
