package xhl.examples.statemachine;

import java.util.List;
import java.util.Map;

import xhl.core.GenericModule;
import xhl.core.elements.Block;
import xhl.core.elements.Expression;
import xhl.core.elements.Symbol;
import xhl.core.validator.Type;
import xhl.core.validator.Validator;

/**
 * XHL module for configuring state machine
 *
 * @author Sergej Chodarev
 */
public class StateMachineModule extends GenericModule {
    private Event[] resetEvents = null;
    private State startState = null;
    private State currentState = null;

    // DSL functions =========================================================

    @Element(name = "!script")
    public void script(@Symbolic Block exprs) {
        Map<Symbol, Type> defined =
                Validator.backwardDefinitions(exprs, getSchema());
        for (Symbol sym : defined.keySet())
            if (defined.get(sym).isNamed("State"))
                evaluator.putSymbol(sym, new State(sym.getName()));
        evaluator.eval(exprs);
    }

    @Element(evaluateArgs = false)
    public void events(Block blk) throws Exception {
        evaluator.pushEnvironment();
        evaluator.putSymbol(new Symbol(":"), getLocalElement("colonEvent"));
        evaluator.eval(blk);
        evaluator.popEnvironment();
    }

    @Element
    public void resetEvents(List<Event> events) {
        resetEvents = events.toArray(new Event[0]);
    }

    @Element(evaluateArgs = false)
    public void commands(Block blk) throws Exception {
        evaluator.pushEnvironment();
        evaluator.putSymbol(new Symbol(":"), getLocalElement("colonCommand"));
        evaluator.eval(blk);
        evaluator.popEnvironment();
    }

    @Element(local=true)
    public void colonEvent(@Symbolic Symbol name, String code) {
        Event event = new Event(name.getName(), code);
        evaluator.putGlobalSymbol(name, event);
    }

    @Element(local=true)
    public void colonCommand(@Symbolic Symbol name, String code) {
        Command cmd = new Command(name.getName(), code);
        evaluator.putGlobalSymbol(name, cmd);
    }

    @Element(evaluateArgs = false)
    public void state(Symbol name, Block blk) throws Exception {
        currentState = (State) evaluator.getSymbol(name);
        evaluator.eval(blk);
        if (startState == null)
            startState = currentState;
        currentState = null;
    }

    @Element
    public void actions(List<Command> args) throws Exception {
        if (currentState == null)
            throw new Exception("Actions must by defined inside state.");
        for (Command cmd : args) {
            currentState.addAction(cmd);
        }
    }

    @Element(name = "->")
    public void transition(Event trigger, State target) {
        currentState.addTransition(trigger, target);
    }

    // End of DSL functions ==================================================

    public StateMachine getStateMachine() {
        StateMachine machine = new StateMachine(startState);
        machine.addResetEvents(resetEvents);
        return machine;
    }
}

@@ -33,54 +33,8 @@
 e;%0A%0A
-import java.util.List;%0Aimport java.util.Map;%0A%0A
 impo
@@ -96,45 +96,8 @@
 ck;%0A
-import xhl.core.elements.Expression;%0A
 impo
@@ -195,16 +195,62 @@
 dator;%0A%0A
+import java.util.List;%0Aimport java.util.Map;%0A%0A
 /**%0A * X
@@ -971,38 +971,16 @@
 @Element
-(evaluateArgs = false)
 %0A    pub
@@ -995,16 +995,26 @@
  events(
+@Symbolic 
 Block bl
@@ -1015,33 +1015,16 @@
 ock blk)
- throws Exception
  %7B%0A     
@@ -1318,9 +1318,21 @@
 ent%5B
-0
+events.size()
 %5D);%0A
@@ -1350,38 +1350,16 @@
 @Element
-(evaluateArgs = false)
 %0A    pub
@@ -1376,16 +1376,26 @@
 ommands(
+@Symbolic 
 Block bl
@@ -1396,33 +1396,16 @@
 ock blk)
- throws Exception
  %7B%0A     
@@ -1597,33 +1597,35 @@
   @Element(local
-=
+ = 
 true)%0A    public
@@ -1807,17 +1807,19 @@
 nt(local
-=
+ = 
 true)%0A  
@@ -2009,30 +2009,8 @@
 ment
-(evaluateArgs = false)
 %0A   
@@ -2028,16 +2028,26 @@
 d state(
+@Symbolic 
 Symbol n
@@ -2051,16 +2051,26 @@
 l name, 
+@Symbolic 
 Block bl
@@ -2071,33 +2071,16 @@
 ock blk)
- throws Exception
  %7B%0A     

Clean up StateMachineModule