#ifndef APP_H
#define APP_H

#include "config.h"
#include <Vector.h>
#include "types.h"
#include "Addon.h"
#include "common/timer.h"
#include "components/StatusLight.h"

class DirectionSwitch;
class EnclosureSensor;
class VFD;
class MotorIdle;
class MotorTemperature;
class MotorSpeed;
class OperationModeSwitch;
class MotorLoad;
class ProximitySensor;

class App : public Addon
{

public:
    App();
    DirectionSwitch *dirSwitch;
    VFD *vfd;
    OperationModeSwitch *opModeSwitch;
    MotorLoad *mLoad;
    Addon *byId(short id);
    ProximitySensor *plungerHome;    

    short lastOpMode;

    short setup();
    short loop();
    short debug();
    short debugIntern(Stream *stream);
    short info();
    short ok();
    short reset();
    
    ushort loopManual();
    ushort loopPlunge();
    ushort loopHome();
    void loop_addons();

    void setup_addons();
    ushort numByFlag(ushort flag);

    void App::debug_mode_loop();

    short plunge(short value = 0);
    short home(short value = 0);
    short stop(short value = 0);
    
    Vector<Addon *> addons;

    //StatusLight statusLightOk;
    //StatusLight statusLightError;

    short setFlag(ushort addonId, ushort flag);

#ifdef HAS_STATES
    short appState(short nop = 0);
    String state();
#endif

    millis_t loopTS;
    millis_t wait;
    millis_t waitTS;
    millis_t plungeStart;
    millis_t bootTime;
    millis_t lastChangeTS;
    millis_t startBtnTS;
    millis_t startBtn2TS;
    millis_t lastAutoTS;
    
    Timer<1, millis> timer; // 10 concurrent tasks, using micros as resolution

    short setOverload(short val);
    short overloaded;
    short lastDirection;
    short lastAutoDirection;

    enum PLUNGE_STATE
    {
        IDLE = 0,
        PLUNGING = 5,
        HOMING = 5,
        JAMMED = 11,
        AUTO = 12
    };
    
    short plungeState;
    short setPlungeState(short newState);
    enum APP_STATE
    {
        RESET = 6,
        STANDBY = 2,
        ERROR = 5
    };
    short _state;
    short _error;    
    short getLastError(short val = 0);
    short setLastError(short val = 0);    

private:

#ifdef MEARSURE_PERFORMANCE
    millis_t addonLoopTime;
    millis_t bridgeLoopTime;
    millis_t printPerfTS;
#endif

    millis_t debugTS;
};

#define HAS_PLUNGE_DEBUG

#ifdef HAS_PLUNGE_DEBUG
    #define PLUNGE_DEBUG(A) Serial.println(A);
#else
    #define PLUNGE_DEBUG(A)
#endif

#ifdef VFD_SPEED_INPUT
    #define VFD_SET_FREQ(A) this->vfd->speed(A);
#else
    #define VFD_SET_FREQ(A)
#endif

#endif