#include "peviewqtprivate.h"

#include "VsInterface.h"
#include "VsCursor.h"
#include "VsFunction.h"

PEViewQtPrivate::PEViewQtPrivate(HWND hwnd)
    : CVsView(hwnd)
{
    m_hWnd = hwnd;

    m_bMouseTracking = false;
    m_3dMode = 0;
}

BOOL PEViewQtPrivate::OnMouseWheel(UINT nFlags, short zDelta, POINT point)
{
    if (this->CheckUIOption(UI_DISABLE_MOUSE_MID))
        return TRUE;

    this->m_tEventMgr.OnMouseMove(nFlags, point.x, point.y); // 去除缩放后运动模糊的重影

    if (this->GetOperator() &&
        this->GetOperator()->OnMouseWheel(nFlags, zDelta, point.x, point.y))
    {
        VsFollowViewportCamera();
        return TRUE;
    }

    /// 缩放限定
    this->m_cameraMaxLength = 10000000;
    if (1 + zDelta / 1000.0 > 1 && this->m_cameraMaxLength > 0)
    {
        float pos[3];
        float target[3];
        VsShowCameraPos(pos);
        VsShowCameraTarget(target);

        float dis = PTDIS(target, pos);
        if (dis > this->m_cameraMaxLength)
            return TRUE;
    }

    int cx, cy;
    VsGetClientSize(cx, cy);

    int viewport[4];
    VsShowViewportPixel(NULL, viewport); /// 当前视口
    if (1)
    {
        int x, y;
        int ox = viewport[0] + viewport[2] / 2;
        int oy = cy - (viewport[1] + viewport[3] / 2);
        float factor = fabs(zDelta / 500.0);
        if (zDelta > 0)
        {
            x = ox + (point.x - ox) * factor;
            y = oy + (point.y - oy) * factor;
        }
        else
        {
            x = ox - (point.x - ox) * factor;
            y = oy - (point.y - oy) * factor;
        }

        float old_eye[3], old_tar[3], old_up[3];
        VsShowCamera(old_eye, old_tar, old_up);
        if (this->CheckUIOption(UI_ENABLE_WHEEL_ZOOM))
            VsCameraPan(ox, oy, x, y);

        if (!VsCameraZoom(-zDelta / 1000.0))
        { /// 如果发生碰撞
            VsSetCamera(old_eye, old_tar, old_up);
        }
        else
        {
            float new_eye[3], new_tar[3], new_up[3];
            VsShowCamera(new_eye, new_tar, new_up);
            float len = PTDIS(new_eye, new_tar);
            float r;
            VsGetSceneSize(new_tar[0], new_tar[1], new_tar[2], r);
            if (len < r / 1000000 || len > 2 * r)
            {
                VsSetCamera(old_eye, old_tar, old_up);
            }
        }

        VsFollowViewportCamera();

        VsInvalidate();
        VsUpdateDisplay(); // 强制刷新，因为后面需要用到视图变换
    }

    if (this->GetOperator())
    {
        this->GetOperator()->OnMouseWheel(nFlags, zDelta, point.x, point.y);
        VsFollowViewportCamera();
    }

    return TRUE;
}

void PEViewQtPrivate::OnLButtonDown(UINT nFlags, POINT point)
{
    if (this->CheckUIOption(UI_DISABLE_MOUSE_LEFT))
        return;

    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_LBUTTON, TRUE, nFlags);
    if (pCurGuide)
        pCurGuide->OnButtonDown(&gp);

    this->MainModule()->OnLButtonDown(nFlags, point.x, point.y);

    if (this->GetOperator())
        this->GetOperator()->OnLButtonDown(nFlags, point.x, point.y);

    this->m_tEventMgr.OnLButtonDown(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnLButtonUp(UINT nFlags, POINT point)
{
    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_LBUTTON, FALSE, nFlags);
    if (pCurGuide)
        pCurGuide->OnButtonUp(&gp);

    this->MainModule()->OnLButtonUp(nFlags, point.x, point.y);

    if (this->GetOperator())
        this->GetOperator()->OnLButtonUp(nFlags, point.x, point.y);

    this->m_tEventMgr.OnLButtonUp(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnRButtonDown(UINT nFlags, POINT point)
{
    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_RBUTTON, TRUE, nFlags);
    if (pCurGuide)
        pCurGuide->OnButtonDown(&gp);

    if (this->CheckUIOption(UI_DISABLE_MOUSE_RIGHT))
        return;

    if (this->GetOperator())
        this->GetOperator()->OnRButtonDown(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnRButtonUp(UINT nFlags, POINT point)
{
    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_RBUTTON, FALSE, nFlags);
    if (pCurGuide)
        pCurGuide->OnButtonUp(&gp);

    if (this->CheckUIOption(UI_DISABLE_MOUSE_RIGHT))
        return;

    if (this->GetOperator())
        this->GetOperator()->OnRButtonUp(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnMButtonDown(UINT nFlags, POINT point)
{
    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_MBUTTON, TRUE, nFlags);
    if (pCurGuide)
        pCurGuide->OnButtonDown(&gp);

    if (this->GetOperator())
        this->GetOperator()->OnMButtonDown(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnMButtonUp(UINT nFlags, POINT point)
{
    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_MBUTTON, FALSE, nFlags);
    if (pCurGuide)
        pCurGuide->OnButtonUp(&gp);

    if (this->GetOperator())
        this->GetOperator()->OnMButtonUp(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnMButtonDblClk(UINT nFlags, POINT point)
{
    if (this->GetOperator())
        this->GetOperator()->OnMButtonDblClk(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnLButtonDblClk(UINT nFlags, POINT point)
{
    this->MainModule()->OnLButtonDblClk(nFlags, point.x, point.y);

    if (this->GetOperator())
        this->GetOperator()->OnLButtonDblClk(nFlags, point.x, point.y);
}

void PEViewQtPrivate::OnMouseMove(UINT nFlags, POINT point)
{
    CVsGuide *pCurGuide = this->MainModule()->CurrentGuide();
    GUIDE_PARAM gp;
    SetMouseGuideParam(gp, point.x, point.y, MK_LBUTTON, TRUE, nFlags);
    if (pCurGuide)
        pCurGuide->OnMove(&gp);

    this->MainModule()->OnMouseMove(nFlags, point.x, point.y);

#if VS_PLATFORM == VS_PLATFORM_WIN32
    // 如果有旋钮则不执行操作
    if ((!this->CheckUIOption(UI_DISABLE_OPERATOR_TEMP) && !this->CheckUIOption(UI_DISABLE_OPERATOR)) && this->GetOperator())
        this->GetOperator()->OnMouseMove(nFlags, point.x, point.y);

    this->m_tEventMgr.OnMouseMove(nFlags, point.x, point.y);

    if (this->CheckUIOption(UI_DISABLE_OPERATOR_TEMP))
        this->ResetUIOption(UI_DISABLE_OPERATOR_TEMP); // 取消临时屏蔽操作

    if (!m_bMouseTracking)
    {
        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(TRACKMOUSEEVENT);
        tme.dwFlags = TME_LEAVE;
        tme.hwndTrack = m_hWnd;
        tme.dwHoverTime = HOVER_DEFAULT;
        m_bMouseTracking = TrackMouseEvent(&tme);
    }
#elif VS_PLATFORM == VS_PLATFORM_LINUX
    if ((!this->CheckUIOption(UI_DISABLE_OPERATOR_TEMP) && !this->CheckUIOption(UI_DISABLE_OPERATOR)) && this->GetOperator())
        this->GetOperator()->OnMouseMove(nFlags, point.x, point.y);

    this->m_tEventMgr.OnMouseMove(nFlags, point.x, point.y);

    if (this->CheckUIOption(UI_DISABLE_OPERATOR_TEMP))
        this->ResetUIOption(UI_DISABLE_OPERATOR_TEMP); // 取消临时屏蔽操作
#endif
}

void PEViewQtPrivate::OnMouseLeave()
{
#if VS_PLATFORM == VS_PLATFORM_WIN32
    while (ShowCursor(TRUE) < 0)
        ;
    m_bMouseTracking = FALSE;

    if (this->GetUserCursor())
    {
        this->GetUserCursor()->Show(FALSE);
    }

#elif VS_PLATFORM == VS_PLATFORM_LINUX
    // todo
#endif
}

void PEViewQtPrivate::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{

    this->MainModule()->OnKeyDown(nChar, nRepCnt, nFlags);

    if (this->GetOperator())
        this->GetOperator()->OnKeyDown(nChar, nRepCnt, nFlags);

    this->NotifyKeyDown(nChar, nRepCnt, nFlags);

    if (!this->CheckUIOption(UI_DISABLE_DEBUG) && nChar == VK_PAUSE)
    {
        this->SetDebugBreak("");
    }
#if VS_PLATFORM == VS_PLATFORM_WIN32
    switch (nChar)
    {
    case VK_ESCAPE:
    {
        if (m_3dMode != 0)
        {
            //
            /// 退出全屏
            int screen_width = ::GetSystemMetrics(SM_CXSCREEN);
            int screen_height = ::GetSystemMetrics(SM_CYSCREEN);

            RECT frame_rect;
            frame_rect.bottom = screen_height;
            frame_rect.right = screen_width;

            frame_rect.top = 0;
            frame_rect.left = 0;

            if (m_3dMode == 1)
            {
                float viewport1[] = {-1, -1, 1, 1};
                VsSetViewport("main", viewport1);
                VsDeleteViewport("sys_3d_right");
                VsSetOptionValuei("stereo", 0);

                VsSetOptionValuef("perspective scale", 1.f);
                VsInvalidate();
            }

            m_3dMode = 0;
        }
    }
    break;

    case 'k':
    case 'K':
    {
        if (m_3dMode == 1)
        {
            float eyeDistance;
            VsShowOptionValuef("eye distance", eyeDistance);
            VsSetViewportFollow("sys_3d_right", "main", 0, eyeDistance);
            VsInvalidate();
        }
    }
    break;

    case 'l':
    case 'L':
    {
        if (m_3dMode == 1)
        {
            float eyeDistance;
            VsShowOptionValuef("eye distance", eyeDistance);
            VsSetViewportFollow("sys_3d_right", "main", 0, eyeDistance);
            VsInvalidate();
        }
    }
    break;
    }
#elif VS_PLATFORM == VS_PLATFORM_LINUX
    // todo
#endif
}

void PEViewQtPrivate::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    this->MainModule()->OnKeyUp(nChar, nRepCnt, nFlags);

    if (this->GetOperator())
        this->GetOperator()->OnKeyUp(nChar, nRepCnt, nFlags);
}

void PEViewQtPrivate::OnContextMenu(POINT point)
{
    CVsFunction *pFunc = (CVsFunction *)this->MainModule()->FindProgram("local")->FindFunction("OnContextMenu");

    if (pFunc)
    {

        POINT pt = point;
        ::ScreenToClient(m_hWnd, &pt);
        m_rclikPoint = point;

        VS_KEY key = VsPickModel(pt.x, pt.y, VS_PICK_FIELD);

        if (!this->IsSelected(key))
        {
            this->DeSelectAll();
            this->Select(key);
        }

        VsInvalidate();

        VariableList vars;
        CVsVariable varHwnd(VAR_DWORD_PTR);
        vars.push_back(&varHwnd);
        varHwnd.SetDword((DWORD_PTR)m_hWnd);

        CVsVariable varX(VAR_INT);
        vars.push_back(&varX);
        varX.SetInt(point.x);
        CVsVariable varY(VAR_INT);
        vars.push_back(&varY);
        varY.SetInt(point.y);

        pFunc->Instance(vars);
        pFunc->Execute();
    }
}
