//  Author: Chris Campbell - www.iforce2d.net
//  -----------------------------------------
//
//  PanZoomScene
//
//  See header file for description.
//

#ifdef _WINDOWS
#include <windows.h>
#endif

#include "PanZoomScene.h"
#include "Window.h"

PanZoomScene::PanZoomScene()
{    
    m_viewCenter.Set(0,0);
    m_viewVerticalSpan = 32;

    m_lmbDown = false;
    m_rmbDown = false;

    m_lmbDownPosPixel.x = 0;
    m_lmbDownPosPixel.y = 0;

    m_rmbDownPosPixel.x = 0;
    m_rmbDownPosPixel.y = 0;

    m_mousePosPixel.x = 0;
    m_mousePosPixel.y = 0;

    m_mousePosWorld.SetZero();
}

PanZoomScene::~PanZoomScene()
{
}

void PanZoomScene::setViewCenter(b2Vec2 center)
{
    m_viewCenter = center;
}

void PanZoomScene::setViewVerticalSpan(float span)
{
    m_viewVerticalSpan = span;
}

float PanZoomScene::pixelToWorldDimension(float pixelDimension)
{
    return pixelDimension * m_viewVerticalSpan / (float)getWindowSize().y;
}

float PanZoomScene::worldToPixelDimension(float worldDimension)
{
    return worldDimension * getWindowSize().y / m_viewVerticalSpan;
}

// Converts a position in screen pixels to a location in the physics world
b2Vec2 PanZoomScene::pixelToWorld(SDL_Point pixelLocation)
{
    SDL_Point windowSize = getWindowSize();
    float ww = windowSize.x;
    float wh = windowSize.y;
    float aspect = ww / (float)wh;
    float viewHorizontalSpan = m_viewVerticalSpan * aspect;

    float xf = pixelLocation.x / (float)ww;
    float yf = (wh - pixelLocation.y) / (float)wh;

    float lx = m_viewCenter.x - 0.5f * viewHorizontalSpan;
    float ly = m_viewCenter.y - 0.5f * m_viewVerticalSpan;
    return b2Vec2( lx + xf * viewHorizontalSpan, ly + yf * m_viewVerticalSpan );
}

// Converts a location in the physics world to a position in screen pixels
SDL_Point PanZoomScene::worldToPixel(b2Vec2 worldLocation)
{
    SDL_Point windowSize = getWindowSize();
    float ww = windowSize.x;
    float wh = windowSize.y;
    float aspect = ww / (float)wh;
    float viewHorizontalSpan = m_viewVerticalSpan * aspect;

    float lx = m_viewCenter.x - 0.5f * viewHorizontalSpan;
    float ly = m_viewCenter.y - 0.5f * m_viewVerticalSpan;

    float xf = (worldLocation.x - lx) / viewHorizontalSpan;
    float yf = (worldLocation.y - ly) / m_viewVerticalSpan;

    SDL_Point p;
    p.x = (int)(xf * ww);
    p.y = (int)(wh - yf * wh);
    //return SDL_Point( xf * ww, wh - yf * wh );
    return p;
}

void PanZoomScene::mouseDown(SDL_MouseButtonEvent mouseButtonEvent)
{
    if ( mouseButtonEvent.button == SDL_BUTTON_LEFT ) {
        m_lmbDown = true;
        m_lmbDownPosPixel.x = mouseButtonEvent.x;
        m_lmbDownPosPixel.y = mouseButtonEvent.y;
    }
    else if ( mouseButtonEvent.button == SDL_BUTTON_RIGHT ) {
        m_rmbDown = true;
        m_rmbDownPosPixel.x = mouseButtonEvent.x;
        m_rmbDownPosPixel.y = mouseButtonEvent.y;
    }
}

void PanZoomScene::mouseUp(SDL_MouseButtonEvent mouseButtonEvent)
{
    if ( mouseButtonEvent.button == SDL_BUTTON_LEFT )
        m_lmbDown = false;
    else if ( mouseButtonEvent.button == SDL_BUTTON_RIGHT )
        m_rmbDown = false;
}

void PanZoomScene::mouseMove(SDL_MouseMotionEvent mouseMoveEvent)
{
    SDL_Point newPosPixel;
    newPosPixel.x = mouseMoveEvent.x;
    newPosPixel.y = mouseMoveEvent.y;
    if ( m_rmbDown ) {
        b2Vec2 delta = m_mousePosWorld - pixelToWorld(newPosPixel);
        setViewCenter( m_viewCenter + delta );
    }

    m_mousePosPixel = newPosPixel;
    m_mousePosWorld = pixelToWorld( m_mousePosPixel );
}

void PanZoomScene::mouseWheel(SDL_MouseWheelEvent mouseWheelEvent)
{
    b2Vec2 oldMousePos = m_mousePosWorld;

    if ( mouseWheelEvent.y < 0 )
        m_viewVerticalSpan *= 1.1f;
    else if ( mouseWheelEvent.y > 0 )
        m_viewVerticalSpan /= 1.1f;

    b2Vec2 newMousePos = pixelToWorld( m_mousePosPixel );
    setViewCenter( m_viewCenter + oldMousePos - newMousePos );
}
