// MotionController.h: interface for the CMotionController class.
//
//////////////////////////////////////////////////////////////////////
#pragma once

#include <map>

#include "Motor.h"
#include "MotionControllerBase.h"

#ifdef BUILD_IODLL
#define IODLLCLASS __declspec(dllexport)
#else
#define IODLLCLASS __declspec(dllimport)
#endif

class IODLLCLASS CMtrStatus
{
public:
    bool m_bNegLimHit;               // 0
    bool m_bPosLimHit;               // 1
    bool m_bHomed;                   // 2
    bool m_bServoReady;              // 3
    bool m_bServoAlarm;              // 4
    bool m_bInPosition;              // 5
    bool m_bMtrOn;                   // 6
    bool m_bpMtrCurOnOff;            // 7 // array to store motor On/Off States before maintenance mode
    double m_dMtrPos;                // 8
    double m_dPosErr;                // 16
    unsigned short m_usMotionStatus; // 24
    unsigned short m_usStatus;       // 26
    int m_iMtrNo;                    // 28     // motor no wrt the type of card used
    int m_iMtrType;                  // 32     // servo or stepper, with or without encoder feedback
    int m_ipMtrCurPos;               // 36  // array to store motor position before maintenance mode
    char m_cMotorName[104];          // 40~ 144 (original size 4 bytes - but has to end on a 8-byte align address)
};

class IODLLCLASS CMotionController : public CCard
{
public:
    friend UINT MotionThreadFn(LPVOID pParam);

    //  static void SetGalilMotionInt(int nAxisNo);
    BOOL IsInPosition(const CMtrProfile& mtrProfile);
    unsigned short GetMotionIOStatus(const CMtrProfile& mtrProfile);

    CMotionController();
    virtual ~CMotionController();

    BOOL InitController(int iNoOfMtr);

    //  check if negative limit hit
    // BOOL IsNegLimHit(int iMotorNo);
    BOOL IsNegLimHit(const CMtrProfile& mtrProfile);

    //  check if positive limit hit
    // BOOL IsPosLimHit(int iMotorNo);
    BOOL IsPosLimHit(const CMtrProfile& mtrProfile);

    //  check if motor at home position
    // BOOL IsHomed(int iMotorNo);
    BOOL IsHomed(const CMtrProfile& mtrProfile);

    //  check if servo ready
    // BOOL IsServoReady(int iMotorNo);
    BOOL IsServoReady(const CMtrProfile& mtrProfile);

    //  check if servo alarm
    // BOOL IsServoAlarm(int iMotorNo);
    BOOL IsServoAlarm(const CMtrProfile& mtrProfile);

    //  get Motor Pos value
    // double GetMtrPos(int iMotorNo);
    double GetMtrPos(const CMtrProfile& mtrProfile);

    //  get Motion status of motor
    // int GetMotionStatus(int iMotorNo);
    int GetMotionStatus(const CMtrProfile& mtrProfile);

    //  get proportional gain value
    double GetPValue(int iMotorNo);

    //  get Integral gain value
    double GetIValue(int iMotorNo);

    //  get Deriative gain value
    double GetDValue(int iMotorNo);

    //  get position error value
    // double GetPosErr(int iMotorNo);
    double GetPosErr(const CMtrProfile& mtrProfile);

    //  check if Motor type is servo motor
    BOOL IsServoMtrType(const CMtrProfile& mtrProfile);

    //  copy all motor status
    void CopyMtrStatus();

    //  check if motor position changed
    bool IsMtrPosChanged(int iMtrNo, int& iPos);

    //  check if motor On/Off States changed
    bool IsMtrOnOffStateChanged(int iMtrNo, bool& bOnOffState);

    //  check if motor is on
    BOOL IsMtrOn(const CMtrProfile& mtrProfile);

    /*  Return Motor(specify by iMtrNo) on or off state.
        Function Return true = Motor specify by iMtrNo Is On, else return false = Motor is off */
    bool GetMtrOnOffState(int iMtrNo);

    void RegisterMotor(const CMtrProfile& mtrProfile, CMotorBase* pMotor);
    void UnRegisterMotor(const CMtrProfile& mtrProfiler);
    static CMotionController& Instance();
    CMotionControllerBase* GetBaseController(int controllerType);

    void TerminateThread();

    void StartUpdate(bool bStartUpdate);

private:
    /**
     * @brief   all the various motion controller objects indexed by the controller ID.
     */

    std::map<int, CMotionControllerBase*> m_motionControllerBase;

    CMtrPos m_mtrPos;                   // object to keep track of current motor position
    CMtrOnOff m_mtrOnOff;               // object to keep track of current motor On/Off States
    std::vector<int> m_vecMtrCurPos;    // array to store motor position before maintenance mode
    std::vector<bool> m_vecMtrCurOnOff; // array to store motor On/Off States before maintenance mode

    int m_iNoOfMtr{ 0 };                // total no of motor
    int m_nNoOfCardType{ 0 };
    CHardwareIni m_iniHardware;

    bool m_bBenchDebugWithActualHardware;
    static CMotionController* m_pInstance;

    CWinThread* m_pThread{ nullptr };

    CEvt m_evtTerminate;
    CEvt m_evtStartUpdate{ "MOTION CONTROLLER START UPDATE" };
};
