#pragma once
// STL
#include <array>
#include <map>
#include <vector>

// third party
#include "gclib.h"
#include "gclibo.h"
// ETEL
#ifdef WITH_ETEL
#include "dsa30.h"
#endif

// project
#include "utility.h"
#include "DebugSetting.h"
#include "Hardware.h"

class CMtrProfile;

class CCard
{
public:
    CCard();
    virtual ~CCard();

    int  GetOutputCardInitIndex(int nCardType, int nCardNo);
    int  GetInputCardInitIndex(int nCardType, int nCardNo);
    void SetOutputCardInitIndex(int nCardType, int nCardNo, int nIndexNo);
    void SetInputCardInitIndex(int nCardType, int nCardNo, int nIndexNo);
    long GetOutputStatusSize() const;
    BOOL GetOutputStatus(int nCardType, int nCardNo, int nPoint);
    void SetOutputStatusSize(long lSize);
    // Update the Output Status for read back
    void SetOutputStatus(int nCardType, int nCardNo, int nPoint, BOOL bLogic);

    // set / get Advantech Device Number
    UINT_PTR GetAcmDeviceHandle(int nCardNo);
    void     SetAcmDeviceHandle(int nCardNo, UINT_PTR hDevHandle);
    //
    GCon              GetGalilCardHandle(int nCardType, int nCardNo);
    void              SetGalilCardHandle(int nCardType, int nCardNo, GCon hDMC);
    int               Get7296PortNo(int nPoint);
    BOOL              GetOutputStatus(int nIndex) const;
    std::vector<BOOL> GetOutputStatus();

    // Advantech : to get device number which is need to open the device handle
    ULONG GetAcmDeviceNum(ULONG DevType, ULONG BoardID, ULONG MasterRingNo, ULONG SlaveBoardID);
    //
    void     RegisterAxisHandle(const CMtrProfile& mtrProfile, UINT_PTR hAxis);
    UINT_PTR GetAxisHandle(const CMtrProfile& mtrProfile);

    // Adlink EtherCAT master
    long GetAdlinkECATBoardId();
    void SetAdlinkECATBoardId(long lBoardId);

    bool m_bTraceData{ false };

    bool m_bBenchDebug{ false };
    //
    CDebugSetting m_benchDebugSetting;

protected:
    // for 8134
    static std::array<HANDLE, 32> m_hMotionIntArr;      // each axis has 1 int event
                                                        // for 8164
    static std::array<HANDLE, 32> m_h8164MotionIntArr;  // each axis has 1 int event
                                                        // for Galil Optima series
    static std::array<HANDLE, 32> m_hGalilMotionIntArr; // each axis has 1 int event

    // Advantech EtherCAT - cater up to 64 axis / card   max 16 card
    static std::array<std::array<HANDLE, 64>, 16> m_hAdvantechMotionIntArr; // each axis has 1 int event

    // Advantech Card Handle - cater 16 card
    static std::array<UINT_PTR, 16> m_hAcmDeviceHandle; // each card has 1 handle

    // Adlink ECT
    static long m_lAdlinkECATBoardId; // to store the board ID of Adlink ECAT card;

#ifdef WITH_ETEL
    // ETEL - per axis handle
    static std::array<DSA_DRIVE*, MAX_ETEL_AXIS> m_ETEL_DSA_DRIVE; // cater up to 32 ETEL Axis
#endif

private:
    // track the input cards initialised Index
    // currently this is used for AdLink PCI IO Cards
    // for up to 6 different type of cards with 16 cards in each type per system
    static std::array<std::array<int, MAX_CARD_FOR_EACH_TYPE>, MAX_CARD_TYPE> m_nInputCardIndex;

    // track the output cards initialised Index
    // currently this is used for AdLink PCI IO Cards
    // for up to 6 different type of cards with 16 cards in each type per system
    static std::array<std::array<int, MAX_CARD_FOR_EACH_TYPE>, MAX_CARD_TYPE> m_nOutputCardIndex;

    // tracking of output point status for read back purpose
    // cater for 6 different output cards type
    // 16 cards per type
    // 144 points per card
    //    static bool m_nOutputStatus[MAX_CARD_TYPE][MAX_CARD_FOR_EACH_TYPE][MAX_POINTS_FOR_EACH_CARD];
    // for output tracking
    static std::vector<BOOL> m_bOutputArray;
    //
    // track the Galil cards initialised handle
    // currently this is used for Galil Cards only
    // for up to 5 different type of cards with 5 cards in each type per system
    static std::array<std::array<GCon, 5>, 5> m_hdmcGalil;

    static std::map<unsigned int, UINT_PTR> m_mapAxisHandle;
};
