#include "cproductside.h"
#include "logic_local_def.h"
#include "csystem_external.h"
QDataStream &operator<<(QDataStream &out, const SINGLECUTPARAM &param)
{
    out << param.dCutDepth;
    out << param.dOvercut;
    out << param.dCutSpd;
    out << param.iLaserFreq;
    out << param.dLaserPower;
    out << param.dOffset;
    out << param.laserpathID;
    out << param.dBeamWidth;
    out << param.iCutCount;

    out << param.iKerfStyle;
    out << param.dKerfExpand;
    out << param.iKerfFirst;
    out << param.iKerfFreq;
    out << param.iKerfIndex;
    out << param.dDIndex;

    out << param.dKerfOffset;
    return out;
}

QDataStream &operator >> (QDataStream &in, SINGLECUTPARAM &param)
{
    in >> param.dCutDepth;
    in >> param.dOvercut;
    in >> param.dCutSpd;
    in >> param.iLaserFreq;
    in >> param.dLaserPower;
    in >> param.dOffset;
    in >> param.laserpathID;
    in >> param.dBeamWidth;
    in >> param.iCutCount;

    in >> param.iKerfStyle;
    in >> param.dKerfExpand;
    in >> param.iKerfFirst;
    in >> param.iKerfFreq;
    in >> param.iKerfIndex;
    in >> param.dDIndex;

    in >> param.dKerfOffset;
    return in;
}

QDataStream &operator<<(QDataStream &out, const SUBINDEX &param)
{
    out << param.dSubIndex;
    out << param.iCount;
    out << param.dSolidOffset;
    out << param.dLocationOffset;
    out << param.dSubIndexX;
    out << param.dSolidLine;
    return out;
}

QDataStream &operator >> (QDataStream &in, SUBINDEX &param)
{

    in >> param.dSubIndex;
    in >> param.iCount;
    in >> param.dSolidOffset;
    in >> param.dLocationOffset;
    in >> param.dSubIndexX;
    in >> param.dSolidLine;
    return in;
}

QDataStream &operator<<(QDataStream &out, const MODEL_INFO &param)
{
    out << param.iDirectLight;
    out << param.iSideLight;
    out << param.dMinScore;
    out << param.iContrast;
    out << param.iExposureUs;
    out << param.iGain;
    return out;
}

QDataStream &operator >> (QDataStream &in, MODEL_INFO &param)
{
    in >> param.iDirectLight;
    in >> param.iSideLight;
    in >> param.dMinScore;
    in >> param.iContrast;
    in >> param.iExposureUs;
    in >> param.iGain;
    return in;
}

QDataStream &operator<<(QDataStream &out, const CUTLINE& param)
{
    out << param.m_BasePt.tX;
    out << param.m_BasePt.tY;
    out << param.m_WPPair.ptPostive.tX;
    out << param.m_WPPair.ptPostive.tY;
    out << param.m_WPPair.ptNegative.tX;
    out << param.m_WPPair.ptNegative.tY;
    out << param.m_bHasCut;
    out << param.m_bSUB;
    out << param.m_YOffset;
    out << param.m_index;
    return out;
}
QDataStream &operator >> (QDataStream &in, CUTLINE& param)
{
    in >> param.m_BasePt.tX;
    in >> param.m_BasePt.tY;
    in >> param.m_WPPair.ptPostive.tX;
    in >> param.m_WPPair.ptPostive.tY;
    in >> param.m_WPPair.ptNegative.tX;
    in >> param.m_WPPair.ptNegative.tY;
    in >> param.m_bHasCut;
    in >> param.m_bSUB;
    in >> param.m_YOffset;
    in >> param.m_index;
    return in;
}

CProductSide::CProductSide(const QString &name, int32_t id)
    :CChannel(name, id)
{

    m_Variants.add_Variant(Var_ProductSide_SideStep,
                           QObject::trUtf8("SideStep"), double(10), false,
                           Variant::TOBOTH, QStringList(), "mm");
    m_Variants.add_Variant(Var_ProductSide_CutStreet,
                           QObject::trUtf8("CutStreet"), double(60), false,
                           Variant::TOBOTH, QStringList(), "um");
    m_Variants.add_Variant(Var_ProductSide_StepDotLine,
                           QObject::trUtf8("StepDotLine"), double(0), false,
                           Variant::TOBOTH, QStringList(), "um");
    m_Variants.add_Variant(Var_ProductSide_SolidDotLine,
                           QObject::trUtf8("SolidDotLine"), double(0), false,
                           Variant::TOBOTH, QStringList(), "um");
    m_Variants.add_Variant(Var_ProductSide_InitAngle,
                           QObject::trUtf8("InitAngle"), double(0), false,
                           Variant::TOBOTH, QStringList(), "degree");
    m_Variants.add_Variant(Var_ProductSide_TemplateOffsetX,
                           QObject::trUtf8("TemplateOffsetX"), double(0), false,
                           Variant::TOBOTH, QStringList(), "mm");
    m_Variants.add_Variant(Var_ProductSide_TemplateOffsetY,
                           QObject::trUtf8("TemplateOffsetY"), double(0), false,
                           Variant::TOBOTH, QStringList(), "mm");

    m_bModelChanged = true;
    m_dLevelAngle = 0;
    m_dSolidBasePosX = 0;
}

CProductSide::~CProductSide()
{

}

void CProductSide::Serialize(QDataStream &stream, bool bwrite, int iVersion)
{
    CChannel::Serialize(stream, bwrite, iVersion);
    if (bwrite) {
        //模型
        for (int i = 0; i < 2; i++) {
            stream << lModels[i];
        }
        //子线
        int isize = m_vSubIndex.size();
        stream << isize;
        for (int i = 0; i < isize; i++) {
            stream << m_vSubIndex[i];
        }
        //切割道加工参数，可能多次加工
        isize = m_vCutParam.size();
        stream << isize;
        for (int i = 0; i < isize; i++) {
            stream << m_vCutParam[i];
        }
    } else {
        for (int i = 0; i < 2; i++) {
            stream >> lModels[i];
        }
        int isize;
        stream >> isize;
        m_vSubIndex.resize(isize);
        for (int i = 0; i < isize; i++) {
            stream >> m_vSubIndex[i];
        }
        stream >> isize;
        m_vCutParam.resize(isize);
        for (int i = 0; i < isize; i++) {
            stream >> m_vCutParam[i];
        }
        m_dLevelAngle = m_Variants.get_VData(Var_ProductSide_InitAngle)
            ->toDouble();
    }

}

bool CProductSide::GetCutParam(int iLayerID, SINGLECUTPARAM &param)
{
    QMutexLocker locker(&m_vCutParam.mutex);
    int iSize = m_vCutParam.size();
    if (!OUTOFRANGE(iLayerID, 0, iSize)) {
        param = m_vCutParam[iLayerID];
        return true;
    }
    return false;
}

CUTLINE *CProductSide::GetCutLine(int iLine)
{
    int iSize = m_CutLineVector.size();
    if (OUTOFRANGE(iLine, 0, iSize)) {
        return NULL;
    }
    return &m_CutLineVector[iLine];
}

MODEL_INFO &CProductSide::get_Model_info(int32_t iCamid)
{
    if (iCamid == CAM2X)
        return lModels[0];
    else if (iCamid == CAM6X)
        return lModels[1];

}

void CProductSide::RecordLineData()
{
    QMutexLocker l(&m_CutLineVector.mutex);
    _SysExt_Instance.AddProductInfo(PROCESS_CUT, QString("Cut Line %1").arg(SIDE_A == m_iID ? "CH1" : "CH2"));
    _SysExt_Instance.AddProductInfo(PROCESS_CUT, "\tLine,BaseX,BaseY,StartX,StartY,EndX,EndY", false);
    int i = 1;
    for (auto iter = m_CutLineVector.cbegin(); iter != m_CutLineVector.cend(); iter++) {
        QString info = QString("\t%7,%1,%2,%3,%4,%5,%6")
            .arg((*iter).m_BasePt.tX, 10).arg((*iter).m_BasePt.tY, 10)
            .arg((*iter).m_WPPair.ptPostive.tX, 10).arg((*iter).m_WPPair.ptPostive.tY, 10)
            .arg((*iter).m_WPPair.ptNegative.tX, 10).arg((*iter).m_WPPair.ptNegative.tY, 10)
            .arg(i);

        _SysExt_Instance.AddProductInfo(PROCESS_CUT, info, false);
        i++;
    }

}

bool CProductSide::WriteRecoveredData()
{
    try {

        QString filePath = _SysExt_Instance.MakeRecoverPath(QString("CutParam%1.lpf").arg(m_iID == SIDE_A ? "CH1" : "CH2"));
        QFile file(filePath);
        if (!file.open(QIODevice::WriteOnly)) {
            LOG_ERR(fmt::format("create WriteRecoveredData file failed ", filePath.toLocal8Bit().data()));
            return false;
        }

        QDataStream stream(&file);
        QMutexLocker l(&m_CutLineVector.mutex);
        //记录划线的数据
        int iSize = m_CutLineVector.size();
        stream << iSize;
        for (auto iter = m_CutLineVector.cbegin(); iter != m_CutLineVector.cend(); ++iter) {
            stream << (*iter);
        }

        //切割参数
        QMutexLocker lp(&m_vCutParam.mutex);
        iSize = m_vCutParam.size();
        stream << iSize;
        for (auto iter = m_vCutParam.cbegin(); iter != m_vCutParam.cend(); ++iter) {
            stream << (*iter);
        }
        lp.unlock();
        stream << m_realCenter.tX;
        stream << m_realCenter.tY;
        stream << m_dLevelAngle;
        stream << m_dSolidBasePosX;
        file.close();
    } catch (std::exception ex) {
        LOG_ERR("create WriteRecoveredData failed ");
    }
    _Sys_Instance_.LogInfo("Write Recovered data success");
    return true;
}

bool CProductSide::ReadRecoveredData()
{
    try {
        QString filePath = _SysExt_Instance.MakeRecoverPath(QString("CutParam%1.lpf").arg(m_iID == SIDE_A ? "CH1" : "CH2"));
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly)) {
            LOG_ERR(fmt::format("create ReadRecoveredData file failed {}", filePath.toLocal8Bit().data()));
            return false;
        }

        QDataStream stream(&file);
        int iSize;
        stream >> iSize;
        //记录划线的数据
        m_CutLineVector.resize(iSize);
        QMutexLocker l(&m_CutLineVector.mutex);
        for (int i = 0; i < iSize; i++) {
            stream >> m_CutLineVector[i];
        }

        //切割参数
        stream >> iSize;
        m_vCutParam.resize(iSize);
        QMutexLocker lp(&m_vCutParam.mutex);
        for (int i = 0; i < iSize; i++) {
            stream >> m_vCutParam[i];
        }

        stream >> m_realCenter.tX;
        stream >> m_realCenter.tY;
        stream >> m_dLevelAngle;
        stream >> m_dSolidBasePosX;
        file.close();
    } catch (std::exception ex) {
        LOG_ERR("ReadRecoveredData file exception ");
    }
    _Sys_Instance_.LogInfo("Read Recovered data success");
    return true;
}

void CProductSide::ReadRecipe(ConfigStreamReader& streamReader, int iVersion)
{
    CChannel::ReadRecipe(streamReader, iVersion);
    
    streamReader.readNextStartElement();
    for (int i = 0; i < 2; i++) {
        streamReader >> lModels[i];
    }
    streamReader.skipCurrentElement();

    streamReader.readNextStartElement();
    int isize = streamReader.attributes().value("size").toInt();;
    m_vSubIndex.resize(isize);
    for (int i = 0; i < isize; i++) {
        streamReader >> m_vSubIndex[i];
    }
    streamReader.skipCurrentElement();

    streamReader.readNextStartElement();
    isize = streamReader.attributes().value("size").toInt();;
    m_vCutParam.resize(isize);
    for (int i = 0; i < isize; i++) {
        streamReader >> m_vCutParam[i];
    }
    streamReader.skipCurrentElement();

    m_dLevelAngle = m_Variants.get_VData(Var_ProductSide_InitAngle)
        ->toDouble();
}

void CProductSide::WriteRecipe(ConfigStreamWriter& streamWriter, int iVersion)
{
    CChannel::WriteRecipe(streamWriter, iVersion);

    streamWriter.writeStartElement("models");
    streamWriter.writeAttribute("count", "2");
    //模型
    for (int i = 0; i < 2; i++) {
        streamWriter << lModels[i];
    }
    streamWriter.writeEndElement();

    streamWriter.writeStartElement("subindexs");
    //子线
    int isize = m_vSubIndex.size();
    streamWriter.writeAttribute("size", QString::number(isize));
    for (int i = 0; i < isize; i++) {
        streamWriter << m_vSubIndex[i];
    }
    streamWriter.writeEndElement();


    streamWriter.writeStartElement("params");
    //切割道加工参数，可能多次加工
    isize = m_vCutParam.size();
    streamWriter.writeAttribute("size", QString::number(isize));
    for (int i = 0; i < isize; i++) {
        streamWriter << m_vCutParam[i];
    }
    streamWriter.writeEndElement();
}

ConfigStreamWriter &operator<<(ConfigStreamWriter &out, const MODEL_INFO& param)
{
    out.writeStartElement("model");
    out << param.iDirectLight;
    out << param.iSideLight;
    out << param.dMinScore;
    out << param.iContrast;
    out << param.iExposureUs;
    out << param.iGain;
    out.writeEndElement();
    return out;
}
ConfigStreamReader &operator >> (ConfigStreamReader &in, MODEL_INFO& param)
{
    in.readNextStartElement();
    in >> param.iDirectLight;
    in >> param.iSideLight;
    in >> param.dMinScore;
    in >> param.iContrast;
    in >> param.iExposureUs;
    in >> param.iGain;
    in.skipCurrentElement();
    return in;
}
ConfigStreamWriter &operator<<(ConfigStreamWriter &out, const CUTLINE& param)
{
    out.writeStartElement("cutline");
    out << param.m_BasePt.tX;
    out << param.m_BasePt.tY;
    out << param.m_WPPair.ptPostive.tX;
    out << param.m_WPPair.ptPostive.tY;
    out << param.m_WPPair.ptNegative.tX;
    out << param.m_WPPair.ptNegative.tY;
    out << param.m_bHasCut;
    out << param.m_bSUB;
    out << param.m_YOffset;
    out << param.m_index;
    out.writeEndElement();
    return out;
}
ConfigStreamReader &operator >> (ConfigStreamReader &in, CUTLINE& param) {
    in.readNextStartElement();
    in >> param.m_BasePt.tX;
    in >> param.m_BasePt.tY;
    in >> param.m_WPPair.ptPostive.tX;
    in >> param.m_WPPair.ptPostive.tY;
    in >> param.m_WPPair.ptNegative.tX;
    in >> param.m_WPPair.ptNegative.tY;
    in >> param.m_bHasCut;
    in >> param.m_bSUB;
    in >> param.m_YOffset;
    in >> param.m_index;
    in.skipCurrentElement();
    return in;
}
ConfigStreamWriter &operator<<(ConfigStreamWriter &out, const SUBINDEX& param)
{
    out.writeStartElement("subindex");
    out << param.dSubIndex;
    out << param.iCount;
    out << param.dSolidOffset;
    out << param.dLocationOffset;
    out << param.dSubIndexX;
    out << param.dSolidLine;
    out.writeEndElement();
    return out;
}
ConfigStreamReader &operator >> (ConfigStreamReader &in, SUBINDEX& param)
{
    in.readNextStartElement();
    in >> param.dSubIndex;
    in >> param.iCount;
    in >> param.dSolidOffset;
    in >> param.dLocationOffset;
    in >> param.dSubIndexX;
    in >> param.dSolidLine;
    in.skipCurrentElement();
    return in;
}
ConfigStreamWriter &operator<<(ConfigStreamWriter &out, const SINGLECUTPARAM& param)
{
    out.writeStartElement("param");
    out << param.dCutDepth;
    out << param.dOvercut;
    out << param.dCutSpd;
    out << param.iLaserFreq;
    out << param.iLaserEpulse;
    out << param.dLaserPower;
    out << param.dOffset;
    out << param.laserpathID;
    out << param.dBeamWidth;
    out << param.iCutCount;

    out << param.iKerfStyle;
    out << param.dKerfExpand;
    out << param.iKerfFirst;
    out << param.iKerfFreq;
    out << param.iKerfIndex;
    out << param.dDIndex;

    out << param.dKerfOffset;

    out.writeEndElement();
    return out;
}
ConfigStreamReader &operator >> (ConfigStreamReader &in, SINGLECUTPARAM& param)
{
    in.readNextStartElement();
    in >> param.dCutDepth;
    in >> param.dOvercut;
    in >> param.dCutSpd;
    in >> param.iLaserFreq;
    in >> param.iLaserEpulse;
    in >> param.dLaserPower;
    in >> param.dOffset;
    in >> param.laserpathID;
    in >> param.dBeamWidth;
    in >> param.iCutCount;

    in >> param.iKerfStyle;
    in >> param.dKerfExpand;
    in >> param.iKerfFirst;
    in >> param.iKerfFreq;
    in >> param.iKerfIndex;
    in >> param.dDIndex;

    in >> param.dKerfOffset;

    in.skipCurrentElement();
    return in;
}