#line 1 "C:\\Users\\mc007\\Desktop\\osr\\lydia-printhead\\firmware\\tests\\osr-pid\\PID.h"
#ifndef PID_H
#define PID_H

#include <ArduinoLog.h>
#include "config.h"
#include <osr-base.h>
#include <App.h>
#include <Addon.h>
#include <Component.h>
#include "types.h"
#include "PIDCommons.h"

class TC;

class PIDModel_S1 : public Component
{
public:
    
    PIDModel_S1(Component *owner, TC *_tc, double *, double *, double *,
                double, double, double);
    
    E_REGISTER_TYPE getNativeType(E_PID_MBRegister reg)
    {
        switch (reg)
        {
            case EPID_REG_CHANNEL:
            case EPID_REG_SP:
            case EPID_REG_PV:
            case EPID_REG_MODE:
            case EPID_REG_DIRECTION:
            case EPID_REG_PID_STATE:
                return ERT_TYPE_INT;
            case EPID_REG_KP:
            case EPID_REG_KI:
            case EPID_REG_KD:
                return ERT_TYPE_DOUBLE;
            default:
                // Handle invalid register
                // You can throw an exception or return a default value
                // depending on your requirements
                return ERT_TYPE_NONE;
        }
    }

    // Function to map each register to a member function pointer
    typedef void (PIDModel_S1::*MemberFunctionPtr)(uint16_t value);

    void mapRegisterToFunction(E_PID_MBRegister reg, MemberFunctionPtr functionPtr)
    {
        //registerToFunctionMap[reg] = functionPtr;
    }
/*
    void handleRegisterValue(E_PID_MBRegister reg, uint16_t value)
    {
        if (registerToFunctionMap.count(reg) > 0)
        {
            MemberFunctionPtr functionPtr = registerToFunctionMap[reg];
            (this->*functionPtr)(value);
        }
        else
        {
            // Handle unsupported register
            // You can throw an exception or return a default value
            // depending on your requirements
        }
    }
*/
    // ... Define member functions for other registers ...

    // commonly used functions **************************************************************************
    
    PIDModel_S1(Component *owner) : Component("PID", 50, Component::COMPONENT_DEFAULT, owner),
                                    channel(-1),
                                    _SP(200),
                                    _PV(100)
    {
        // setFlag(OBJECT_RUN_FLAGS::E_OF_DEBUG);
    }

    // commonly used functions **************************************************************************
    
    void setMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0)

    bool compute(); // * performs the PID calculation.  it should be
                    //   called every time loop() cycles. ON/OFF and
                    //   calculation frequency can be set using SetMode
                    //   SetSampleTime respectively

    void setOutputLimits(double, double); // clamps the output to a specific range. 0-255 by default, but
                                          // it's likely the user will want to change this depending on
                                          // the application

    // available but not commonly used functions ********************************************************
    void setTunings(double, double,   // * While most users will set the tunings once in the
                    double);          //   constructor, this function gives the user the option
                                      //   of changing tunings during runtime for Adaptive control
    void setControllerDirection(int); // * Sets the Direction, or "Action" of the controller. DIRECT
                                      //   means the output will increase when error is positive. REVERSE
                                      //   means the opposite.  it's very unlikely that this will be needed
                                      //   once it is set in the constructor.
    void setSampleTime(int);          // * sets the frequency, in Milliseconds, with which
                                      //   the PID calculation is performed.  default is 100

    // Display functions ****************************************************************
    double getKp();     // These functions query the pid for interal values.
    double getKi();     //  they were created mainly for the pid front-end,
    double getKd();     // where it's important to know what is actually
    int getMode();      //  inside the PID.
    int getDirection(); //

    int runFoo()
    {
        Log.verboseln("Foo");
        return E_OK;
    }
    int channel;
    int _SP;
    int _PV;
    TC *tc;

    // Component implementation
    short setup();
    void setPIDState(PID_STATE state) { pidState = state; }
    PID_STATE getPIDState() { return pidState; }

    //Modbus implementation
    short setValueFromRegister(E_PID_MBRegister reg, int value);

private:
    double dispKp; // * we'll hold on to the tuning parameters in user-entered
    double dispKi; //   format for display purposes
    double dispKd; //

    double kp; // * (P)roportional Tuning Parameter
    double ki; // * (I)ntegral Tuning Parameter
    double kd; // * (D)erivative Tuning Parameter

    int controllerDirection;

    double *myInput;    // * Pointers to the Input, Output, and Setpoint variables
    double *myOutput;   //   This creates a hard link between the variables and the
    double *mySetpoint; //   PID, freeing the user from having to constantly tell us
                        //   what these values are.  with pointers we'll just know.

    unsigned long lastTime;
    double ITerm, lastInput;

    unsigned long SampleTime;
    double outMin, outMax;
    bool inAuto;

    PID_STATE pidState;
};

/*
class TemperatureController
{
public:
    TemperatureController(int numPIDs)
    {
        pids.reserve(numPIDs);
    }

    void addPID(PID* pid)
    {
        pids.push_back(pid);
    }

    void removePID(PID* pid)
    {
        auto it = std::find(pids.begin(), pids.end(), pid);
        if (it != pids.end())
        {
            pids.erase(it);
        }
    }

    void setMode(int mode)
    {
        for (auto pid : pids)
        {
            pid->setMode(mode);
        }
    }

    void compute()
    {
        for (auto pid : pids)
        {
            pid->compute();
        }
    }

    void setOutputLimits(double min, double max)
    {
        for (auto pid : pids)
        {
            pid->setOutputLimits(min, max);
        }
    }

    // Other methods for managing the PIDs...

private:
    std::vector<PID*> pids;
};
*/

#endif
