/**********************************************************************\
 * Kurzbeschreibung: automat.c
 * Stellt Funktionen zur Realisierung eines Automaten zur Verf�gung,  
 * die �ber die in der automat.h vorgegebene C-Schnittstelle 
 * mit einer grafischen Schnittstelle kommunizieren. 
 *
 * Datum:       Autor:        Grund der Aenderung:
 * 
 *
\**********************************************************************/
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "automat.h"

typedef enum {A=0,B,C,D,E,F,G,H,I} state_t;

typedef struct {

    int       input;

    int       mask;

    state_t   nxtstate;

} fsm_state_t;

typedef struct {

    const fsm_state_t * transitions;

    int                 nrOfTransitions;

    state_t             defaultNxtState;

} fsm_full_state_t;

#define SIZE_OF(a) (sizeof((a))/ sizeof(*(a)))

#define NR_OF_STATES        (I-A + 1)

static state_t s_curstate = A;

static const fsm_state_t s_transitions_A[] = {

    {0x002, ~0x004, B},

    {0x003, ~0x004, C}

};

static const fsm_state_t s_transitions_B[] = {

    {0x002, ~0x004, C},

    {0x003, ~0x004, D}

};

static const fsm_state_t s_transitions_C[] = {

    {0x002, ~0x004, D},

    {0x003, ~0x000, F},

    {0x007, ~0x000, H}

};

static const fsm_state_t s_transitions_D[] = {

    {0x002, ~0x000, F},

    {0x003, ~0x004, E},

    {0x006, ~0x000, H}

};

static const fsm_state_t s_transitions_E[] = {

    {0x006, ~0x000, H},

    {0x002, ~0x004, F},

    {0x003, ~0x004, G}

};

static const fsm_state_t s_transitions_F[] = {

    {0x006, ~0x000, H}

};

static const fsm_state_t s_transitions_G[] = {

    {0x006, ~0x000, I}

};

static const fsm_state_t s_transitions_H[] = {

    {0x000, ~0x000, A}

};

static const fsm_state_t s_transitions_I[] = {

    {0x000, ~0x000, A}

};

static const fsm_full_state_t s_state_table[NR_OF_STATES] = {

    { s_transitions_A, SIZE_OF(s_transitions_A), A },

    { s_transitions_B, SIZE_OF(s_transitions_B), B },

    { s_transitions_C, SIZE_OF(s_transitions_C), C },

    { s_transitions_D, SIZE_OF(s_transitions_D), D },

    { s_transitions_E, SIZE_OF(s_transitions_E), E },

    { s_transitions_F, SIZE_OF(s_transitions_F), F },

    { s_transitions_G, SIZE_OF(s_transitions_G), G },

    { s_transitions_H, SIZE_OF(s_transitions_H), H },

    { s_transitions_I, SIZE_OF(s_transitions_I), I }

};

static const fsm_action_t s_out_table[NR_OF_STATES] = {

    { false, false, false, 0, "Warten" },        // A

    { false, false, false, 1, "1 Euro" },        // B

    { false, false, false, 2, "2 Euro" },        // C

    { false, false, false, 3, "3 Euro" },        // D

    { true,  false, false, 3, "3 Euro + M" },    // E

    { true,  false, false, 4, "4 Euro" },        // F

    { true,  true,  false, 4, "4 Euro + M" },    // G

    { true,  false, true,  4, "Kaffee" },        // H

    { false, false, false, 0, "Kaffee + M" }     // I

};

void automat_reset(void) {

    s_curstate = A;

}

void automat_transition(BOOL becher, BOOL muenze, BOOL muenz_wert) {

    int input = ((becher & 0x1) << 2) | ((muenze & 0x1) << 1) | (muenz_wert & 0x1);

    const fsm_full_state_t *current = &s_state_table[s_curstate];

    for (int i = 0; i < current->nrOfTransitions; ++i) {

        if ((input & ~current->transitions[i].mask) == (current->transitions[i].input & ~current->transitions[i].mask)) {

            s_curstate = current->transitions[i].nxtstate;

            return;

        }

    }

    s_curstate = current->defaultNxtState;

}

fsm_action_t automat_output(void) {

    return s_out_table[s_curstate];

}
