#pragma once

#include <cstdint>
#include <string>
#include "grbl.h"

namespace iosender {


struct Color {
    union {
        float r, g, b, a;
    };
    float values[4];
};

class GrblConstants {
public:

    static const uint8_t CMD_EXIT = 0x03; // ctrl-C
    static const uint8_t CMD_RESET = 0x18; // ctrl-X
    static const uint8_t CMD_STOP = 0x19; // ctrl-Y
    static const uint8_t CMD_STATUS_REPORT = 0x80;
    static const uint8_t CMD_CYCLE_START = 0x81;
    static const uint8_t CMD_FEED_HOLD = 0x82;
    static const uint8_t CMD_GCODE_REPORT = 0x83;
    static const uint8_t CMD_SAFETY_DOOR = 0x84;
    static const uint8_t CMD_JOG_CANCEL = 0x85;
    static const uint8_t CMD_STATUS_REPORT_ALL = 0x87;
    static const uint8_t CMD_OPTIONAL_STOP_TOGGLE = 0x88;
    static const uint8_t CMD_SINGLE_BLOCK_TOGGLE = 0x89;
    static const uint8_t CMD_OVERRIDE_FAN0_TOGGLE = 0x8A;
    static const uint8_t CMD_FEED_OVR_RESET = 0x90;
    static const uint8_t CMD_FEED_OVR_COARSE_PLUS = 0x91;
    static const uint8_t CMD_FEED_OVR_COARSE_MINUS = 0x92;
    static const uint8_t CMD_FEED_OVR_FINE_PLUS = 0x93;
    static const uint8_t CMD_FEED_OVR_FINE_MINUS = 0x94;
    static const uint8_t CMD_RAPID_OVR_RESET = 0x95;
    static const uint8_t CMD_RAPID_OVR_MEDIUM = 0x96;
    static const uint8_t CMD_RAPID_OVR_LOW = 0x97;
    static const uint8_t CMD_SPINDLE_OVR_RESET = 0x99;
    static const uint8_t CMD_SPINDLE_OVR_COARSE_PLUS = 0x9A;
    static const uint8_t CMD_SPINDLE_OVR_COARSE_MINUS = 0x9B;
    static const uint8_t CMD_SPINDLE_OVR_FINE_PLUS = 0x9C;
    static const uint8_t CMD_SPINDLE_OVR_FINE_MINUS = 0x9D;
    static const uint8_t CMD_SPINDLE_OVR_STOP = 0x9E;
    static const uint8_t CMD_COOLANT_FLOOD_OVR_TOGGLE = 0xA0;
    static const uint8_t CMD_COOLANT_MIST_OVR_TOGGLE = 0xA1;
    static const uint8_t CMD_PID_REPORT = 0xA2;
    static const uint8_t CMD_TOOL_ACK = 0xA3;
    static const uint8_t CMD_PROBE_CONNECTED_TOGGLE = 0xA4;

    static const std::string CMD_STATUS_REPORT_LEGACY;
    static const std::string CMD_CYCLE_START_LEGACY;
    static const std::string CMD_FEED_HOLD_LEGACY;
    static const std::string CMD_UNLOCK;
    static const std::string CMD_HOMING;
    static const std::string CMD_CHECK;
    static const std::string CMD_GETSETTINGS;
    static const std::string CMD_GETSETTINGS_ALL;
    static const std::string CMD_GETPARSERSTATE;
    static const std::string CMD_GETINFO;
    static const std::string CMD_GETINFO_EXTENDED;
    static const std::string CMD_GETNGCPARAMETERS;
    static const std::string CMD_GETSTARTUPLINES;
    static const std::string CMD_GETSETTINGSDETAILS;
    static const std::string CMD_GETSETTINGSGROUPS;
    static const std::string CMD_GETALARMCODES;
    static const std::string CMD_GETERRORCODES;
    static const std::string CMD_PROGRAM_DEMARCATION;
    static const std::string CMD_SDCARD_MOUNT;
    static const std::string CMD_SDCARD_DIR;
    static const std::string CMD_SDCARD_DIR_ALL;
    static const std::string CMD_SDCARD_REWIND;
    static const std::string CMD_SDCARD_RUN;
    static const std::string CMD_SDCARD_UNLINK;
    static const std::string CMD_SDCARD_DUMP;
    static const std::string FORMAT_METRIC;
    static const std::string FORMAT_IMPERIAL;
    static const std::string NO_TOOL;
    static const std::string THCSIGNALS; // Keep in sync with THCSignals enum below!!

    static const int X_AXIS = 0;
    static const int Y_AXIS = 1;
    static const int Z_AXIS = 2;
    static const int A_AXIS = 3;
    static const int B_AXIS = 4;
    static const int C_AXIS = 5;
};

enum class CameraMoveMode {
    XAxisFirst = 1,
    YAxisFirst = 2,
    BothAxes = 3
};


enum class GrblStates {
    Unknown = 0,
    Idle,
    Run,
    Tool,
    Hold,
    Home,
    Check,
    Jog,
    Alarm,
    Door,
    Sleep
};

enum class GrblMode {
    Normal = 0,
    Laser,
    Lathe
};

enum class GrblEncoderMode {
    Unknown = 0,
    FeedRate = 1,
    RapidRate = 2,
    SpindleRPM = 3
};

enum class GrblSetting {
    PulseMicroseconds = 0,
    StepperIdleLockTime = 1,
    StepInvertMask = 2,
    DirInvertMask = 3,
    InvertStepperEnable = 4,
    LimitPinsInvertMask = 5,
    InvertProbePin = 6,
    StatusReportMask = 10,
    JunctionDeviation = 11,
    ArcTolerance = 12,
    ReportInches = 13,
    SoftLimitsEnable = 20,
    HardLimitsEnable = 21,
    HomingEnable = 22,
    HomingDirMask = 23,
    HomingFeedRate = 24,
    HomingSeekRate = 25,
    HomingDebounceDelay = 26,
    HomingPulloff = 27,
    G73Retract = 28,
    PulseDelayMicroseconds = 29,
    RpmMax = 30,
    RpmMin = 31,
    Mode = 32, // enum GrblMode
    PWMFreq = 33,
    PWMOffValue = 34,
    PWMMinValue = 35,
    PWMMaxValue = 36,
    TravelResolutionBase = 100,
    MaxFeedRateBase = 110,
    AccelerationBase = 120,
    MaxTravelBase = 130,
    MotorCurrentBase = 140,
};

enum class grblHALSetting {
    PulseMicroseconds = 0,
    StepperIdleLockTime = 1,
    StepInvertMask = 2,
    DirInvertMask = 3,
    InvertStepperEnable = 4,
    LimitPinsInvertMask = 5,
    InvertProbePin = 6,
    StatusReportMask = 10,
    JunctionDeviation = 11,
    ArcTolerance = 12,
    ReportInches = 13,
    ControlInvertMask = 14, // Note: Used for detecting GrblHAL firmware
    CoolantInvertMask = 15,
    SpindleInvertMask = 16,
    ControlPullUpDisableMask = 17,
    LimitPullUpDisableMask = 18,
    ProbePullUpDisable = 19,
    SoftLimitsEnable = 20,
    HardLimitsEnable = 21,
    HomingEnable = 22,
    HomingDirMask = 23,
    HomingFeedRate = 24,
    HomingSeekRate = 25,
    HomingDebounceDelay = 26,
    HomingPulloff = 27,
    G73Retract = 28,
    PulseDelayMicroseconds = 29,
    RpmMax = 30,
    RpmMin = 31,
    Mode = 32, // enum GrblMode
    PWMFreq = 33,
    PWMOffValue = 34,
    PWMMinValue = 35,
    PWMMaxValue = 36,
    StepperDeenergizeMask = 37,
    SpindlePPR = 38,
    EnableLegacyRTCommands = 39,
    SoftLimitJogging = 40,
    HomingLocateCycles = 43,
    HomingCycle_1 = 44,
    HomingCycle_2 = 45,
    HomingCycle_3 = 46,
    HomingCycle_4 = 47,
    HomingCycle_5 = 48,
    HomingCycle_6 = 49,
    JogStepSpeed = 50,
    JogSlowSpeed = 51,
    JogFastSpeed = 52,
    JogStepDistance = 53,
    JogSlowDistance = 54,
    JogFastDistance = 55,
    // Per axis settings
    TravelResolutionBase = 100,
    MaxFeedRateBase = 110,
    AccelerationBase = 120,
    MaxTravelBase = 130,
    MotorCurrentBase = 140,
    MicroStepsBase = 150,
    StallGuardBase = 200,
    // End per axis settings
    ToolChangeMode = 341
};

enum class StreamingState {
    NoFile = 0,
    Idle,
    Send,
    SendMDI,
    Home,
    Halted,
    FeedHold,
    ToolChange,
    Start,
    Stop,
    Paused,
    JobFinished,
    Reset,
    AwaitResetAck,
    Disabled,
    Error
};

enum class HomedState {
    Unknown = 0,
    NotHomed,
    Homed
};

// Keep in sync with GrblInfo.SignalLetters constant below
enum class Signals : int {
    Off = 0,
    LimitX = 1 << 0,
    LimitY = 1 << 1,
    LimitZ = 1 << 2,
    LimitA = 1 << 3,
    LimitB = 1 << 4,
    LimitC = 1 << 5,
    LimitU = 1 << 6,
    LimitV = 1 << 7,
    LimitW = 1 << 8,
    EStop = 1 << 9,
    Probe = 1 << 10,
    Reset = 1 << 11,
    SafetyDoor = 1 << 12,
    Hold = 1 << 13,
    CycleStart = 1 << 14,
    BlockDelete = 1 << 15,
    OptionalStop = 1 << 16,
    ProbeDisconnected = 1 << 17,
    MotorWarning = 1 << 18,
    MotorFault = 1 << 19
};

enum class THCSignals : int {
    Off = 0,
    ArcOk = 1 << 0,
    THCEnabled = 1 << 1,
    THCActive = 1 << 2,
    TorchOn = 1 << 3,
    OhmicProbe = 1 << 4,
    VelocityLock = 1 << 5,
    VoidLock = 1 << 6,
    Down = 1 << 7,
    Up = 1 << 8
};

struct GrblState {
    GrblStates State;
    int Substate;
    int LastAlarm;
    int Error;
    Color color;
    bool MPG;
};


class Grbl {
public:
    static void Reset();
};


}