#include "cjig_driver.h"
#include "logic_local_def.h"
#include "logic_eap.h"
#include "cmworktabledriver.h"
#include "csystem_external.h"
#include "ccam.h"
#include "cprocess_laserkerf.h"

CJigDriver::CJigDriver(const QString& name, int32_t id)
    : CDriverCard(name, id)
{
    //区域配置

    //中心位置
    m_Variants.add_Variant(Var_Process_LaserKerf_AreaCenterX,
                           QObject::trUtf8("AreaCenterX"), double(665), false,
                           Variant::TOXML);

    m_Variants.add_Variant(Var_Process_LaserKerf_AreaCenterY,
                           QObject::trUtf8("AreaCenterY"), double(36), false,
                           Variant::TOXML);

    //每个小区域的直径
    m_Variants.add_Variant(Var_Process_LaserKerf_AreaCellDiameter,
                           QObject::trUtf8("AreaCellDiameter"), double(3), false,
                           Variant::TOXML);

    //有效区域的宽度
    m_Variants.add_Variant(Var_Process_LaserKerf_AreaValidWidth,
                           QObject::trUtf8("AreaValidWidth"), double(60), false,
                           Variant::TOXML);
    //0 圆形 1矩形
    m_Variants.add_Variant(Var_Process_LaserKerf_AreaType,
                           QObject::trUtf8("AreaShape"), uint(0), false,
                           Variant::TOXML);


    //排除外区域
    m_Variants.add_Variant(Var_Process_LaserKerf_OuterErosionDistance,
                           QObject::trUtf8("OuterErosionDistance"), double(8), false,
                           Variant::TOXML);

    //排除中心区域
    m_Variants.add_Variant(Var_Process_LaserKerf_InnerErosionDistance,
                           QObject::trUtf8("InnerErosionDistance"), double(8), false,
                           Variant::TOXML);

    //测量厚度
    m_Variants.add_Variant(Var_Process_LaserKerf_ZFocusThickness,
                           QObject::trUtf8("Thickness"), double(-0.44), false,
                           Variant::TOXML);

    m_Variants.add_Variant(Var_Process_LaserKerf_WorkTableYOffset,
                           QObject::trUtf8("WorktableYOffset"), double(0), false,
                           Variant::TOXML);

    //划线长度
    m_Variants.add_Variant(Var_Process_LaserKerf_LineLength,
                           QObject::trUtf8("LineLenth"), double(1), false,
                           Variant::TOXML);

    //划线步进 高倍相机0.9mm 是1个视野
    //200um可以画一条
    m_Variants.add_Variant(Var_Process_LaserKerf_LineStep,
                           QObject::trUtf8("LineStep"), double(0.2), false,
                           Variant::TOXML);

    //焦点定位时的光源、相机参数
    m_Variants.add_Variant(Var_Process_LaserKerf_FocusLightDirect,
                           QObject::trUtf8("KerfFocusLightCoaxial"), int(200), false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_LaserKerf_FocusLightCircle,
                           QObject::trUtf8("KerfFocusLightRing"), int(50), false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_LaserKerf_FocusExposure,
                           QObject::trUtf8("KerfFocusLightExposure"), int(2000), false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_Process_LaserKerf_FocusGain,
                           QObject::trUtf8("KerfFocusLightGain"), int(0), false,
                           Variant::TOXML);

    m_iCurPosIdx = 0;	//
    m_dFocusOffset = 0; //计算焦点偏移补偿
    m_iKerfCamID = CAM6X;
}

int CJigDriver::ReplaceMarkPanel()
{
    std::vector<_Mark_Area> tempVec;
    int iCurIndex = 0;
    int iTempIndex = 0;

    {
        QWriteLocker l(&m_Lock);
        tempVec.swap(m_MarkListTopLeft);
        iCurIndex = m_iCurPosIdx;
        l.unlock();
    }


    try
    {
        InitalPosVector(m_MarkListTopLeft, iCurIndex);

        int size = m_MarkListTopLeft.size();
        int iStep = size / 4;
        int iIndex = iStep / 2;
        for (int i = 0; i < 4; i++)
        {
            MeasureThickness(iIndex, false);
            iIndex += iStep;
        }

    }
    catch (const QString& ex)
    {
        //恢复
        QWriteLocker l(&m_Lock);
        m_MarkListTopLeft.clear();
        m_MarkListTopLeft.swap(tempVec);
        //m_iCurPosIdx = iCurIndex;
        l.unlock();
        MQT_THROW_STR(ex);
        return -1;
    }

    {
        QWriteLocker l(&m_Lock);
        /*m_MarkListTopLeft.clear();
        m_MarkListTopLeft.swap(tempVec);*/
        m_iCurPosIdx = iCurIndex;
        l.unlock();
    }

    SaveCutData(true);
    LoadMarkData(false);
    return 0;
}

void CJigDriver::InitalPosVector(std::vector<_Mark_Area>& areaListTopLeft, int& iIndex)
{
    areaListTopLeft.clear();
    iIndex = 0;

    //内部嵌套为列，外部嵌套为行
    std::vector<int> rowColList;
    //double validWidth = m_Variants.get_VData(Var_Process_LaserKerf_AreaValidWidth)->toDouble();
    //double validStep 665 36
    double dCenterX = m_Variants.get_VData(Var_Process_LaserKerf_AreaCenterX)->toDouble();
    double dCenterY = m_Variants.get_VData(Var_Process_LaserKerf_AreaCenterY)->toDouble();

    /*double validWidth = 60;*/
    double validWidth = m_Variants.get_VData(Var_Process_LaserKerf_AreaValidWidth)->toDouble();

    //stepLineWidth=0.2
    double stepLineWidth = m_Variants.get_VData(Var_Process_LaserKerf_LineStep)->toDouble();
    //double cellWidth = 4;
    double cellWidth = m_Variants.get_VData(Var_Process_LaserKerf_AreaCellDiameter)->toDouble();

    //外部区域缩减
    double innerErosion = m_Variants.get_VData(Var_Process_LaserKerf_OuterErosionDistance)->toDouble();
    //内部区域缩减
    double outerErosion = m_Variants.get_VData(Var_Process_LaserKerf_InnerErosionDistance)->toDouble();

    uint areaType = m_Variants.get_VData(Var_Process_LaserKerf_AreaType)->toUInt();
    if (areaType == 0)
    {
        double radius = validWidth / 2 - outerErosion;
        double dy = innerErosion + cellWidth;
        while (dy < radius)
        {
            int colCount = radius * cos(asin(dy / radius)) / cellWidth;
            if (colCount <= 0)
            {
                break;
            }

            rowColList.push_back(colCount);
            dy += cellWidth;
        }
    }
    else
    {
        double radius = validWidth / 2 - outerErosion;
        double dy = innerErosion + cellWidth;
        while (dy < radius)
        {
            int colCount = radius / cellWidth;
            if (colCount <= 0)
            {
                break;
            }

            rowColList.push_back(colCount);
            dy += cellWidth;
        }
    }

    _Mark_Area initMarkArea;
    initMarkArea.dWidth = cellWidth;
    initMarkArea.dHeight = cellWidth;
    initMarkArea.iLineIndex = 0;
    initMarkArea.iSize = cellWidth / stepLineWidth;
    initMarkArea.iReservedIndex = initMarkArea.iSize / 2;
    initMarkArea.dStep = stepLineWidth;
    initMarkArea.iStartIndex = initMarkArea.iLineIndex;
    initMarkArea.iReservedIndex = initMarkArea.iSize / 2;

    //平台原点在左下角 X向右为正 Y向里为正
    int cellIndex = 0;
    //第一象限
    CMPointd ptRightTop = CMPointd(- innerErosion, - innerErosion);
    ptRightTop.tX += 0;
    ptRightTop.tY += -cellWidth;
    for (size_t row = 0; row < rowColList.size(); row++)
    {
        for (int col = 0; col < rowColList[row]; col++)
        {
            double offsetX = -cellWidth * col;
            double offsetY = -cellWidth * row;
            CMPointd pt(ptRightTop.tX + offsetX, ptRightTop.tY + offsetY);

            _Mark_Area markArea = initMarkArea;
            markArea.ptLeftTop = pt;
            markArea.iCellIndex = cellIndex++;
            areaListTopLeft.push_back(markArea);
        }
    }

    //第二象限
    CMPointd ptLeftTop = CMPointd(innerErosion, - innerErosion);
    ptLeftTop.tX += cellWidth;
    ptLeftTop.tY += -cellWidth;
    for (size_t row = 0; row < rowColList.size(); row++)
    {
        for (int col = 0; col < rowColList[row]; col++)
        {
            double offsetX = cellWidth * col;
            double offsetY = -cellWidth * row;
            CMPointd pt(ptLeftTop.tX + offsetX, ptLeftTop.tY + offsetY);

            _Mark_Area markArea = initMarkArea;
            markArea.ptLeftTop = pt;
            markArea.iCellIndex = cellIndex++;
            areaListTopLeft.push_back(markArea);
        }
    }

    //第三象限
    CMPointd ptLeftBottom = CMPointd(innerErosion, innerErosion);
    ptLeftBottom.tX += cellWidth;
    ptLeftBottom.tY += 0;
    for (size_t row = 0; row < rowColList.size(); row++)
    {
        for (int col = 0; col < rowColList[row]; col++)
        {
            double offsetX = cellWidth * col;
            double offsetY = cellWidth * row;
            CMPointd pt(ptLeftBottom.tX + offsetX, ptLeftBottom.tY + offsetY);

            _Mark_Area markArea = initMarkArea;
            markArea.ptLeftTop = pt;
            markArea.iCellIndex = cellIndex++;
            areaListTopLeft.push_back(markArea);
        }
    }

    //第四象限
    CMPointd ptRightBottom = CMPointd( - innerErosion, innerErosion);
    ptRightBottom.tX += 0;
    ptRightBottom.tY += 0;
    for (size_t row = 0; row < rowColList.size(); row++)
    {
        for (int col = 0; col < rowColList[row]; col++)
        {
            double offsetX = -cellWidth * col;
            double offsetY = cellWidth * row;
            CMPointd pt(ptRightBottom.tX + offsetX, ptRightBottom.tY + offsetY);

            _Mark_Area markArea = initMarkArea;
            markArea.ptLeftTop = pt;
            markArea.iCellIndex = cellIndex++;
            areaListTopLeft.push_back(markArea);
        }
    }
}

void CJigDriver::SaveCutData(bool bWrite)
{
    QString strPath = CMakePath::make_config_path("LaserCutIndex.lpf");
    QFile file(strPath);
    if (!file.open(QIODevice::ReadWrite))
    {
        MQT_THROW_CODESTR(ALARM_MAIN_LASERCALI_ERROR, (QObject::trUtf8("Laser Cali") + QObject::trUtf8("open path %1 failed").arg(strPath)));

    }
    QTextStream stream(&file);
    if (bWrite)
    {
        stream << m_iCurPosIdx << endl;
    }
    else
    {
        stream >> m_iCurPosIdx;
    }
}

void CJigDriver::LoadMarkData(bool bRead)
{
    QString strPath = CMakePath::make_config_path("LaserCutData.lpf");
    QFile file(strPath);
    if (bRead)
    {
        if (!file.open(QIODevice::ReadWrite))
        {
            MQT_THROW_CODESTR(ALARM_MAIN_LASERCALI_ERROR, (QObject::trUtf8("Laser Cali") + QObject::trUtf8("open path %1 failed").arg(strPath)));

        }
    }
    else
    {
        if (!file.open(QIODevice::WriteOnly))
        {
            MQT_THROW_CODESTR(ALARM_MAIN_LASERCALI_ERROR, (QObject::trUtf8("Laser Cali") + QObject::trUtf8("open path %1 failed").arg(strPath)));
        }
    }
    QWriteLocker l(&m_Lock);
    QDataStream stream(&file);
    if (bRead)
    {
        int iSize = 0;
        stream >> iSize;

        m_MarkListTopLeft.clear();
        if (0 == iSize)return;

        m_MarkListTopLeft.resize(iSize);
        for (int i = 0; i < iSize; i++)
        {
            _Mark_Area markArea;
            stream >> markArea.iCellIndex;
            stream >> markArea.ptLeftTop.tX;
            stream >> markArea.ptLeftTop.tY;
            stream >> markArea.iSize;
            stream >> markArea.iReservedIndex;	//用于其他作用的index
            stream >> markArea.iLineIndex;
            stream >> markArea.iStartIndex;	//哪条起可以用
            stream >> markArea.dWidth;
            stream >> markArea.dHeight;
            stream >> markArea.dStep;
            stream >> markArea.dFocusOffset;
            stream >> markArea.bEnable;
            stream >> markArea.bFocused;
            stream >> markArea.bFoucsedCuted;
            m_MarkListTopLeft[i] = markArea;
        }
    }
    else
    {

        QString csvPath = CMakePath::make_config_path("LaserCutData.csv");
        QFile csvFile(csvPath);
        if (!csvFile.open(QIODevice::WriteOnly))
        {
            MQT_THROW_CODESTR(ALARM_MAIN_LASERCALI_ERROR, (QObject::trUtf8("Laser Cali") + QObject::trUtf8("open path %1 failed").arg(csvPath)));
        }

        QTextStream csvStream(&csvFile);
        QDataStream stream(&file);
        stream << (int)m_MarkListTopLeft.size();
        for (int i = 0; i < m_MarkListTopLeft.size(); i++)
        {
            int iLineIdx;
            _Mark_Area& markArea = m_MarkListTopLeft[i];
            stream << markArea.iCellIndex;
            stream << markArea.ptLeftTop.tX;
            stream << markArea.ptLeftTop.tY;
            stream << markArea.iSize;
            stream << markArea.iReservedIndex;	//用于其他作用的index
            stream << markArea.iLineIndex;
            stream << markArea.iStartIndex;			//哪条起可以用
            stream << markArea.dWidth;
            stream << markArea.dHeight;
            stream << markArea.dStep;
            stream << markArea.dFocusOffset;
            stream << markArea.bEnable;
            stream << markArea.bFocused;
            stream << markArea.bFoucsedCuted;

            if (i == 0)
                csvStream << markArea.tittle().c_str();

            csvStream << markArea.toString().c_str();
        }
    }
}

int CJigDriver::MeasureThickness(int iCellIndex /*= -1*/, bool bOnlyMeasure /*= false*/)
{
    double dStartPosX = 0;
    double dEndPosX = 0;
    double dPosY = 0;

    CalcuMeasurePos(dStartPosX, dEndPosX, dPosY, iCellIndex);

    CProcess_LaserKerf* pLaserCali = GET_PROCESS(PROCESS_LASERKERF, SM_MAIN, CProcess_LaserKerf);
    if (!bOnlyMeasure && IsNeedMeasureCut(iCellIndex))
    {
        pLaserCali->CutKerf(dStartPosX, dEndPosX, dPosY, true, iCellIndex);
    }

    pLaserCali->MoveKerfPos();
    MeasTargetThick(iCellIndex);
    return 0;
}


int CJigDriver::CalcuMeasurePos(double& dStartPosX, double& dEndPosX, double& dPosY, int iCellIndex /*= -1*/)
{
    QReadLocker l(&m_Lock);
    if (iCellIndex <= 0)
        iCellIndex = m_iCurPosIdx;

    if (iCellIndex >= m_MarkListTopLeft.size())
    {
        //没有区域可供划线了，请更换
        MQT_THROW_CODESTR(ALARM_MAIN_LASERCALI_ERROR, (QObject::trUtf8("Laser Cali") + QObject::trUtf8("No area available to cutline, please replace the check wafer")));
    }

    CMWorkTableDriver* pWorktableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorktableDriver);

    _Mark_Area markArea = m_MarkListTopLeft[iCellIndex];
    double posX = markArea.ptLeftTop.tX - markArea.dWidth / 2;
    double posY = markArea.ptLeftTop.tY + markArea.dStep * markArea.iReservedIndex;
    l.unlock();

    double dKerfWidth = m_Variants.get_VData(Var_Process_LaserKerf_LineLength)->toDouble();
    //高倍相机看到时，坐标的位置
    double halfLineLength = dKerfWidth / 2;
    double posStart = posX + halfLineLength;

    CMPointd axisStart(posStart, posY);
    CMPointd wtStart;
    pWorktableDriver->AxisToWt(m_iKerfCamID, axisStart, wtStart);
    dStartPosX = wtStart.tX;
    dEndPosX = wtStart.tX + dKerfWidth;
    dPosY = wtStart.tY;

    m_CheckPos.tX = wtStart.tX + halfLineLength;
    m_CheckPos.tY = wtStart.tY;

    //此时没有偏移
    m_dFocusOffset = 0;

    return 0;
}

double CJigDriver::MeasTargetThick(int iCellIndex)
{
    CMWorkTableDriver* pWorkTableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorkTableDriver);


    SetMeasureCamParam();
    double dThickness = m_Variants.get_VData(Var_Process_LaserKerf_ZFocusThickness)->toDouble();
    double dZpos = pWorkTableDriver->DefoucsDisToZPos(m_iKerfCamID, dThickness);

    //测量出来的厚度
    double dFoucsPos = pWorkTableDriver->FoucsChannel(m_iKerfCamID, dThickness, WORKTABLE, -1);
    //测量出来的片厚
    double dThickMeasure = pWorkTableDriver->ZPosToDefoucsDis(m_iKerfCamID, dFoucsPos, WORKTABLE);


    //测量出的厚度偏差
    double dOffset = dThickMeasure - dThickness;
    if (fabs(dOffset) > 0.4)
    {
        MQT_THROW_CODESTR(ALARM_MAIN_LASERCALI_ERROR, (QObject::trUtf8("Laser Cali") + (QString("Measure Offset %1>%2").arg(dOffset).arg(0.4))));
    }

    //当前焦点
    _SysExt_Instance.LogInfo(QString("Measure laser check area offset with worktable:%1").arg(dThickMeasure));

    CCam* pCam = GET_CHDIRECT(m_iKerfCamID, CCam);
    Q_ASSERT(pCam);
    pCam->m_imageContainer.clearString();
    QString str = QObject::trUtf8("Thick:%1mm").arg(dThickMeasure);
    pCam->m_imageContainer.addString(str);

    /*int iSideID = _SysExt_Instance.m_iCurSideID == SIDE_B ? SIDE_B : SIDE_A;
    CaptureImage(iSideID, str);*/

    CJigDriver* pJigDriver = GET_CARD(JigDriver, CJigDriver);
    QWriteLocker l(&m_Lock);
    Q_ASSERT(iCellIndex < m_MarkListTopLeft.size());
    m_MarkListTopLeft[iCellIndex].bFocused = true;
    m_MarkListTopLeft[iCellIndex].dFocusOffset = dOffset;
    m_dFocusOffset = dOffset;

    //m_MarkListTopLeft[m_iCurPosIdx]

    return 0;
}


void CJigDriver::SetMeasureCamParam()
{
    int iLightDirect = m_Variants.get_VData(Var_Process_LaserKerf_FocusLightDirect)->toInt();
    int iLightCircle = m_Variants.get_VData(Var_Process_LaserKerf_FocusLightCircle)->toInt();
    int iExposure = m_Variants.get_VData(Var_Process_LaserKerf_FocusExposure)->toInt();
    int iGain = m_Variants.get_VData(Var_Process_LaserKerf_FocusGain)->toInt();
    _SysExt_Instance.SetCamLight(m_iKerfCamID, iLightDirect, true, false);
    _SysExt_Instance.SetCamLight(m_iKerfCamID, iLightCircle, false, false);
    _SysExt_Instance.SetCamParam(m_iKerfCamID, iExposure, iGain);
}

bool CJigDriver::IsNeedMeasure()
{
    QReadLocker l(&m_Lock);
    if (m_iCurPosIdx >= m_MarkListTopLeft.size())
        return false;

    if (m_MarkListTopLeft[m_iCurPosIdx].bFocused)
        return false;

    return true;
}

bool CJigDriver::IsNeedMeasureCut(int iCellIndex/*=-1*/)
{
    QReadLocker l(&m_Lock);
    if (iCellIndex == -1)
        iCellIndex = m_iCurPosIdx;

    if (iCellIndex >= m_MarkListTopLeft.size())
        return false;

    if (m_MarkListTopLeft[iCellIndex].bFoucsedCuted)
        return false;

    return true;
}

bool CJigDriver::PosIndexIncrease()
{
    QWriteLocker l(&m_Lock);
    Q_ASSERT(m_iCurPosIdx < m_MarkListTopLeft.size());
    bool bFind = false;
    for (int i = m_iCurPosIdx; i < m_MarkListTopLeft.size(); i++)
    {
        int iLineIdx;
        _Mark_Area& markArea = m_MarkListTopLeft[i];
        if (CellAreaHasLine(markArea, iLineIdx))
        {
            //找到一条,则更新数据
            markArea.iLineIndex = iLineIdx;
            m_iCurPosIdx = i;
            bFind = true;
            break;
        }
        else
        {
            m_iCurPosIdx += 1;
        }
    }
    l.unlock();

    SaveCutData(true);
    LoadMarkData(false);

    return bFind;
}

void CJigDriver::SetMeasureCuttedMark(int idx, bool bCutted)
{

    QWriteLocker l(&m_Lock);
    Q_ASSERT(idx < m_MarkListTopLeft.size() && idx >= 0);

    m_MarkListTopLeft[idx].bFoucsedCuted = bCutted;
}

bool CJigDriver::CellAreaHasLine(const _Mark_Area& markArea, int& iLine)
{
    iLine = -1;
    if (markArea.bEnable == false) return false;
    if (markArea.iSize <= 0) return false;

    int iLineIndex = markArea.iLineIndex;
    if (iLineIndex + 1 < markArea.iSize)
    {
        iLineIndex += 1;
        if (iLineIndex == markArea.iReservedIndex)
        {
            //中心那条线不用于划线
            iLineIndex += 1;
        }

        if (iLineIndex > markArea.iSize)
            return false;

        iLine = iLineIndex;
        return true;
    }

    //已经用完了
    return false;
}