#pragma once

// STL
#include <unordered_map>
#include <string>
#include <memory>
#include <variant>

#include "commondef.h"

// project
#include "ISGManager.h"
#include "BufferedSocket.h"

// SGManager.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CSGManager document

/*************************************************************************************/
class ISGManagerObserver;
class CSGManager : public ISGManager, public IBufferSocketCallBack
{
public:
    // ctor
    CSGManager();
    virtual ~CSGManager();

    // methods
    void        EnableEventForAllMode() override;
    void        DisableEventForAllMode() override; // Note: Event Enable in PRODUCTION Mode
    std::string GetControlState();
    std::string GetLinkState() override;
    bool        IsOnlineRemote() override;
    bool        IsEnableCommunicating() override;
    bool        IsOnlineLocal() override;
    bool        IsSpoolActive() override;
    bool        IsConnectWithSecsGem() override; // check for connection between handler and Ti secs gem
    void        OnReceive(const char* buf, int size) override;
    void        OnDisconnect(int errorCode) override;
    void        ResetReceiveBuffer();

    bool        m_bDataComplete{ false };
    std::string m_RcvBuff;

protected:
    /******************************* To Hanlder info ***********************/
    std::string m_strSecsGemConnection;
    std::string m_sSGMainMode;
    std::string m_sSGLoginUser;
    std::string m_sMachineState;
    bool        m_bIsSecsGemEnabled{ false };
    HWND        m_hHandler{ nullptr };

    /**********************************************************************/
    /**********************************************************************/
    int m_NumberOfDay{ 30 };
    /**********************************************************************/
public:
    /************** Handler Calling Functions *****************************/
    bool ConnectSocketSecsGem(bool bUpdateParameter = true) override; // To make connection with Independent Secs/Gem
    bool DisconnectSocketSecsGem() override;                          // To disconnect Secs/Gem application

    // Secsgem Application Function
    void SetEnableLogFile(bool bEnable = true) override;
    void SetLogLevel(const std::string& level) override;
    void SetNumberOfDaysKeepInMemoryForLogFile(int nDays = 30);
    bool SetSecsGemIpAddressAndPort(ISGManagerObserver* pObserver, int iPort, const std::string& strIpAddress, bool bConnect = false, bool bUpdateParameter = true) override;
    bool StartAndConnectSecsGemApplication(ISGManagerObserver* pObserver); // To Start Secs/Gem application and connect
    bool CloseSecsGemApplication() override;                               // To close secsgem application
    bool StartSecsGemApplication() override;                               // To start Secsgem application

    // SecsGem Status Function
    bool GoOnLine() override;                                        // To switch to SecsGem Online mode
    bool GoOffline() override;                                       // To switch to SecsGem Offline mode
    bool GoRemote() override;                                        // To switch to Online/Remote control state
    bool GoLocal() override;                                         // To switch to Online/Local control state
    bool SecsGemDisableLink() override;                              // To disable SecsGem Link
    bool SecsGemEnableLink() override;                               // To enable Secsgem Link
    bool SetMainMode(const std::string& sMode) override;             // To set Main Mode
    bool SetUserLevel(const std::string& sUserLevel) override;       // To set User level
    bool SetProcessState(const std::string& sProcessState) override; // To set process state
    bool UpdateCurrentParameters();                                  // To send current mainmode, user and process state to secsgem appln

    // Send Event Function
    bool SendEvent(const std::string& strEventName) override; // To send Event,iEventReply:0= No need to Watit Event Reply

    // Update Variable Function
    bool SetVariableValue(const std::string& strVariableName, const std::variant<int, long, double, std::string>& value) override;

    // Alarm Function
    bool SendAlarmOn(UINT iAlarmID, const std::string& sAlarmText) override;  // To send Alarm On
    bool SendAlarmOff(UINT iAlarmID, const std::string& sAlarmText) override; // To send Alarm Off
    bool ClearAllAlarms() override;                                           // To clear all alarms

    // Data Set Function
    bool UploadData(const std::string& strName) override;   // To Upload Data
    bool DownloadData(const std::string& strName) override; // To download data
    bool ResetData() override;                              // To reset data

    // Wafer map Function
    bool DownloadWaferMap(const std::string& sWMapID, int nType = 2, int nFormat = 1, int nFNLoc = 0, int nRotAngle = 0, int nOrgLoc = 0, const std::string& strBinCodeEq = "", const std::string& strNullBinCodeEq = "") override;
    bool UploadWaferMap(const std::string& strName) override;   // To Upload Wafer Map
    bool DownloadStripMap(const std::string& strName) override; // To download strip Map

    bool DisplayTerminalMsgDialog() override;                                           // To display terminal message
    bool AcknowledgeRemoteCommand(const std::string& sRmtCmd, int iReturnVal) override; // To acknowledge remote command

    // Process Program Management(Recipe)
    bool DownloadRecipe(const std::string& strName) override; // To download recipe
    bool UploadRecipe(const std::string& strName) override;   // To Upload recipe
    bool UpdateRecipeList() override;                         // To update recipe list

    // ***************************************************************
    // Verify recipe after download recipe, then send S7F27 for PASS or FAIL
    // strResultData = "PASS": successful load recipe
    // strResultData = "FAIL": Fail to load recipe
    // Note:Do not use this function unless customer request
    // ***************************************************************
    bool SendRecipeVerification(const std::string& strResultData) override; // reply to host

    // ***************************************************************
    // To Add Recipe
    // bRefreshRecipe = true  :Not Send GemPPChangeEvent to host
    // bRefreshRecipe = false :Send GemPPChangeEvent with PPCHANGESTATUS(Created) to host
    // ***************************************************************
    bool AddRecipe(const std::string& strName, bool bRefreshRecipe = false) override;

    // ***************************************************************
    //  After delete Recipe file at C:\\PPDER and D:\\PPDER,
    //  then send GemPPChangeEvent with PPCHANGESTATUS(Deleted) to host.
    // ****************************************************************
    bool DeleteRecipe(const std::string& strName) override; // To delete Recipe

    // ***************************************************************
    // bRefreshRecipe = true  :Delete all recipe at C:\\PPDIR only
    // bRefreshRecipe = false :Delete all recipe at C:\\PPDIR and D:\\PPDIR
    // ***************************************************************
    bool DeleteAllRecipe(bool bRefreshRecipe = false) override;

    // ***************************************************************
    //  Send GemPPChangeEvent with PPCHANGESTATUS(Changed) to host.
    //  After edit recipe, need to call this function to inform to host.
    // ****************************************************************
    bool EditRecipe(const std::string& strName) override;

    // ***************************************************************
    //  Send EPT Module Data to host.
    // ****************************************************************
    bool SendEPTData(int nModuleID, const std::string& strTaskName, int nTaskType, int nEPTState, int nBlockedReson, const std::string& strBlockedReasonText) override;

    void OnReceivedControlState(const std::string& strControlState);                           // This function is called when Control State change is received
    void OnReceivedLinkState(const std::string& strLinkState);                                 // This function is called when Link State change is received
    void OnReceivedSpoolState(const std::string& strSpoolState);                               // This function is called when Spool State change is received
    void OnWaferMapDownloaded(const std::string& strWaferMapDownloaded);                       // This function is called when Wafer Map downloaded
    void OnStripMapDownloaded(const std::string& strStripMapDownloaded);                       // This function is called when Strip Map downloaded
    void OnWaferMapUploaded(const std::string& strWaferMapUploaded);                           // This function is called when Wafer Map Uploaded
    void OnRecipeDownloaded(const std::string& strRecipeDownloaded);                           // This function is called when Recipe is downloaded from Host
    void OnRecipeUploaded(const std::string& strRecipeUploaded);                               // This function is called when Recipe is uploaded.
    void OnRecipeDeleted(const std::string& strRecipeDeleted);                                 // This function is called when Recipe is deleted.
    void OnRecipeAdded(const std::string& strAddedRecipe);                                     // This function is called when Recipe is added
    void OnDatasetUploaded(const std::string& strDatasetUploaded);                             // This function is called when Data Set uploaded
    void OnDatasetDownloaded(const std::string& strDatasetDownloaded);                         // This function is called when Dataset downloaded from Host
    void OnRemoteCommandReceived(const std::string& strRemoteCmdReceived, int nReply = 0);     // This function is called when a Remote command is received
    void OnRecipeUpdateNumberOfRecipe(const std::string& strNumberOfRecipe);                   // This function is called when Number recipe received
    void OnRecipeUpdateNthRecipe(unsigned int iRecipeNumber, const std::string& strNthRecipe); // This function is called to updated Nth Recipe
    void OnRecipeUpdatedList();                                                                // This function is called when updated Recipe List.
    void OnReceivedPendingMessage(const std::string& strPendingReadMsg);                       // This function is called whenever message received
    void OnReceivedE10State(const std::string& strE10State);                                   // This function is called when E10 State change is received

    void OnAllRecipeDeleted(const std::string& strRecipeDeleted);
    void OnRecipeEdited(const std::string& strRecipeEdited);
    void OnECChanged(const std::string& sECID, const std::string& strECData); // Thi function is call when host change ECID value.

    // virtual override
    void SetSecsGemDataFileFolder(const std::string& strSGDataFileFolder) override; // Write secs gem data to this file
    bool SendMsgToSecsGem(const std::string& strStr) override;
    void SetWinHandler(HWND hHandler) override;

    void NotifyHandlerToConnect() override;

protected:
    virtual void NotifyHandler(WPARAM wParam, LPARAM lParam);

private:
    void InitCommandMap();

    /************************** private methods *************************/
    bool static SkipToNextData(char** ppStr);
    std::string GetNextData(char** ppStr);

    // attributes
    const std::vector<std::string> m_vecMachineStates{
        "IDLE",
        "INITIALIZING",
        "INITIALIZED",
        "RUNNING",
        "INIT STOP",
        "INIT ERROR",
        "STOP",
        "JAM",
        "ESTOP",
        "ENGINEERING",
        "SCHEDULE"
    };

    const std::unordered_map<std::string, int> m_vecMainModes{
        { "NOMATERIAL", NOMATERIAL_MODE },
        { "PRODUCTION", PRODUCTION_MODE },
        { "ENGINEERING", ENGINEERING_MODE },
        { "SCHEDULED", SCHEDULED_MODE },
        { "NON-SCHEDULED", NON_SCHEDULED_MODE }
    };

    const std::vector<std::string> m_vecUserLevels{
        "OPERATOR",
        "TECHNICIAN",
        "ENGINEER",
        "SUPER USER"
    };

    using CommandHandler = std::function<void(char*&)>;
    std::unordered_map<std::string, CommandHandler> m_commandMap;

    /************************** private fields **************************/
    int                 m_nSGPort{ 2000 };
    std::string         m_strSGIpAddress;
    ISGManagerObserver* m_pObserver{ nullptr };
    /******************************* To Hanlder Info ***********************/
    int         m_iEnableForAllMode{ 0 };
    std::string m_sControlState;
    std::string m_sLinkState;
    std::string m_sSpoolState;
    std::string m_sWaferMapDownloaded;
    std::string m_sStripMapDownloaded;
    std::string m_sWaferMapUploaded;
    std::string m_sRecipeDownloaded;
    std::string m_sRecipeUploaded;
    std::string m_sRecipeDeleted;
    std::string m_sAddedRecipe;
    std::string m_sDatasetUploaded;
    std::string m_sDatasetDownloaded;
    std::string m_sRemoteCmdReceived;
    std::string m_sNumberOfRecipe;
    std::string m_sNthRecipe;
    std::string m_sE10State;
    std::string m_sGeneralCmdReceived;

    std::string m_sSecsGemDataFile;

    std::unique_ptr<CBufferedSocket> m_pSocketSecsGem;
};
