#ifndef PIDCOMMONS_H
#define PIDCOMMONS_H

#include <macros.h>
#include <types.h>

// Macro to detect RTTI support
#if defined(__cpp_rtti) || defined(__GXX_RTTI)
#define RTTI_SUPPORTED
#endif

// Registers & Coils

#define OR_BIT(A) (A >> 1)
#define OR_WORD(A) (A << 4)

#define OSR_PID_REGISTER_START 0x1000

static bool OSR_STATUS_BIT(unsigned int high, unsigned int low, byte bit)
{
    // shift down all for 16bit platforms only
    if (bit <= 16)
    {
        return (low & (1 << 8));
    }

    return (OR_WORD(high) & (1 << (OR_BIT(bit))));
}

typedef enum E_PID_MBRegister : uint16_t
{
    EPID_REG_CHANNEL = OSR_PID_REGISTER_START,
    EPID_REG_SP = OSR_PID_REGISTER_START + 1,
    EPID_REG_PV = OSR_PID_REGISTER_START + 2,
    EPID_REG_KP = OSR_PID_REGISTER_START + 3,
    EPID_REG_KI = OSR_PID_REGISTER_START + 4,
    EPID_REG_KD = OSR_PID_REGISTER_START + 5,
    EPID_REG_MODE = OSR_PID_REGISTER_START + 6,
    EPID_REG_DIRECTION = OSR_PID_REGISTER_START + 7,
    EPID_REG_PID_STATE = OSR_PID_REGISTER_START + 8
};

typedef enum E_PID_MODES
{
    EPM_MANUAL = 0,
    EPM_AUTOMATIC = 1,
    EPM_DIRECT = 0,
    EPM_REVERSE = 1
} PID_MODES;

typedef enum PID_STATE
{
    E_PS_HEATER_OVERCURRENT = 0,
    E_PS_HEATER_CURRENTHOLD = 1,
    E_PS_AD_CONVERTERERROR = 2,
    E_PS_HS_ALARM = 3,
    E_PS_RSP_INPUTERROR = 4,
    E_PS_INPUTERROR = 6,
    E_PS_POTENTIOMETERINPUTERROR = 7,
    E_PS_CONTROL_OUTPUTOPENOUTPUT = 8,
    E_PS_CONTROL_OUTPUTCLOSEOUTPUT = 9,
    E_PS_HBALARM_CT1 = 10,
    E_PS_HBALARM_CT2 = 11,
    E_PS_ALARM1 = 12,
    E_PS_ALARM2 = 13,
    E_PS_ALARM3 = 14,
    E_PS_PROGRAMEND_OUTPUT = 15,

    // Upper Word
    E_PS_EVENTINPUT1 = 16,
    E_PS_EVENTINPUT2 = 17,
    E_PS_EVENTINPUT3 = 18,
    E_PS_EVENTINPUT4 = 19,
    E_PS_WRITEMODE = 20,
    E_PS_NONVOLATILEMEMORY = 21,
    E_PS_SETUPAREA = 22,
    E_PS_ATEXCECUTE = 23,
    E_PS_RUNSTOP = 24,
    E_PS_COMWRITE = 25,
    E_PS_AUTOMANUALSWITCH = 26,
    E_PS_PROGRAMSTART = 27,
    E_PS_HEATEROVERCURRENT_CT2 = 28,
    E_PS_HEATERCURRENTHOLD_CT2 = 29,
    E_PS_HSALARM_CT2 = 31
} PID_STATE;

typedef enum E_REGISTER_TYPE
{
    ERT_TYPE_INT,
    ERT_TYPE_FLOAT,
    ERT_TYPE_DOUBLE,
    ERT_TYPE_STRING,
    ERT_TYPE_BOOL,
    ERT_TYPE_BYTE,
    ERT_TYPE_WORD,
    ERT_TYPE_DWORD,
    ERT_TYPE_QWORD,
    ERT_TYPE_ARRAY,
    ERT_TYPE_STRUCT,
    ERT_TYPE_NONE
} E_REGISTER_TYPE;

////////////////////////////////////////////////////////////////////////////////
//
//  experimental

/*
    // Function to return the native type of member variables
    template <typename T>
    E_REGISTER_TYPE getNativeType()
    {
        if (typeid(T) == typeid(int))
        {
            return TYPE_INT;
        }
        else if (typeid(T) == typeid(float))
        {
            return TYPE_FLOAT;
        }
        else if (typeid(T) == typeid(double))
        {
            return TYPE_DOUBLE;
        }
        else
        {
            // Handle unsupported type
            // You can throw an exception or return a default value
            // depending on your requirements
            return E_NOT_FOUND;
        }
    }

    */

/**
 * @brief Class containing registers for Omron E5 controller
 */

class OR_E5_SWR
{
public:
    /**
     * @brief PV register
     *
     * Temperature: Use the specified range for each sensor.
     * Analog: Scaling lower limit − 5% FS to Scaling upper limit + 5% FS
     */
    int OR_E5_SWR_PV;

    /**
     * @brief Status register
     *
     * Refer to 5-2 Status for details (see @ref OR_E5_STATUS_1 and @ref OR_E5_STATUS_2)
     */
    int OR_E5_SWR_STATUS;

    /**
     * @brief Internal Set Point register
     *
     * Internal Set Point(see appendix *1) - SP lower limit to SP upper limit
     */
    int OR_E5_SWR_ISP;

    /**
     * @brief Heater Current 1 Value Monitor register
     *
     * Heater Current 1 Value Monitor, 0x00000000 to 0x00000226 (0.0 to 55.0)
     */
    int OR_E5_SWR_HeaterCurrentValue1_Monitor;

    /**
     * @brief MV Monitor Heating register
     *
     * MV Monitor (Heating)
     * Standard: 0xFFFFFFCE to 0x0000041A (−5.0 to 105.0)
     * Heating and cooling: 0x00000000 to 0x0000041A (0.0 to 105.0)
     */
    int OR_E5_SWR_MVMonitorHeating;

    /**
     * @brief MV Monitor Cooling register
     *
     * MV Monitor (Cooling)
     * 0x00000000 to 0x0000041A (0.0 to 105.0)
     */
    int OR_E5_SWR_MVMonitorCooling;

    /**
     * @brief Set Point Limit register
     *
     * Set Point - SP lower limit to SP upper limit
     */
    int OR_E5_SWR_SP_LIMIT;

    /**
     * @brief Alarm 1 register
     *
     * Alarm Value 1
     * 0xFFFFF831 to 0x0000270F (−1999 to 9999)
     */
    int OR_E5_SWR_ALARM_1;

    /**
     * @brief Alarm 1 Upper Limit register
     *
     * Alarm Value - Upper Limit 1
     * 0xFFFFF831 to 0x0000270F (−1999 to 9999)
     */
    int OR_E5_SWR_ALARM_1_UL;

    /**
     * @brief Alarm 1 Lower Limit register
     *
     * Alarm Value - Lower Limit 1
     * 0xFFFFF831 to 0x0000270F (−1999 to 9999)
     */
    int OR_E5_SWR_ALARM_1_LL;

    /**
     * @brief Alarm 2 register
     *
     * Alarm Value 2
     * 0xFFFFF831 to 0x0000270F (−1999 to 9999)
     */
    int OR_E5_SWR_ALARM_2;

    /**
     * @brief Alarm 2 Upper Limit register
     *
     * Alarm Value - Upper Limit 1
     * 0xFFFFF831 to 0x0000270F (−1999 to 9999)
     */
    int OR_E5_SWR_ALARM_2_UL;

    /**
     * @brief Alarm 2 Lower Limit register
     *
     * Alarm Value - Lower Limit 1
     * 0xFFFFF831 to 0x0000270F (−1999 to 9999)
     */
    int OR_E5_SWR_ALARM_2_LL;

    /**
     * @brief PV2 register
     *
     * Temperature: Use the specified range for each sensor.
     * Analog: Scaling lower limit − 5% FS to Scaling upper limit + 5% FS
     */
    int OR_E5_SWR_PV2;

    /**
     * @brief Internal Set Point 2 register
     *
     * Internal Set Point(see appendix *1) - SP lower limit to SP upper limit
     */
    int OR_E5_SWR_ISP2;

    /**
     * @brief Multi SP Number Monitor register
     *
     * Multi SP No. Monitor, 0x00000000 to 0x00000007 (0 to 7)
     */
    int OR_E5_SWR_MSMON;

    /**
     * @brief Status Extended register
     *
     * Status,
     * - Not displayed on the Controller display.
     * - In 2-byte mode, the rightmost 16 bits are read.
     */
    int OR_E5_SWR_STATUSEX;
};

#endif
