#ifndef APP_H
#define APP_H

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

class DirectionSwitch;
class EnclosureSensor;
class VFD;
class MotorIdle;
class MotorTemperature;
class MotorSpeed;
class AutoReverse;
class CartridgeFull;
class _DipSwitch;
class OperationModeSwitch;
class Power;
class HopperLoaded;
class MotorLoad;
class RMotorControl;

class Plunger;
class App : public Addon
{

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

    short lastOpMode;

    short setup();
    short loop();
    short debug();
    short info();
    short ok();

    void loop_service();
    void loop_normal();
    ushort loop_auto_reverse();

    void loop_com();

    void _loop_motor_manual();
    void loop_addons();

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

    // operation mode specific
    void App::debug_mode_loop();

    short shred(short value = 0);

    ushort loopShred();
    void loopShredCancel();

    Vector<Addon *> addons;

    StatusLight statusLightOk;
    StatusLight statusLightError;

    // bridge
    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 shredStart;
    millis_t bootTime;
    Timer<10, millis> timer; // 10 concurrent tasks, using micros as resolution

    short plungerCB(short val);
    short setOverload(short val);
    short overloaded;

    enum SHRED_STATE
    {
        WAITING = 100,
        INIT = 1,
        POWERED = 2,
        STARTED = 3,
        HOMED = 4,
        PLUNGED = 5,
        SHREDDED = 6,
        UNPOWERED = 7,
        DONE = 8,
        CANCELLING = 10,
        JAMMED = 11,
        REVERSING = 12,
        REVERSED = 13,
        STOPPING = 14,
        FORWARDING = 15,
        CANCELLED = 16,
        STUCK = 17,
        PLUNGED_SHREDDING = 18
    };
    short shredState;
    short shredStateLast;
    short shredCancelState;
    short beforeJamming;
    short jamCounter;
    short setShredState(short newState);
    bool isAutoReversing();

    enum APP_STATE
    {
        RESET = 6,
        SHREDDING = 1,
        STANDBY = 2,
        ERROR = 5
    };

    short _state;
    short _error;
    short getLastError(short val = 0)
    {
        return _error;
    }
    short setLastError(short val = 0);
    short setAppState(short newState);
    short getAppState(short val);

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

    millis_t debugTS;
};

#endif