/****************************************************************************
** File name    :  HTIEC61850Thread.cpp
** Description  :  IEC 61850 库API
**              ： 第三方库
** Create date  :  2019.09.01
** Auther by    :  Liuyx
** Version info :  V1.0.01
** Copyrigth By:  xi'an huatek, Inc Co., Ltd
** Update record:
** DATE         AUTHER   DESC
** -------------------------------------------------------------------------
** 2019.09.01   Liuyx    first build
****************************************************************************/
#include "HTGlobal.h"
#include "static_model.h"
static const char *_FILE_ = "HTIEC61850Thread.cpp";

/***************************************************************************
** function name :  thread_cache_proc
** deacription   :  data cache thread
** parameter     :  none
** return code   :  NULL
***************************************************************************/
void *thread_cache_proc(void *arg)   // 同步内存数据线程
{
    vPrtLogMsg(LOG_DEBUG, 0, "thread_cache_proc = %d startup...", GETTID());
    while (g_Running)
    {
        vLoadDeviceCtrlParam();
        vLoadAmpliDeviceThreshold();
        vLoadNoiseDeviceThreshold();
        vLoadCenterDeviceThreshold();
        vLoadICDParameterBind();

        vPrtDeviceCtrlParam();
        vPrtDeviceThresholdConf();
        vPrtICDParameterBind();

        _SLEEP(1000 * 60);
    }
    vPrtLogMsg(LOG_DEBUG, 0, "thread_cache_proc = %d shutdown!", GETTID());
    return NULL;
}

/*******************************************************************************
** Function Name :  thread_iec61850_client_proc
** Description   :  IEC61850 client application process
** Parameter In  :  *argv
**   param name  :  
** Parameter Out :  None
**   param name  :  
** Return Code   :  void *
**        RET_OK :  Successed
**      RET_FAIL :  Failed
** Create by     :  Liuyx
** Create date   :  2020:7:29 20:11
** History modify:  Liuyx
** Copyright (C), 2012-2020, Xi'an Huatek. Co., Ltd.
**-----------------------------------------------------------------------
** Modify by     :  Date            : Context
** Liuyx  :  2020/07/29          : created
********************************************************************************/
void *thread_iec61850_client_proc(void *arg)
{
    ST_IED_CONN_HANDLE stIedConn, *pst = (ST_IED_CONN_HANDLE*)arg;
    memcpy(&stIedConn, pst, sizeof(ST_IED_CONN_HANDLE));
    vPrtLogMsg(LOG_DEBUG, 0, "thread_iec61850_client_proc = %d on IED:[%s:%d] startup...", GETTID(),pst->ied_addr,pst->ied_port);

    while (g_Running && (IED_STATE_CONNECTED == IedConnection_getState(stIedConn.hConnHandle))) 
    {
        //vGetRemoteIEDModelConfig(stIedConn.hConnHandle);  // 从IED获取icd模型
        //vSetFCSEData_CTRL(stIedConn.hConnHandle); // 下设控制参数

        /* read an analog measurement value from server */
        vGetFCMXData_YC(stIedConn.hConnHandle);     // 读取遥测数据-监测值
        //vGetFCMXData_YX(stIedConn.hConnHandle);     // 读取遥信数据-告警位

        //vDownLoadComtradeFiles(stIedConn);  // 下载录播文件
        _SLEEP(1000 * 60);
        vPrtLogMsg(LOG_DEBUG, 0, "Get once monitor data complate...");
    } 
    vPrtLogMsg(LOG_DEBUG, 0, "thread_iec61850_client_proc is shutdown complate...");
    vIedFreeIedEvent(stIedConn);

    return NULL;

    //IedConnection_abort(con, &error);
    //IedConnection_close(con);
    //IedConnection_destroy(con);

    printf("get report completed...\n");
    return NULL;
}


static void IedConnectionClosed(void* parameter, IedConnection connection)
{
    vPrtLogMsg(LOG_WARNG, 0, "Connection is closeed!");
    IedConnection_close(connection);
    IedConnection_destroy(connection);
}

/***************************************************************************
** function name :  thread_iec61850_manager_proc
** deacription   :  link manager thread
** parameter     :  none
** return code   :  NULL
***************************************************************************/
void *thread_iec61850_manager_proc(void *arg)
{
    IedClientError error;
    map<string, ST_IED_CONN_HANDLE>::iterator m_pIter;
    vPrtLogMsg(LOG_DEBUG, 0, "thread_iec61850_manager_proc = %d startup...", GETTID());
    vIedInitIedEvent();
    while (g_Running)
    {
        pthread_testcancels();

        for (m_pIter = g_MapIedConn.begin(); m_pIter != g_MapIedConn.end(); m_pIter++)
        {
            if ((IED_STATE_CONNECTED == IedConnection_getState((*m_pIter).second.hConnHandle))) {
                _SLEEP(500);
                continue;
            }
            else {
                mutex_lock(g_MapIedConn_mutex);
                IedConnection_close((*m_pIter).second.hConnHandle);
                (*m_pIter).second.bIsConnect = false;
                mutex_unlock(g_MapIedConn_mutex);
            }
            mutex_lock(g_MapIedConn_mutex);
            if (!(*m_pIter).second.IedModel) {
                (*m_pIter).second.IedModel = LoadModelConfigFile(g_TConfig.getIEDModelConfigFile());
                if ((*m_pIter).second.IedModel == NULL) {
                    vPrtLogMsg(LOG_ERROR, 0, "Load model config failed,model_file=%s", g_TConfig.getIEDModelConfigFile());
                    mutex_unlock(g_MapIedConn_mutex);
                    return NULL;
                }
                
                vPrtLogMsg(LOG_DEBUG, 0, "Load model config:[%s]...OK", g_TConfig.getIEDModelConfigFile());
            }
            if (!(*m_pIter).second.hConnHandle) {
                (*m_pIter).second.hConnHandle = IedConnection_create();
            }

            // 建立通信链路
            IedConnection_connect((*m_pIter).second.hConnHandle, &error, (*m_pIter).second.ied_addr, (*m_pIter).second.ied_port);
            if (error != IED_ERROR_OK) {
                vPrtLogMsg(LOG_ERROR, error, "Failed to connect to %s:%i, try again later...",
                    (*m_pIter).second.ied_addr, (*m_pIter).second.ied_port);
                if ((*m_pIter).second.bWarn){
                    (*m_pIter).second.iLastAlaarmTime = time(NULL);
                    vSetIedDevicesWarnMesg((*m_pIter).second.ied_addr, (*m_pIter).second.ied_port, (*m_pIter).second.iLastAlaarmTime);                    
                    (*m_pIter).second.bWarn = false;
                }
                mutex_unlock(g_MapIedConn_mutex);
                _SLEEP(500);
                continue;
            }
            vPrtLogMsg(LOG_DEBUG, 0, "Connect to Ied server:%s:%d start...OK", (*m_pIter).second.ied_addr, (*m_pIter).second.ied_port);
            if (!(*m_pIter).second.bWarn) 
                vDelIedDevicesWarnMesg((*m_pIter).second.ied_addr, (*m_pIter).second.ied_port, (*m_pIter).second.iLastAlaarmTime);
            (*m_pIter).second.bWarn = true;
            (*m_pIter).second.bIsConnect = true;
            (*m_pIter).second.iLastTime = time(NULL);
            (*m_pIter).second.iLastActionTime = time(NULL);
            IedConnection_installConnectionClosedHandler((*m_pIter).second.hConnHandle, IedConnectionClosed, NULL);
            mutex_unlock(g_MapIedConn_mutex);

            // 校时

            // 上传配置
            setComtradeFile((*m_pIter).second.hConnHandle, "etc/setting.ini");

            pthread_t thread_handle_minor_recv = -1;
#ifndef _WIN32
            pthread_attr_t attr;
            pthread_attr_init(&attr);
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  // 创建一个分离子线程,接收数据线程
#endif
            ht_pthread_create_background(&thread_handle_minor_recv, thread_iec61850_client_proc, (void*)&(*m_pIter).second);
#ifndef _WIN32
            pthread_detach(thread_handle_minor_recv);
#endif         
        }
        _SLEEP(5000);
    }
    for (m_pIter = g_MapIedConn.begin(); m_pIter != g_MapIedConn.end(); m_pIter++)
        vIedFreeIedEvent((*m_pIter).second);    
    vPrtLogMsg(LOG_DEBUG, errno, "shutdown thread_iec61850_manager_proc...complate");

    return NULL;
}

/***************************************************************************
** function name :  thread_database_proc
** deacription   :  parser thread
** parameter     :  none
** return code   :  NULL
***************************************************************************/
void* thread_database_proc(void * arg)
{
    unsigned char szBuf[MAX_SBUFF_TCP] = { 0 };
    int iRet = -1, recv_buflen = 0, pkgLen = 0;
    ST_DB_BODY stData;

    vPrtLogMsg(LOG_DEBUG, 0, "thread_database_proc = %d startup...", GETTID());
    
    while (g_Running)
    {
        pthread_testcancels();
        memset(&stData, 0x00, sizeof(ST_DB_BODY));
        mutex_lock(g_list_db_body_mutex);
        if (g_list_db_body.empty() || g_list_db_body.size() <= 0) {
            mutex_unlock(g_list_db_body_mutex);
            _SLEEP(MAX_SLEEP_EMPTY * 10);
            continue;
        }
        memcpy(&stData, &(g_list_db_body.back()), sizeof(ST_DB_BODY));  // 由尾取出
        g_list_db_body.pop_back(); // 由尾删除
        mutex_unlock(g_list_db_body_mutex);

        vSetRealDevicesMoniMesg(&stData);
    }
    return NULL;
}

/***************************************************************************
** function name :  thread_dbalarm_proc
** deacription   :  parser thread
** parameter     :  none
** return code   :  NULL
***************************************************************************/
void* thread_dbalarm_proc(void * arg)
{
    unsigned char szBuf[MAX_SBUFF_TCP] = { 0 };
    int iRet = -1, recv_buflen = 0, pkgLen = 0;
    ST_DB_WARN stAlarm;

    vPrtLogMsg(LOG_DEBUG, 0, "thread_dbalarm_proc = %d startup...", GETTID());

    while (g_Running)
    {
        pthread_testcancels();
        memset(&stAlarm, 0x00, sizeof(ST_DB_WARN));
        mutex_lock(g_list_db_warn_mutex);
        if (g_list_db_warn.empty() || g_list_db_warn.size() <= 0) {
            mutex_unlock(g_list_db_warn_mutex);
            _SLEEP(MAX_SLEEP_EMPTY * 10);
            continue;
        }
        memcpy(&stAlarm, &(g_list_db_warn.back()), sizeof(ST_DB_WARN));  // 由尾取出
        g_list_db_warn.pop_back(); // 由尾删除
        mutex_unlock(g_list_db_warn_mutex);

        vSetRealDevicesWarnMesg(stAlarm);
    }
    return NULL;
}
