// GPVisionHS.h: interface for the CGPVisionHS class.
//
//////////////////////////////////////////////////////////////////////

#pragma once

#include <map>
#include <memory>
#include <vector>
#include <bitset>

#include "GPVision.h"
#include "FileLog.h"
#include "VisionMultiUnitResult.h"
#include "ICameraId.h"

#include "KeyValue.h"

#ifdef BUILD_COMMDLL
#define COMMDLL_DLLCLASS __declspec(dllexport)
#else
#define COMMDLL_DLLCLASS __declspec(dllimport)
#endif

constexpr auto MAX_UNIT = 2048;

struct stGPMultiUnitDataResult
{
    std::string strResult;
    double      dResult1;
    double      dResult2;
    double      dResult3;
    double      dResult4;
};

using namespace std;

class COMMDLL_DLLCLASS CGPVisionHS : public CGPVision
{
public:
    //
    enum INFO_TYPE
    {
        INFO_MODELNAME = 1,
        INFO_CURRENT_PACKAGENAME,
        INFO_PACKAGENAME,
        INFO_CURRENT_PACKAGEID,
        INFO_5ME, // reply R - OK, F - Directory not found, B - files or parameters errors
    };

    // New Command for Intel Design
    enum CMD_CODE // For %10x
    {
        CMD_MODULE_ENABLE = 1,
        CMD_SKIP_A_UNIT,
        CMD_SKIP_INSP_MOD,
        CMD_OBJ_ID_MOD,
        CMD_LIVE_MODE,
        CMD_LIGHT_ADJ,
        CMD_LIGHT_INTENSITY,
        CMD_SKIP_COUNT,
        CMD_OBJ_ID_INC_MODE,
        CMD_GRR,
        CMD_SHOW_MODEL,
        CMD_LOAD_IMAGE,
        CMD_SAVE_IMAGE, // 13
        // according to 29Apr19 protocol doc
        CMD_INSPECT_GRR,
        CMD_COMPUTE_GRR,
        CMD_RENAME_REJ_IMAGE,
        CMD_DEL_REJ_IMAGE,
        CMD_READ_PICKUP_ENCODER,
        CMD_SAVE_REJ_IMAGE_FOLDER,
        CMD_RECORD_MEASUREMENT,
        CMD_FORCE_RESULT,
    };

    enum CMD_CODE_STATUS // For %11x
    {
        CMD_MODULE_STATUS = 1,
        CMD_TEACH_STATUS,
    };

    enum GPMODULEID
    {
        MOD_GENERAL                = 0x000000,
        MOD_PACKAGELOCATE          = 0x000001,
        MOD_PIN1INSPECTION         = 0x000002,
        MOD_MARKINSPECTION         = 0x000004,
        MOD_PACKAGEINSPECTION      = 0x000008,
        MOD_2DMATRIXINSPECTION     = 0x000010,
        MOD_BGA2DINSPECTION        = 0x000020,
        MOD_CSPPADINSPECTION       = 0x000040,
        MOD_REFERENCELOCATE        = 0x000080,
        MOD_PATTERNLOCATE          = 0x000100,
        MOD_CALIBRATION            = 0x000200,
        MOD_OCRINSPECTION          = 0x000400,
        MOD_SURFACEINSPECTION      = 0x000800,
        MOD_LEADINSPECTION2DTYPE1  = 0x001000,
        MOD_LEADINSPECTION3D       = 0x020000,
        MOD_MEASUREMENT            = 0x100000,
        MOD_WAFEROCRINSPECTION     = 0x200000,
        MOD_POSTSEALINSPECTION     = 0x400000,
        MOD_WAFERSURFACEINSPECTION = 0x1000000,
        MOD_ADVSURFACEINSPECTION   = 0x2000000,
        MOD_QFNINSPECTION          = 0x10000000,
        MOD_GPI                    = 0x40000000,
    };

    enum RESOLUTION_OPTION
    {
        X_RESOLUTION = 1,
        Y_RESOLUTION,
    };

    enum OCR_PARAM_ID
    {
        OCR_FONT_NAME = 1,
        OCR_MARK_FORMAT,
    };

    enum ADV_SURFACE_ID
    {
        ADV_SURFACE_1 = 1,
        ADV_SURFACE_2,
    };

    enum PATTERN_LOCATION_TYPE
    {
        ADJUST_PATTERN = 1,
        RETRIEVE_PATTERN,
    };

    enum TWO_TYPE_INSPECTION
    {
        DISABLED = 0,
        INDEPENDENT_INSP,
        ONE_TRIGGER_INSP,
    };

    enum SAVE_IMG_TYPE
    {
        SAVE_REJ,
        SAVE_FORCE_PASS,
        SAVE_GOOD,
    };

    CGPVisionHS(std::string strMutexName = _T("gp_vision_mutex"), size_t nMaxStation = MAX_VISION_STATION);
    virtual ~CGPVisionHS() final;

    bool StartPatternLocationInspection(int nStationNo, PATTERN_LOCATION_TYPE eType);

    bool StartPostSealInspection(int nStationNo);
    bool StartOTFInspection(int nStationNo);
    bool StartInTapeInspection(int nStationNo);

    __declspec(deprecated("Use StartInspectPosition() instead")) bool StartInspectTapePosition(int nStationNo, int nReferencePt = 1);
    //
    bool StartInspectPosition(int nStationNo, int nReferencePt = 1);   // Generalise Position Inspection
    bool StartCalibratePosition(int nStationNo, int nReferencePt = 1); // For Position Calibration (XYTheta)
    bool StartOTFCalibratePosition(int nStationNo, int nReferencePt = 1, int nIncrementMode = 1);
    bool WaitStartScanLoopAck(int nStationNo, DWORD dwTimeout);
    bool RequestOTFGetReady(int nStationNo, int nReferencePt = 1, int nIncrementMode = 1, int nTwoTypeInsp = DISABLED);
    bool StartInspect(int nStationNo, int nInspectType = 0, int nEdge = 1, int nTwoTypeInsp = DISABLED);

    __declspec(deprecated("Use StartInspect() instead")) bool StartPnpThetaHomeInspection(int nStationNo);

    bool StartTeach(int nStationNo, int nInspectType, int nEdge = 1);
    bool StartLightVerification(int nStationNo);
    void ReceiveComm(const char* cpcBuffer, int nSize);

    int  WaitInTeachOrCapture(int nStationNo, DWORD dwTimeout); // Monitor Either InTeach or Capture
    bool Get2DMatrixResult(int nStationNo, std::string& str2DMatrixResult);

    bool StartTeachPosition(int nStationNo, int nIndexX, int nIndexY, int nColFOV, int nRowFOV);
    bool StartInspectPosition(int nStationNo, int nIndexX, int nIndexY, int nColFOV, int nRowFOV);
    bool GetMultiUnitResult(int nStationNo, stGPMultiUnitDataResult& st_MultiUnitResult, int nUnitID);
    bool WaitResultReady(int nStationNo, DWORD dwTimeout, bool bMultiUnit = false);
    bool SetFOVOffset(int nStationNo, double dOffsetX = 0.0, double dOffsetY = 0.0);

    __declspec(deprecated("Use SetClusterID() instead")) bool SetFOVPosition(int nStationNo, std::string strStripID, int nDeviceCluster = -1);

    bool SetUnitXYPos(int nStationNo, double dX, double dY);
    bool SetUnitColRow(int nStationNo, int nCol, int nRow);
    bool SetInspectIndex(int nStationNo, int nIndexX, int nIndexY);
    bool SetClusterID(int nStationNo, std::string csClusterID);
    bool SetUnitID(int nStationNo, int nUnitNo, std::string csID);

    // This function is used to set inspection type for OTF inspection before trigger OTF
    bool SetInspectionType(int nStationNo, int nType);

    // Deprecated
    __declspec(deprecated("Use SetClusterID() & SetInspectIndex() instead")) bool SendReelNoPocketNo(int nStationNo, int iReel, int iPocket);

    // Stored Image Handling
    bool SetRejectImageSavingOn(int nStationNo, bool bOn = true);
    bool WaitImageLoadReady(int nStationNo, DWORD dwTimeout);
    bool LoadStoredImage(int nStationNo, std::string csStripID, int nInspectedX = 1, int nInspectedY = 1);
    bool GetImageLoadResult(int nStationNo, std::string& csImageLoadResult);

    // Buffering Mode Command (Similar to OTF command)
    bool RequestStartBufferingGetReady(int nStationNo);
    bool WaitStartBufferingLoopAck(int nStationNo, DWORD dwTimeout = 0);
    bool RequestEndBufferingGetReady(int nStationNo);
    bool WaitEndBufferingLoopAck(int nStationNo, DWORD dwTimeout = 0);
    int  GetNoOfBufferingCapture(int nStationNo);

    // Get GP Info
    std::string GetInfo(int nPackageID, std::string csParameter, DWORD dwTimeout = 0, bool bWaitAck = false);
    bool        WaitInfoReady(DWORD dwTimeout = 0);
    bool        GetInfoResult(std::string& csPackageNameResult);

    std::string GetModelNameInfo(DWORD dwTimeout = 0);
    std::string GetPackageNameInfo(int nPackageID, DWORD dwTimeout = 0);
    int         GetPackageIdInfo(DWORD dwTimeout = 0);
    //
    bool OpenLot(std::string csPackageName, DWORD dwTimeout = 5000);

    // E30 Recipe Management
    bool ReadRecipe(std::string csRecipeName, DWORD dwTimeout = 5000);
    bool WriteRecipe(std::string csRecipeName, DWORD dwTimeout = 5000);

    // 5M+E
    bool Write5mE(DWORD dwTimeout = 5000);
    bool SaveRejectImage(int nStationNo, bool bEnableSave);
    bool SaveGoodImage(int nStationNo, bool bEnableSave);
    //
    void VerifyAndInitVariable();
    void SetDryRunWithoutMaterial(bool bEnable = false);

    bool IsGPVisionMutexFree();

    bool InitParameterFile(bool bWrite);

    // Ported from C330
    bool EnableVisionStation(const std::vector<bool>& vecApp);
    bool UpdateStationStatus(const std::vector<int>& vecEnabledList);

    bool SwitchAppWindow(int nStationNo);
    bool SwitchMultipleAppWindow(bool bEnable = true);
    bool StartStopGrr(int nStationNo, int nUnit, int nCycle, bool bOn);

    bool SetOCRText(int nStationNo, std::string strOCRTextList);

    bool SetOCRParam(int nStationNo, int nParamID, std::string strParamValue);
    bool GetOCRParam(int nStationNo, int nParamID, std::string& strParamValue);

    bool SetModuleEnable(int nStationNo, int nInspectionModule, bool bEnable = true);
    bool IsModuleEnable(int nStationNo, int nInspectionModule, int nSetNo = 1);

    double GetResolution(int nStationNo, bool bXResolution);
    bool   IsSemiT10Enable(int nStationNo);
    bool   IsRefLocateEnable(int nStationNo);

    int  GetInspectionSequence(int nStationNo);
    bool IsDiagLogDataEnable(int nStationNo);
    bool IsDiagResultAlwaysGood(int nStationNo);

    bool RequestSkipInspMod(int nStationNo, int nModuleId, int nSetId, bool bSkip);

    // Revised Base class routine
    bool SendMsg(std::string csMsg, DWORD dwTimeout, bool bWaitAck = false);
    bool SendCommand(std::string csCommand, bool bWaitAck = false, DWORD dwTimeout = 5000);
    bool WaitImageTaken(int nStationNo, DWORD dwTimeout = 0);
    bool Run();
    bool Stop();
    bool DataEnd();
    bool DataStart();
    bool SetLotNumber(std::string csLotNumber);
    bool SetLotSize(long lLotSize);
    bool CloseLot(DWORD dwTimeout = 5000);
    bool OpenLot(int nPackageID, DWORD dwTimeout = 5000);
    bool IsTeachingValid(int nStationNo, int nTypeID);

    // Data Logging
    void SetLogEnable(bool bEnable = true);
    void SetLogFilename(const std::string& csFilename);
    //
    void               InitParameters(int nStationNo, int nNoOfUnitsResult, std::vector<int>& pnGx, std::vector<int>& pnLx, std::vector<int>& pnDataSetType, int nNoOfDataSetType = 1);
    CVisionUnitResult* GetMultiUnitResult(int nStationNo, int nUnitNo, int nCat);
    int                GetTotalUnits(int nStationNo);

    //
    // Save the current reject image to the dedicated folder. Acknowledge R<CR> if OK or F<CR> if error.
    bool SaveCurrentImage(int nStationNo, SAVE_IMG_TYPE eImgType, std::string strUniqueID = _T(""));

    bool ForcePass(int nStationNo, int nUnitID = 1);

    bool CameraLiveCapture(int nStationNo, bool bOn = true, int nType = 1);

    //
    void InitLocalLoopback(std::string strIpAddress);
    void ResetInspectionEvents(int nStationNo);

    // Handler request the last reading of package size from GP
    bool QueryPackageSize(int nStationNo, int ParamID);
    bool WaitPackageSizeReady(int nStationNo, DWORD dwTimeout);
    void GetPackageSize(int nStationNo, CMyPoint& ptResult);
    //
    bool SetCustomInspectionType(int nStationNo, int nType);

    bool SetInspectionInfo(int nStationNo, std::string strID, CPoint ptXY);

    size_t GetMaxStnInUse() { return m_nMaxStnInUse; }
    void   SetMaxStnInUse(size_t nMaxStnInUse) { m_nMaxStnInUse = nMaxStnInUse; }



private:
    void InitPviTokenConfig();
    int  GetPviParamNo(int nDataSetNum, int nTokenPos);
    //

    virtual bool ProcessDollarUnitDataSet(string& strData, CVisionUnitResult* pVisionBuffer, int nDataSetType, bool bAbsPosition = false); // $ protocol

    virtual bool ProcessExclamationUnitDataSet(string& strData, CVisionUnitResult* pVisionBuffer, int nDataSetType); // ! protocol

    virtual bool ProcessAndUnitDataSet(string& strData, CVisionUnitResult* pVisionBuffer, int nDataSetType); // & protocol

    bool DecodeCameraType(const string& strCamera, int& nCameraIndex, int& nDataType);

    bool IsValidStationNo(int nStationNo);

    void   ResetReceiveBuffer();
    string TranslateResCode(const string& strCode);

    void SaveLogData(const std::string& strMsg);

    // Attributes
    // Option
    bool m_bDryRunWithoutMaterial;

    HANDLE m_hInfoReady;
    HANDLE m_hNAck1;
    HANDLE m_hNAck2;

    std::vector<HANDLE> m_hStartScanLoopReady;
    std::vector<HANDLE> m_hImageLoadReady;
    std::vector<HANDLE> m_hMultiUnitResultReady;
    std::vector<HANDLE> m_hStartBufferingReady;
    std::vector<HANDLE> m_hEndBufferingReady;
    std::vector<HANDLE> m_hModuleStatusReady;
    std::vector<HANDLE> m_hResolutionResultReady;
    std::vector<HANDLE> m_hSemiT10ResultReady;
    std::vector<HANDLE> m_hGeneralResultReady;
    std::vector<HANDLE> m_hOcrParamReady;
    std::vector<HANDLE> m_hPackageSizeReady;

    vector<string> m_vec2DMatrixResult;
    vector<string> m_vecImageLoadResult;
    string         m_strInfoResult;
    string         m_strOcrParamValue;

    std::vector<std::vector<stGPMultiUnitDataResult>> m_stMultiUnitResult;
    ////
    // Ported from TH800UV to handle Semi-T10 format
    std::vector<CVisionMultiUnitResult> m_visionMultiUnitResult;

    std::vector<int>    m_nRowFOV;
    std::vector<int>    m_nColFOV;
    std::vector<int>    m_nNoOfBufferingCapture; // For tracking of bufferring capture
    std::vector<double> m_dResolutionData;
    std::vector<int>    m_nInspectSeq;
    std::vector<string> m_strUniqueId; // For tracking of unique Id issue upon inspection
    //
    bitset<MAX_VISION_STATION> m_bsStartBufferingMode;
    bitset<MAX_VISION_STATION> m_bsModuleStatusEnable;
    bitset<MAX_VISION_STATION> m_bsSemiT10Enable;
    bitset<MAX_VISION_STATION> m_bsTeachingValid;
    bitset<MAX_VISION_STATION> m_bsDiagResultAlwaysGood;
    bitset<MAX_VISION_STATION> m_bsDiagLogDataEnable;

    //
    std::map<int, std::map<int, CVisionResult::XYT_PVI_PARAM>> m_mapDataSetConfig;

    size_t m_nMaxStnInUse;
    // Logging
    CCriticalSection m_criticalSectionFileLog;
    CFileLog         m_FileLog;
    bool             m_bLogEnable;

    bool m_bLocalLoopback;
    // E30
    string m_strLoadedPkg;
    string m_strLastError;

    //
    std::unique_ptr<CICameraId> m_camId;
    string                      m_strOneLine;
    string                      m_strDryRunExceptionCode;

    std::vector<CMyPoint> m_ptPackageSize;

protected:
    CKeyValue m_tokenizer;
};
