#include "cctrlgraphopengl.h"
#include <QBrush>
#include <QColor>
#include <QTransform>
#include <QStylePainter>
#include <QStaticText>
#include <QPainterPath>
#include "cmpoint.h"
#include "m_math.h"
#include "cshapelogic.h"
#include "ccoordpolar.h"
#include "def_global_gui.h"

void CCtrlGraphOpenGL::initializeGL()
{
    makeCurrent();
    initializeOpenGLFunctions(); //初始化OPenGL功能函数
    glClearColor(0.93f, 0.93f, 0.93f, 1.0f);

}

void CCtrlGraphOpenGL::resizeGL(int w, int h)
{
    UNUSED(w);
    UNUSED(h);
    ZoomFit();
    refreshPixmap();
}

void CCtrlGraphOpenGL::paintGL()
{
    makeCurrent();
    QStylePainter painter(this);
    painter.drawPixmap(0,0,m_Pixmap);

    if(m_bCapture)
    {
        QRect rect_normalized= m_rubberBandRect.normalized();
        rect_normalized.adjust(0,0,-1,-1);
        painter.setPen(palette().mid().color());
        painter.drawRect(rect_normalized);
    }

    m_timeFPS.StartTime();
    m_iFrame++;
    if(m_timeFPS.GetTime()>1)
    {
        m_dFPS=m_iFrame;
        m_iFrame=0;
        m_timeFPS.StopTime();
    }

    painter.drawText(rect(),
                     Qt::AlignBottom|Qt::AlignRight,
                     QObject::trUtf8("FPS:%1").arg(m_dFPS));

}

CCtrlGraphOpenGL::CCtrlGraphOpenGL(QWidget *parent) :
    QOpenGLWidget(parent)
{
    m_iMargin_Left=40;
    m_iMargin_Right=30;
    m_iMargin_Top=30;
    m_iMargin_Bottom=30;

    m_bCapture=false;
    m_iPenWidth=0;
    m_bEnableZoom=true;
    m_bEnbleDrawText=true;
    m_bISOTROPIC=true;

    m_iZeroPos=CENTER_POS;
    setFocusPolicy(Qt::StrongFocus);

    m_bInit=false;
    m_BKColor=QRgb(0xececec);

    m_dFPS=0;
    m_iFrame=0;
    m_bXVertical=false;
    m_iCoordLineLength=30;
    m_sName=QObject::trUtf8("chart");

	m_dStartX = 0;
	m_dStartY = 0;
}

void CCtrlGraphOpenGL::init_rectWindow()
{
    m_rectWindow.m_width=m_dRangeXMax;
    m_rectWindow.m_height=m_dRangeYMax;
    adjust_rectWindow(true );
}

CCtrlGraphOpenGL::~CCtrlGraphOpenGL()
{
}

void CCtrlGraphOpenGL::MInit()
{
    if(!m_bEnbleDrawText)
    {
        m_iMargin_Left=3;
        m_iMargin_Right=3;
        m_iMargin_Top=3;
        m_iMargin_Bottom=3;
    }
    init_rectWindow();
}

void CCtrlGraphOpenGL::MTimeFresh()
{
    refreshPixmap();
}

void CCtrlGraphOpenGL::MFresh()
{
    refreshPixmap();
}

void CCtrlGraphOpenGL::MApply()
{

}
static int32_t text_offset=5;
static int32_t triangle_length=10;
void CCtrlGraphOpenGL::draw_Background(QPainter &painter)
{
    adjust_rectWindow(false);
    for(QList<double>::iterator ii=lUnitsX.begin();ii!=lUnitsX.end();ii++)
    {
        m_dCurUnitX=*ii;
        if(m_rectWindow.m_width>m_dCurUnitX)break;
    }
    for(QList<double>::iterator ii=lUnitsY.begin();ii!=lUnitsY.end();ii++)
    {
        m_dCurUnitY=*ii;
        if(m_rectWindow.m_height>m_dCurUnitY)break;
    }

    QRectF rectView=get_rectClip();
    double dstepViewX=rectView.width()/m_rectWindow.m_width*m_dCurUnitX;

    double dstepViewY=rectView.height()/m_rectWindow.m_height*m_dCurUnitY;

    QBrush bhtext(palette().windowText().color());
    QBrush bhline(palette().mid().color());
    painter.setPen(QPen(bhtext,0));
    double dpos=int32_t(m_rectWindow.bottomleft().tX/m_dCurUnitX)*m_dCurUnitX;
    if(dpos<m_rectWindow.bottomleft().tX) dpos+=m_dCurUnitX;
    for(;dpos<m_rectWindow.bottomright().tX;dpos+=m_dCurUnitX)
    {
        QPointF pttopw,ptbottomw;
        QPointF pttopv,ptbottomv;
        pttopw=QPointF(dpos,m_rectWindow.topleft().tY);
        ptbottomw=QPointF(dpos,m_rectWindow.bottomright().tY);
        pttopv=m_trans_LP2DP.map(pttopw);
        ptbottomv=m_trans_LP2DP.map(ptbottomw);

        if(m_bEnbleDrawText)
        {
            painter.setPen(QPen(bhtext,0));
            if(!m_bXVertical)
            {
                QRectF rectText(QPointF(ptbottomv.x()-dstepViewX/2,ptbottomv.y()),
                                QPointF(ptbottomv.x()+dstepViewX/2,ptbottomv.y()+m_iMargin_Bottom));

                rectText.adjust(0,text_offset,0,text_offset);
                painter.drawText(rectText,
                                 Qt::AlignHCenter|Qt::AlignTop,
                                 MakeCoordText(dpos + m_dStartX,true));
            }
            else
            {
                painter.save();
                painter.translate(ptbottomv);
                painter.rotate(60);
                painter.drawText(QRectF(QPointF(5,-50),QSizeF(100,100)),
                                 Qt::AlignLeft|Qt::AlignVCenter,
                                 MakeCoordText(dpos + m_dStartX,true));
                painter.restore();
            }
        }
        if(DEQUAL0(dpos-m_rectWindow.bottomleft().tX)
                ||DEQUAL0(dpos-m_rectWindow.bottomright().tX))
        {
            continue;
        }
        painter.setPen(QPen(bhline,0,Qt::DashLine));
        painter.drawLine(pttopv,ptbottomv);
    }
    dpos=int32_t(m_rectWindow.bottomleft().tY/m_dCurUnitY)*m_dCurUnitY;
    if(dpos<m_rectWindow.bottomleft().tY)dpos+=m_dCurUnitY;
    for(;dpos<m_rectWindow.topright().tY;dpos+=m_dCurUnitY)
    {
        QPointF ptleftw,ptrightw;
        QPointF ptleftv,ptrightv;
        ptleftw=QPointF(m_rectWindow.topleft().tX,dpos);
        ptrightw=QPointF(m_rectWindow.bottomright().tX,dpos);
        ptleftv=m_trans_LP2DP.map(ptleftw);
        ptrightv=m_trans_LP2DP.map(ptrightw);
        if(m_bEnbleDrawText)
        {
            QRectF rectText(QPointF(ptleftv.x()-m_iMargin_Left,ptleftv.y()-dstepViewY/2),
                            QPointF(ptleftv.x(),ptleftv.y()+dstepViewY/2));
            rectText.adjust(-text_offset,0,-text_offset,0);
            painter.setPen(QPen(bhtext,0));
            painter.drawText(rectText,
                             Qt::AlignVCenter|Qt::AlignRight,
                             MakeCoordText(dpos + m_dStartY,false));
        }

        if(DEQUAL0(dpos-m_rectWindow.bottomleft().tY)
                ||DEQUAL0(dpos-m_rectWindow.topright().tY))
        {
            continue;
        }
        painter.setPen(QPen(bhline,0,Qt::DashLine));
        painter.drawLine(ptleftv,ptrightv);
    }
    rectView.adjust(0,0,-1,-1);
    painter.setPen(QPen(bhtext,0));
    painter.drawRect(rectView);
    if(!m_bEnbleDrawText) return;

    painter.drawStaticText(text_offset,text_offset,
                           QStaticText(tr("%3:unit:(%1/%2)").
                                       arg(m_strUnitY).
                                       arg(m_strUnitX).
                                       arg(m_sName)));

    QPointF bottomleft= rect().bottomLeft();

    bottomleft.rx()+=text_offset;
    bottomleft.ry()-=text_offset;

    painter.drawLine(bottomleft.x(),bottomleft.y(),
                     bottomleft.x()+m_iCoordLineLength,bottomleft.y());
    QPainterPath path(QPointF(bottomleft.x()+m_iCoordLineLength,bottomleft.y()));
    path.lineTo(QPointF(bottomleft.x()+m_iCoordLineLength-triangle_length,bottomleft.y()+triangle_length/2));
    path.lineTo(QPointF(bottomleft.x()+m_iCoordLineLength-triangle_length,bottomleft.y()-triangle_length/2));
    path.lineTo(QPointF(bottomleft.x()+m_iCoordLineLength,bottomleft.y()));
    painter.fillPath(path,bhtext);

    painter.drawText(bottomleft.x()+m_iCoordLineLength+text_offset,
                     bottomleft.y()+ text_offset/2,
                     "X");
    painter.drawLine(bottomleft.x(),bottomleft.y(),
                     bottomleft.x(),bottomleft.y()-m_iCoordLineLength);

    path=QPainterPath(QPointF(bottomleft.x(),bottomleft.y()-m_iCoordLineLength));
    path.lineTo(QPointF(bottomleft.x()+triangle_length/2,bottomleft.y()-m_iCoordLineLength+triangle_length));
    path.lineTo(QPointF(bottomleft.x()-triangle_length/2,bottomleft.y()-m_iCoordLineLength+triangle_length));
    path.lineTo(QPointF(bottomleft.x(),bottomleft.y()-m_iCoordLineLength));

    painter.fillPath(path,bhtext);
    painter.drawText(bottomleft.x()- text_offset/2,
                     bottomleft.y()-m_iCoordLineLength-text_offset,
                     "Y");

    //    painter.setPen(Qt::lightGray);
    //    QRectF rect1=rect();
    //    rect1.adjust(0.5,0.5,-0.5,-0.5);
    //    painter.drawRect(rect1);
    //    painter.setClipRect(rectView);
}

void CCtrlGraphOpenGL::updaterubberBandRect()
{
    QRect rect_normalized= m_rubberBandRect.normalized();
    update(rect_normalized.left(),rect_normalized.top(),rect_normalized.width(),1);
    update(rect_normalized.left(),rect_normalized.top(),1,rect_normalized.height());
    update(rect_normalized.left(),rect_normalized.bottom(),rect_normalized.width(),1);
    update(rect_normalized.right(),rect_normalized.top(),1,rect_normalized.height());
}

void CCtrlGraphOpenGL::refreshPixmap(bool bupdate)
{
    if(!isVisible()) return;
    makeCurrent();
    m_Pixmap=QPixmap(size());
    m_Pixmap.fill(m_BKColor);
    QPainter painter(&m_Pixmap);
    painter.initFrom(this);
    if(!painter.isActive())return;
    draw_Background(painter);
    if(bupdate)
    {
        update();
    }
}

void CCtrlGraphOpenGL::CalcuTransfrom()
{
    QRectF rectView=get_rectClip();
    QPolygonF one,two;
    one.push_back(QPointF(m_rectWindow.topleft().tX,m_rectWindow.topleft().tY));
    one.push_back(QPointF(m_rectWindow.bottomright().tX,m_rectWindow.bottomright().tY));
    one.push_back(QPointF(m_rectWindow.topright().tX,m_rectWindow.topright().tY));
    one.push_back(QPointF(m_rectWindow.bottomleft().tX,m_rectWindow.bottomleft().tY));

    two.push_back(QPointF(rectView.topLeft().x(),rectView.topLeft().y()));
    two.push_back(QPointF(rectView.bottomRight().x(),rectView.bottomRight().y()));
    two.push_back(QPointF(rectView.topRight().x(),rectView.topRight().y()));
    two.push_back(QPointF(rectView.bottomLeft().x(),rectView.bottomLeft().y()));
    QTransform transform;

    bool bsuccess= QTransform::quadToQuad(one,two, transform);
    if (true == bsuccess)
    {
        m_trans_LP2DP = transform;
    }
    else
    {
        //Q_ASSERT(bsuccess);
    }
    //    bsuccess= QTransform::quadToQuad(two,one,m_trans_DP2LP);
    //    Q_ASSERT(bsuccess);
    m_trans_DP2LP=m_trans_LP2DP.inverted(&bsuccess);
    Q_ASSERT(bsuccess);
}
//void CCtrlGraphOpenGL::paintEvent(QPaintEvent *pEvent)
//{
//    UNUSED(pEvent);
//    QStylePainter painter(this);
//    painter.drawPixmap(0,0,m_Pixmap);

//    if(m_bCapture)
//    {
//        QRect rect_normalized= m_rubberBandRect.normalized();
//        rect_normalized.adjust(0,0,-1,-1);
//        painter.setPen(palette().mid().color());
//        painter.drawRect(rect_normalized);
//    }

//}

void CCtrlGraphOpenGL::showEvent(QShowEvent *pEvent)
{
    UNUSED(pEvent);
    if(!m_bInit)
    {
        m_bInit=true;
        ZoomFit();
    }
}

void CCtrlGraphOpenGL::mousePressEvent(QMouseEvent *pEvent)
{
    m_bCapture=false;
    if(pEvent->button()==Qt::LeftButton)
    {
        if(m_bEnableZoom)
        {
            QRectF rectView=get_rectClip();
            QPointF posEvent=pEvent->pos();
            if(rectView.contains(posEvent))
            {
                m_rubberBandRect.setTopLeft(pEvent->pos());
                m_rubberBandRect.setBottomRight(pEvent->pos());
                m_bCapture=true;
            }
        }
    }
    else if(pEvent->button()==Qt::RightButton)
    {
        ZoomFit();
    }
}

void CCtrlGraphOpenGL::mouseReleaseEvent(QMouseEvent *pEvent)
{
    UNUSED(pEvent);
    if(pEvent->button()==Qt::LeftButton)
    {
        if(m_bCapture)
        {
            QRect rect_normalized= m_rubberBandRect.normalized();
            if((rect_normalized.width()>4&&rect_normalized.height()>4))
            {
                QPointF topleft=m_trans_DP2LP.map(rect_normalized.topLeft());
                QPointF bottomright=m_trans_DP2LP.map(rect_normalized.bottomRight());

                double curRangeX= fabs(double(topleft.x()-bottomright.x()));
                double curRangeY= fabs(double(topleft.y()-bottomright.y()));
                if(curRangeX>m_dRangeXMin&&curRangeY>m_dRangeYMin)
                {
                    QPointF center= m_trans_DP2LP.map(rect_normalized.center());
                    m_rectWindow.m_center=CMPointd(center.x(),center.y());
                    m_rectWindow.m_width=curRangeX;
                    m_rectWindow.m_height=curRangeY;
                }
            }
            refreshPixmap();
        }
    }
    m_bCapture=false;
}

void CCtrlGraphOpenGL::mouseMoveEvent(QMouseEvent *pEvent)
{
    if(m_bCapture )
    {
        updaterubberBandRect();
        QPointF posEvent=pEvent->pos();
        QRectF rectView=get_rectClip();
        if(rectView.contains(posEvent))
        {
            m_rubberBandRect.setBottomRight(pEvent->pos());
        }
        else
        {
            if(posEvent.x()>m_rubberBandRect.right())
            {
                m_rubberBandRect.setRight(rectView.right());
            }
            if(posEvent.y()>m_rubberBandRect.bottom())
            {
                m_rubberBandRect.setBottom(rectView.bottom());
            }
        }
        updaterubberBandRect();
    }
}

void CCtrlGraphOpenGL::wheelEvent(QWheelEvent *pEvent)
{
    int numDegrees=pEvent->delta()/8;
    int numticks=numDegrees/15;
    m_rectWindow.m_width-=numticks*m_dCurUnitX/10.0;
    m_rectWindow.m_height-=numticks*m_dCurUnitY/10.0;

    //   QPoint center= m_trans_DP2LP.map(pEvent->pos());
    //   m_rectWindow.m_center=CMPointd(center.x(),center.y());
    refreshPixmap();
}

QString CCtrlGraphOpenGL::MakeCoordText(double dPos, bool bX)
{
    UNUSED(bX);
    return QString("%1").arg(dPos);
}

//void CCtrlGraphOpenGL::resizeEvent(QResizeEvent *)
//{
//    adjust_rectWindow(false);
//    refreshPixmap();
//}

void CCtrlGraphOpenGL::ZoomIn()
{
    if(!m_bEnableZoom) return;
    m_rectWindow.m_width*=2;
    m_rectWindow.m_height*=2;
    refreshPixmap();
}

void CCtrlGraphOpenGL::ZoomOut()
{
    if(!m_bEnableZoom) return;
    m_rectWindow.m_width/=2;
    m_rectWindow.m_height/=2;
    refreshPixmap();
}

void CCtrlGraphOpenGL::ZoomFit()
{
    init_rectWindow();
    refreshPixmap();
}

QRectF CCtrlGraphOpenGL::get_rectClip()
{
    QRect cliprect=rect();
        cliprect.adjust(m_iMargin_Left,m_iMargin_Top,
                        -m_iMargin_Right,-m_iMargin_Bottom);

    return cliprect;
}

void CCtrlGraphOpenGL::adjust_rectWindow(bool bresetZero)
{
    QRectF rectView=get_rectClip();
    double dviewwidth=rectView.width();
    double dviewheight=rectView.height();
    double dwindowwidth=m_rectWindow.m_width;
    double dwindowheight=m_rectWindow.m_height;
    dwindowwidth= min(dwindowwidth,m_dRangeXMax);
    dwindowwidth= max(dwindowwidth,m_dRangeXMin);

    dwindowheight= min(dwindowheight,m_dRangeYMax);
    dwindowheight= max(dwindowheight,m_dRangeYMin);

    if(m_bISOTROPIC)
    {

        double dscale=max(dwindowwidth/dviewwidth,
                          dwindowheight/dviewheight);

        dwindowwidth=dviewwidth*dscale;
        dwindowheight=dviewheight*dscale;
    }

    m_rectWindow.m_width=dwindowwidth;
    m_rectWindow.m_height=dwindowheight;

    if(bresetZero)
    {
        switch(m_iZeroPos)
        {
        case CENTER_POS:
            m_rectWindow.m_center.tX=0;
            m_rectWindow.m_center.tY=0;
            break;
        case LEFT_BOTTOM:
            m_rectWindow.m_center.tX=dwindowwidth/2;
            m_rectWindow.m_center.tY=dwindowheight/2;
            break;
        case LEFT_CENTER:
            m_rectWindow.m_center.tX=dwindowwidth/2;
            m_rectWindow.m_center.tY=0;
            break;
        case LEFT_TOP:
            m_rectWindow.m_center.tX=dwindowwidth/2;
            m_rectWindow.m_center.tY=-dwindowheight/2;
            break;
        case BOTTOM_CENTER:
            m_rectWindow.m_center.tX=0;
            m_rectWindow.m_center.tY=dwindowheight/2;
            break;
        case BOTTOM_RIGHT:
            m_rectWindow.m_center.tX=-dwindowwidth/2;
            m_rectWindow.m_center.tY=dwindowheight/2;
            break;
        default:
            Q_ASSERT(0);
        }
    }
    CalcuTransfrom();
}

void CCtrlGraphOpenGL::SetStartXY(double dStartX, double dStartY)
{
	m_dStartX = dStartX;
	m_dStartY = dStartY;
}