#include "claserdriver_sp.h"
#include <string>
#include "base.h"
#include "cmotor.h"
#include "cmotordriver.h"
#include "claser.h"
#include "cmserialport.h"
#include "logic_compdef.h"
#include "callsystem.h"
#include "logic_eap.h"
#define MAX_COMMAND_LEN 256
using std::string;
CLaserDriver_SP::CLaserDriver_SP(const QString& name, int32_t id)
    : CLaserDriver_Base(name, id)
{
    m_bConnected = false;
}

int CLaserDriver_SP::SetLDD(int32_t laserid, bool_t bOn)
{
    Q_UNUSED(laserid);
    if (bOn)
    {
        CLaser* pLaser = (CLaser*)FindChannel(LASER);
        Q_ASSERT(pLaser);
        GetLaserTime(LASER);
        int iLaserTime = pLaser->m_Variants.get_VData(Var_Laser_LaserTime_ID)->toInt();
        int iLaserTimeLimit = pLaser->m_Variants.get_VData(Var_Laser_LaserTime_Limit_ID)->toInt();

        if (iLaserTime > iLaserTimeLimit)
        {
            MQT_THROW_CODESTR(ALARM_LASER_USEAGETIMEOUT, QObject::trUtf8("Laser use time :%1 hours "
                              "bigger then limit time :%2 hours")
                              .arg(iLaserTime).arg(iLaserTimeLimit));
        }

        SendCommand("BEI:1", nullptr);
        SendCommand("ON", nullptr);
        _Sys_Instance_.LogInfo(m_sName + " set LDD ON");
    }
    else
    {
        SendCommand("OFF", nullptr);

        //MSleep(3000);
        _Sys_Instance_.LogInfo(m_sName + " set LDD OFF");
    }

    return RTN_SUCCESS1;
}

//设置电流
int CLaserDriver_SP::SetCurrent_Ref(int32_t laserid, double dCurrent)
{
    Q_UNUSED(laserid)
        std::string sCmd = "C:" + std::to_string((long double)dCurrent);
    SendCommand(sCmd.c_str(), nullptr);

    _Sys_Instance_.LogInfo(m_sName + "  set electric current(" + QString::number(dCurrent) + ")");
    return RTN_SUCCESS1;
}

int CLaserDriver_SP::GetCurrent_Cur(int32_t laserid)
{
    if (false == m_bConnected)
    {
        LOG_DEBUG("GetCurrent_Cur Failed Laser not connected");
        return RTN_FAILED1;
    }

    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?C", pResponse);
    try
    {
        double electric = 0;
        electric = stod(string(pResponse));

        CLaser* pLaser = (CLaser*)FindChannel(laserid);
        Q_ASSERT(pLaser);
        pLaser->m_Variants.get_VData(Var_Laser_Current_Cur_ID)->setValue(electric);
        m_dDiode = electric;
        return RTN_SUCCESS1;
    }
    catch (...)
    {
        return RTN_FAILED1;
    }

    return RTN_SUCCESS1;
}

void CLaserDriver_SP::do_msg(int iID, QVariantList& vlInput, V_MsgOutput* pvlOutput)
{
    int32_t isize = vlInput.size();
    if (iID == SETEPULSEFREQ)
    {
        if (isize >= 2)
        {
            if (RTN_FAILED1 == SetEpulseFreq(vlInput[0].toInt(), vlInput[1].toInt()))
            {
                MQT_THROW_CODESTR(ALARM_LASER_COMMUNICATION, QObject::trUtf8("Set laser epulse parameter failed"));
            }
        }
    }
    else if (iID == GETEPULSEFREQ)
    {
        if (isize > 0)
        {
            int epulseFreq = 0;
            if (RTN_SUCCESS1 == GetEpulseFreq(vlInput[0].toInt(), epulseFreq))
            {
                m_iEpulseFreq = epulseFreq;
            }
            else
            {
                m_iEpulseFreq = 0;
            }
        }
    }
    else if (iID == GETSTATE)
    {
        GetState();
    }
    else if (iID == GETINNERPOWER)
    {
        GetInnerPower();
    }
    else if (iID == SETINNERGATE)
    {
        SetInnerGate(vlInput[0].toInt(), vlInput[1].toBool());
    }
    else if (iID == INITINISHED)
    {
        _Sys_Instance_.m_SysMsg.SetMsg(QObject::tr("Init Laser finished"));
        return;
    }

    CLaserDriver_Base::do_msg(iID, vlInput, pvlOutput);
}

int CLaserDriver_SP::GetDiodTemp(int32_t laserid)
{
    if (false == m_bConnected)
    {
        LOG_ERR("GetDiodTemp Failed Laser not connected");
        return RTN_FAILED1;
    }

    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?T", pResponse);
    try
    {
        double temp = 0;
        temp = stod(string(pResponse));

        CLaser* pLaser = (CLaser*)FindChannel(laserid);
        Q_ASSERT(pLaser);
        pLaser->m_Variants.get_VData(Var_Laser_Diodtemp_ID)->setValue(temp);
        m_dTemperature = temp;
        return RTN_SUCCESS1;
    }
    catch (...)
    {
        return RTN_FAILED1;
    }
}

int CLaserDriver_SP::GetInnerPower()
{
    if (false == m_bConnected)
    {
        LOG_ERR("GetInnerPower Failed Laser not connected");
        return RTN_FAILED1;
    }

    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?P", pResponse);
    try
    {
        double temp = 0;
        temp = stod(string(pResponse));

        m_dInnerPower = temp;
        return RTN_SUCCESS1;
    }
    catch (...)
    {
        return RTN_FAILED1;
    }
}

int CLaserDriver_SP::GetLaserTime(int32_t laserid)
{
    double dAllThgTime;
    if (true == ReadAllThgTime(dAllThgTime))
    {
        SetLaserTime(laserid, (int)dAllThgTime);
    }

    return RTN_SUCCESS1;
}

int32_t CLaserDriver_SP::init_driver()
{
    m_pSerialPort->open();
    CLaser* pLaser = (CLaser*)FindChannel(LASER);
    Q_ASSERT(pLaser);
    //关电流不能同时马上打开
    //SetLDD(LASER, FALSE);
    OpenLaserGate(LASER, FALSE);
    SetGateSource(LASER, TRUE);
    SetInnerGate(LASER, true);

    bool_t bOn = pLaser->m_Variants.get_VData(Var_Laser_shutter_ID)->toBool();
    if (bOn)
    {
        //在预热状态不能设置电流频率
        SetLDD(LASER, TRUE);
    }

    //检查预热
    //QTime time;
    //time.start();
    //int iWarmTime=m_Variants.get_VData(Var_LaserDriver_WarmTime_ID)->toInt();
    ////while (byFault==2)
    ////{
    ////	if(time.elapsed()>iWarmTime*1000)
    ////	{
    ////		MQT_THROW_STR(QObject::trUtf8("Laser Warm Time out"));
    ////	}
    ////	GetBroadFault( LASER,  byFault );
    ////}
    //CPreciseTime timeCost;
    //timeCost.StartTime();
    //int32_t iTimeCount=0;
    ////GetShutterStatus( LASER);
    ////bool_t bOn=pLaser->m_Variants.get_VData(Var_Laser_shutter_ID)->toBool();
    //float64_t dCurrentThres=pLaser->m_Variants.get_VData(Var_Laser_Current_Thres_ID)->toDouble();
    //int32_t iCurrenttime=m_Variants.get_VData(Var_LaserDriver_CurrentLoadTime_ID)->toDouble();
    //////先开shutter
    //////再开ldd
    ////if(!bOn)
    ////{
    ////	SetLDD(LASER,FALSE);
    ////	do
    ////	{
    ////		GetCurrent_Cur(LASER);
    ////		double dCurrent=pLaser->m_Variants.get_VData(Var_Laser_Current_Cur_ID)->toDouble();
    ////		if (dCurrent<dCurrentThres)
    ////		{
    ////			break;
    ////		}
    ////		iTimeCount=timeCost.GetTime()*1000;
    ////	} while (iTimeCount<iCurrenttime||iCurrenttime==0);
    ////	if (iTimeCount>=iCurrenttime)
    ////	{
    ////		MQT_THROW_STR(QObject::trUtf8("Set Current TimeOut"));
    ////	}
    ////	iTimeCount=0;
    ////	SetShutter(LASER,TRUE);

    ////}
    //GetCurrent_Ref(LASER);
    //double dCurrentRef=pLaser->m_Variants.get_VData(Var_Laser_Current_Ref_ID)->toDouble();
    //SetLDD(LASER,TRUE);
    //timeCost.StartTime();
    //do
    //{
    //	GetCurrent_Cur(LASER);
    //	double dCurrent=pLaser->m_Variants.get_VData(Var_Laser_Current_Cur_ID)->toDouble();
    //	m_gSystem.m_SysMsg.SetMsg(QObject::trUtf8("Laser current on:%1(A)/%2(A)...")
    //		.arg(dCurrent,0,'f',3)
    //		.arg(dCurrentRef,0,'f',3));
    //	if ( fabs(dCurrentRef-dCurrent)<dCurrentThres||dCurrent>dCurrentRef)
    //	{
    //		break;
    //	}
    //	iTimeCount=timeCost.GetTime()*1000;

    //} while (iTimeCount<iCurrenttime||iCurrenttime==0);
    ////if (iTimeCount>iCurrenttime)
    ////{
    ////	MQT_THROW_STR(QObject::trUtf8("Set Current TimeOut"));
    ////}
    //////设置激光器就打开了
    //////设置内触发模式
    //
    ////SetPowerRate(LASER,99);

    ////GetPowerRate(LASER);
    ////GetFreq(LASER);
    ////GetSerial(LASER);

    ////dword_t dwFPKTime=
    ////	pLaser->m_Variants.get_VData(Var_Laser_FPKTime_ID)->toInt();
    //////    SetFPKTime(LASER,dwFPKTime,true);
    ////GetFPKTime(LASER);
    return CDriverCard::init_driver();
}

int32_t CLaserDriver_SP::exit_driver()
{
    if (m_bCloseLaser)
    {
        SetLDD(LASER, FALSE);
    }
    m_pSerialPort->close();
    return CLaserDriver_Base::exit_driver();
}

void CLaserDriver_SP::SendCommand(const char* pCommand, char* pResponse)
{
    QMutexLocker locker(&m_CardMutex);
    int isize = strlen(pCommand);

    char sendBuff[MAX_COMMAND_LEN] = { 0 };
    PacketCommand(pCommand, isize, sendBuff);

    isize = strlen(sendBuff);
    //MqDebug()<<"Send Laser Command"<<sendBuff;
    try
    {
        m_pSerialPort->send(sendBuff, isize);
    }
    catch (const QString& ex)
    {
        MQT_THROW_CODESTR(ALARM_LASER_COMMUNICATION, ex);
    }
    if (nullptr != pResponse)
    {
        try
        {
            int irtn = m_pSerialPort->wait();
            m_pSerialPort->receive(pResponse, irtn);
        }
        catch (const QString& ex)
        {
            MQT_THROW_CODESTR(ALARM_LASER_COMMUNICATION, (m_sName + " " + ex));
        }
        //MqDebug()<<"Recive Laser Command"<<pResponse;
        if (false == CheckResponse(pResponse))
        {
            MQT_THROW_CODESTR(ALARM_LASER_COMMUNICATION, QObject::trUtf8("Send command response error. Driver:%1 Command:%2 Response:%3")
                              .arg(m_sName).arg(pCommand).arg(pResponse));
        }
    }
}

void CLaserDriver_SP::PacketCommand(const char* pCommand, int& srcSize, char* pPacketCommand)
{
    char* send = pPacketCommand;
    Q_ASSERT(strlen(pCommand) == srcSize);

    strcpy(send, pCommand);
    strcpy(send + srcSize, "\r");
}

int CLaserDriver_SP::SetFreq(int32_t laserid, float64_t dFreq)
{
    CLaser* pLaser = (CLaser*)FindChannel(laserid);
    Q_ASSERT(pLaser);
    Q_ASSERT(dFreq > 0);
    unsigned long long lFreq = int(dFreq * 1000);
    std::string sCmd = "Q:" + std::to_string(lFreq);

	for (int i = 0; i < 3; i++) {
		if (RTN_SUCCESS1 == GetFreq(laserid)) {
			break;
		}
	}
	float64_t dwFreq = pLaser->m_Variants.get_VData(Var_Laser_Freq_ID)->toDouble();
	if ((int)dFreq == (int)dwFreq) {
		_Sys_Instance_.LogInfo(m_sName + "Ignore set freq:" + QString::number(lFreq) + " Khz");
		return RTN_SUCCESS1;
	}

    SendCommand(sCmd.c_str(), nullptr);

    //读取重试3次
    for (int i = 0; i < 3; i++) {
        if (RTN_SUCCESS1 == GetFreq(laserid)) {
            break;
        }
    }

    dwFreq = pLaser->m_Variants.get_VData(Var_Laser_Freq_ID)->toDouble();

    _Sys_Instance_.LogInfo(m_sName + " set freq:" + QString::number(lFreq) + " Khz");
    if ((int)dFreq != (int)dwFreq) {
        _Sys_Instance_.LogError(ErrCodeStr(ALARM_LASER_COMMUNICATION) + m_sName + " set freq failed freq:" + QString::number(lFreq) + " Khz");
        return RTN_FAILED1;
    }

    return RTN_SUCCESS1;
}

int CLaserDriver_SP::GetFreq(int32_t laserid)
{
    if (false == m_bConnected)
    {
        LOG_ERR("GetFreq Failed Laser not connected");
        return RTN_FAILED1;
    }

    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?Q", pResponse);
    try
    {
        int frequency = stoi(string(pResponse));

        CLaser* pLaser = (CLaser*)FindChannel(laserid);
        Q_ASSERT(pLaser);

        float64_t dFreq = frequency / 1000.0;
        pLaser->m_Variants.get_VData(Var_Laser_Freq_ID)->setValue(dFreq);
    }
    catch (...)
    {
        return RTN_FAILED1;
    }


    return RTN_SUCCESS1;
}

int CLaserDriver_SP::OpenLaserGate(int32_t laserid, bool bOpen)
{
#if 0
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);

    if (bOpen)
    {
        LOG_INFO(fmt::format("{} {}", m_sName.toStdString(), " open laser shutter"));
    }
    else
    {
        LOG_INFO(fmt::format("{} {}", m_sName.toStdString(), " close laser shutter"));
    }

    if (bOpen)
    {
        if (_SysExt_Instance.m_bEnbaleLaserOpen)
        {
            CLaser* pLaser = (CLaser*)FindChannel(LASER);
            Q_ASSERT(pLaser);
            GetLaserTime(LASER);
            int iLaserTime = pLaser->m_Variants.get_VData(Var_Laser_LaserTime_ID)->toInt();
            int iLaserTimeLimit = pLaser->m_Variants.get_VData(Var_Laser_LaserTime_Limit_ID)->toInt();

            if (iLaserTime > iLaserTimeLimit)
            {
                MQT_THROW_CODESTR(ALARM_LASER_USEAGETIMEOUT, QObject::trUtf8("Laser use time :%1 hours "
                                  "bigger then limit time :%2 hours")
                                  .arg(iLaserTime).arg(iLaserTimeLimit));
            }

            CLaserDriver_Base::OpenLaserGate(laserid, bOpen);
        }
        else
        {
            LOG_INFO(fmt::format("{} {}", m_sName.toStdString(), "open laser shutter (disable laser)"));
        }
    }
    else
    {
        CLaserDriver_Base::OpenLaserGate(laserid, bOpen);
    }
#endif

    CLaserDriver_Base::OpenLaserGate(laserid, bOpen);
    return RTN_SUCCESS1;
}

int CLaserDriver_SP::SetPowerRate(int32_t laserid, float64_t dpower)
{
    Q_UNUSED(dpower)
        CLaser* pLaser = (CLaser*)FindChannel(laserid);
    Q_ASSERT(pLaser);
    double dwPowerRate = 100;
    pLaser->m_Variants.get_VData(Var_Laser_Power_ID)->setValue(dwPowerRate);
    return RTN_SUCCESS1;
}

int CLaserDriver_SP::GetPowerRate(int32_t laserid)
{
    SetPowerRate(laserid, 100);
    return RTN_SUCCESS1;
}

int CLaserDriver_SP::SetGateSource(int32_t laserid, bool_t bExt)
{
    Q_UNUSED(laserid)
        string sCmd = "GEXT:1";
    if (false == bExt)
    {
        sCmd = "GEXT:0";
    }

    SendCommand(sCmd.c_str(), nullptr);

    return RTN_SUCCESS1;
}


int CLaserDriver_SP::SetInnerGate(int laserId, bool bOpen)
{
    Q_UNUSED(laserId);
    string sReturn;
    string sCmd = "G:1";
    if (!bOpen)
    {
        sCmd = "G:0";
    }

    LOG_INFO(fmt::format("{} {} {} {}", "Set Laser Gate:", sCmd.c_str(), " Open:", bOpen));
    SendCommand(sCmd.c_str(), nullptr);

    return RTN_SUCCESS1;
}

int CLaserDriver_SP::SetEpulseFreq(int32_t laserid, int frequency)
{
    Q_UNUSED(laserid);
    //CLaser* pLaser=(CLaser*)FindChannel(laserid);
    //Q_ASSERT(pLaser);
    //Q_ASSERT(frequency > 0 && "set epulse failed frequency < 0");
    if (frequency <= 0)
    {
        MQT_THROW_CODESTR(ALARM_LASER_COMMUNICATION, QObject::tr("set epulse failed frequency < 0"));
    }
    unsigned long long dwFreq = frequency;
    std::string sCmd = "EPRF:" + std::to_string(dwFreq);

	int epluse = 0;
	for (int i = 0; i < 3; i++) {
		if (RTN_SUCCESS1 == GetEpulseFreq(laserid, epluse)) {
			break;
		}
	}

	if (epluse == dwFreq) {
		_Sys_Instance_.LogInfo(m_sName + "Ignore set epulse " + QString::number(dwFreq) + " Hz");
		return RTN_SUCCESS1;
	}

    SendCommand(sCmd.c_str(), nullptr);

	epluse = 0;
    for (int i = 0; i < 3; i++) {
        if (RTN_SUCCESS1 == GetEpulseFreq(laserid, epluse)) {
            break;
        }
    }

    _Sys_Instance_.LogInfo(m_sName + " set epulse " + QString::number(dwFreq) + " Hz");
    //LOG(INFO)<<(m_sName + " set epulse " + QString::number(dwFreq) + " Hz").toStdString().c_str();
    if (epluse != dwFreq)
    {
        _Sys_Instance_.LogError(ErrCodeStr(ALARM_LASER_COMMUNICATION) + m_sName + " set epulse " + QString::number(dwFreq) + " Hz");
        return RTN_FAILED1;
    }

    return RTN_SUCCESS1;
}

int CLaserDriver_SP::GetEpulseFreq(int32_t laserid, int& eprf)
{
    if (false == m_bConnected)
    {
        LOG_ERR("GetEpulseFreq Failed Laser not connected");
        return RTN_FAILED1;
    }

    Q_UNUSED(laserid);
    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?EPRF", pResponse);
    try
    {
        eprf = stoi(string(pResponse));

        /*CLaser* pLaser=(CLaser*)FindChannel(laserid);
        Q_ASSERT(pLaser);

        float64_t dFreq=frequency/1000.0;
        pLaser->m_Variants.set_VData(Var_Laser_Freq_ID,dFreq);*/
    }
    catch (...)
    {
        return RTN_FAILED1;
    }

    return RTN_SUCCESS1;
}

int CLaserDriver_SP::GetState()
{
    char pResponse[RESPONSELENGTH] = { 0 };
    int state = 0;
    std::string sReturn;
    try
    {
        SendCommand("*STB?", pResponse);
    }
    catch (...)
    {
        m_bEmissionOn = false;
        m_bError = true;
        LOG_ERR((QString("%2 ReadState SendCommand failed %1").arg(sReturn.c_str()).arg(m_sName)).toLocal8Bit().data());
        return RTN_FAILED1;
    }

    try
    {
        sReturn = pResponse;
        state = stoi(sReturn);

        m_bConnected = true;
    }
    catch (...)
    {
        m_bEmissionOn = false;
        m_bError = true;
        LOG_ERR((QString("%2 ReadState to covert to int %1").arg(sReturn.c_str()).arg(m_sName)).toLocal8Bit().data());

        m_bConnected = false;
        return RTN_FAILED1;
    }

    //    bool m_IsEmissionOn; //bit0//开关 Emmition On
    //    bool m_IsPreheat;//bit3 预热中
    //    bool m_IsError;//bit5 错误
    //    bool m_IsGateOn;//bit2 门控
    //    bool m_IsShutterOn; //bit1 光闸

    m_bEmissionOn = IsBitOn(state, 0);
    m_bPreheat = IsBitOn(state, 3);
    m_bError = IsBitOn(state, 5);
    m_bInternalGate = IsBitOn(state, 2);
    m_bExternalGate = IsBitOn(state, 4);
    //shutter = IsBitOn(state, 1);
    //LOG(INFO)<<"Laser State:"<<sReturn.c_str();

    if (m_bPreheat)
    {
        ReadWarmupTime(m_iPreheatTimeSecs);
    }

    //获取晶体使用时间
    ReadThgTime(m_dCurThgUseHours);


    GetLaserTime(LASER);

    return RTN_SUCCESS1;

}

bool CLaserDriver_SP::ReadWarmupTime(int& timeSeconds)
{
    if (false == m_bConnected)
    {
        LOG_ERR("ReadWarmupTime Failed Laser not connected");
        return false;
    }

    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?WARMUPTIME", pResponse);

    try
    {
        std::string sRet = pResponse;
        timeSeconds = stoi(sRet);
        return true;
    }
    catch (...)
    {
        LOG_ERR(fmt::format("ReadWarmupTime {} {}", pResponse, " to int failed"));
        return false;
    }
}

bool CLaserDriver_SP::ReadThgTime(double& dCurThgUserHours)
{
    //当前晶体小时数
    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?MTR:THR", pResponse);

    try
    {
        std::string sRet = pResponse;
        dCurThgUserHours = stod(sRet);

        return true;
    }
    catch (...)
    {
        LOG_ERR(fmt::format("GetThgTime {} {}", pResponse, " to int failed"));
        return false;
    }
}

bool CLaserDriver_SP::ReadAllThgTime(double& dAllThgUseHousrs)
{
    //当前晶体小时数
    char pResponse[RESPONSELENGTH] = { 0 };
    SendCommand("?MTR:TALLHRS", pResponse);

    try
    {
        std::string sRet = pResponse;

        QString sInfo = sRet.c_str();

        double dUseHours = 0;
        QStringList tempList = sInfo.split(",");
        for (int i = 0; i < tempList.count(); i++)
        {
            dUseHours += tempList[i].toDouble();
        }

        dAllThgUseHousrs = dUseHours;

        return true;
    }
    catch (...)
    {
        LOG_ERR(fmt::format("GetThgTime {} {} ", pResponse, " to int failed"));
        return false;
    }
}

bool CLaserDriver_SP::CheckResponse(char* pResponse)
{
    int buffLen = strlen(pResponse);
    Q_ASSERT(buffLen > 0);
    if ((byte)pResponse[buffLen - 1] != '\n')
    {
        return false;
    }
    else
    {
        pResponse[buffLen - 1] = 0;
        return true;
    }
}
