//! [main]
#include "pip.h"

enum Mode {Start, Manual, Auto, Finish, End};

class Machine: public PIStateMachine<Mode> {
	PIOBJECT_SUBCLASS(Machine, PIObject)
public:
	Machine() {
		addState(Start, "start", HANDLER(startFunc));
		addState(Manual, "manual", HANDLER(manualFunc));
		addState(Auto, "auto", HANDLER(autoFunc));
		addState(Finish, "finish", HANDLER(finishFunc));
		addState(End, "end", HANDLER(endFunc));
		
		addRule(Start, Manual, "init_ok", HANDLER(beginManualFunc));
		addRule(Start, Auto, "init_ok", HANDLER(beginAutoFunc));
		addRule(Manual, Auto, HANDLER(manualToAutoFunc));
		addRule(Auto, Manual, HANDLER(autoToManualFunc));
		addRule(Manual, Finish);
		addRule(Auto, Finish);
		Rule r(Finish, End);
		r.addCondition("finish_0_ok");
		r.addCondition("finish_1_ok", 2);
		addRule(r);
		
		setInitialState(Start);
		
		CONNECT2(void, void*, int, &timer, timeout, this, tick);
		timer.start(500);
	}
	virtual void execution(const State & state) {
		piCout << "performed conditions:" << currentConditions();
	}
	virtual void transition(const State & from, const State & to) {
		piCout << "switch from" << from.name << "to" << to.name << "state";
	}
	
	EVENT_HANDLER(void, startFunc) {piCout << "start function";}
	EVENT_HANDLER(void, manualFunc) {piCout << "manual function";}
	EVENT_HANDLER(void, autoFunc) {piCout << "auto function";}
	EVENT_HANDLER(void, finishFunc) {piCout << "finish function";}
	EVENT_HANDLER(void, endFunc) {piCout << "end function";}
	EVENT_HANDLER(void, beginManualFunc) {piCout << "begin manual function";}
	EVENT_HANDLER(void, beginAutoFunc) {piCout << "begin auto function";}
	EVENT_HANDLER(void, autoToManualFunc) {piCout << "switch from auto to manual function";}
	EVENT_HANDLER(void, manualToAutoFunc) {piCout << "switch from manual to auto function";}
	
	PITimer timer;
};

Machine machine;

void key_event(char key, void*) {
	switch (key) {
	case 's': machine.switchToState(Start); break;
	case 'm': machine.switchToState(Manual); break;
	case 'a': machine.switchToState(Auto); break;
	case 'f': machine.switchToState(Finish); break;
	case 'e': machine.switchToState(End); break;
	case '1': machine.performCondition("init_ok"); break;
	case '2': machine.performCondition("finish_0_ok"); break;
	case '3': machine.performCondition("finish_1_ok"); break;
	case 'r': machine.resetConditions(); break;
	case 'R': machine.reset(); break;
	}
}

int main(int argc, char * argv[]) {
	PIKbdListener kbd(key_event);
	kbd.enableExitCapture();
	WAIT_FOR_EXIT
};
//! [main]
