#include "PlayerKam.h"

#include <Globals.h>

#include "Game.h"
#include "Globals.h"

class MovementFlags
{
public:
    static const int SNEAKING = 0x00001;
    static const int SPRINTING = 0x00002;
    static const int FLYING = 0x00004;
    static const int JUMPING = 0x00008;
    static const int WALK_FORWARD = 0x00010;
    static const int WALK_BACKWARD = 0x00020;
    static const int WALK_LEFT = 0x00040;
    static const int WALK_RIGHT = 0x00080;
    static const int ROTATE_LEFT = 0x00100;
    static const int ROTATE_RIGHT = 0x00200;
    static const int GROUND_CONTACT = 0x01000;
};

PlayerKam::PlayerKam(Framework::Screen3D* zScreen)
    : Cam3D()
{
    kameraControll = 0;
    setScreenPosition(0, 0);
    setScreenSize(zScreen->getBackBufferSize());
    setStyle(
        Cam3D::Style::Tick | Cam3D::Style::Movable | Cam3D::Style::Rotatable);
    setRotation({(float)PI / 2.f, 0, 0});
    lastDirection = {0, 0, 0};
    entityId = -1;
    movementFlags = 0;
    lastMovementFlags = 0;
}

void PlayerKam::setDirection(Framework::Vec3<float> direction)
{
    if (direction.getLengthSq() > 0)
    {
        float rotZ = std::atan2(direction.y, direction.x) + (float)PI / 2;
        setRotation({getRotation().x, getRotation().y, rotZ});
    }
}

void PlayerKam::doKeyboardEvent(Framework::KeyboardEvent& te)
{
    if (!World::INSTANCE)
    {
        return;
    }
    if (te.id == TE_Press)
    {
        if (te.key[0] >= '0' && te.key[0] <= '9')
        {
            char action[5];
            action[0] = 3;
            *(int*)(action + 1) = te.key[0] - '1';
            if (*(int*)(action + 1) < 0) *(int*)(action + 1) = 9;
            World::INSTANCE->zClient()->sendPlayerAction(action, 5);
        }
        if (kameraControll)
        {
            if (te.virtualKey == 'W')
            {
                movementFlags |= MovementFlags::WALK_FORWARD;
            }
            if (te.virtualKey == 'S')
            {
                movementFlags |= MovementFlags::WALK_BACKWARD;
            }
            if (te.virtualKey == 'A')
            {
                movementFlags |= MovementFlags::WALK_LEFT;
            }
            if (te.virtualKey == 'D')
            {
                movementFlags |= MovementFlags::WALK_RIGHT;
            }
            if (te.virtualKey == VK_SPACE)
            {
                movementFlags |= MovementFlags::JUMPING;
            }
            if (te.virtualKey == T_Shift)
            {
                movementFlags |= MovementFlags::SPRINTING;
            }
            if (te.virtualKey == T_Strg)
            {
                movementFlags |= MovementFlags::SNEAKING;
            }
        }
    }
    if (te.id == TE_Release)
    {
        if (te.virtualKey == T_Esc)
        {
            bool oldControl = kameraControll;
            kameraControll = 0;
            movementFlags = 0;
            setShowCursor(true);
            if (!oldControl)
                ((Game*)(Menu*)menuRegister->get("game"))->closeCurrentDialog();
        }
        if (te.virtualKey == T_Tab)
        {
            char action = 4; // open inventory
            World::INSTANCE->zClient()->sendPlayerAction(&action, 1);
        }
        if (te.key[0] == 'q')
        {
            char action = 9; // open quest dialog
            World::INSTANCE->zClient()->sendPlayerAction(&action, 1);
        }
        if (te.key[0] == 'm')
        {
            ((Game*)(Menu*)menuRegister->get("game"))->zMap()->setVisibility(1);
        }
        if (te.virtualKey == 'W')
        {
            movementFlags &= ~MovementFlags::WALK_FORWARD;
        }
        if (te.virtualKey == 'S')
        {
            movementFlags &= ~MovementFlags::WALK_BACKWARD;
        }
        if (te.virtualKey == 'A')
        {
            movementFlags &= ~MovementFlags::WALK_LEFT;
        }
        if (te.virtualKey == 'D')
        {
            movementFlags &= ~MovementFlags::WALK_RIGHT;
        }
        if (te.virtualKey == VK_SPACE)
        {
            movementFlags &= ~MovementFlags::JUMPING;
        }
        if (te.virtualKey == T_Shift)
        {
            movementFlags &= ~MovementFlags::SPRINTING;
        }
        if (te.virtualKey == T_Strg)
        {
            movementFlags &= ~MovementFlags::SNEAKING;
        }
        if (te.key[0] == 'F')
        {
            if (movementFlags & MovementFlags::FLYING)
            {
                movementFlags &= ~MovementFlags::FLYING;
            }
            else
            {
                movementFlags |= MovementFlags::FLYING;
            }
        }
    }
    if (lastMovementFlags != movementFlags)
    {
        World::INSTANCE->zClient()->sendPlayerMovement(movementFlags);
        lastMovementFlags = movementFlags;
    }
}

void PlayerKam::doMouseEvent(Framework::MouseEvent& me)
{
    if (!World::INSTANCE)
    {
        return;
    }
    if (me.processed && me.id != ME_RLeft && me.id != ME_RRight)
    {
        kameraControll = 0;
        setShowCursor(true);
        movementFlags = 0;
    }
    else
    {
        if (!kameraControll && me.id != ME_RLeft && me.id != ME_RRight)
        {
            if (me.id == ME_PLeft) setControlEnabled(1);
        }
        else
        {
            if (kameraControll || me.id == ME_RLeft || me.id == ME_RRight)
            {
                if (me.id == ME_PLeft)
                {
                    char action[2] = {1, 8};
                    World::INSTANCE->zClient()->sendPlayerAction(action, 2);
                }
                if (me.id == ME_RLeft)
                {
                    char action[2] = {0, 8};
                    World::INSTANCE->zClient()->sendPlayerAction(action, 2);
                }
                if (me.id == ME_PRight)
                {
                    char action[2] = {1, 9};
                    World::INSTANCE->zClient()->sendPlayerAction(action, 2);
                }
                if (me.id == ME_RRight)
                {
                    char action[2] = {0, 9};
                    World::INSTANCE->zClient()->sendPlayerAction(action, 2);
                }
            }
        }
        me.processed = 1;
    }
    if (lastMovementFlags != movementFlags)
    {
        World::INSTANCE->zClient()->sendPlayerMovement(movementFlags);
        lastMovementFlags = movementFlags;
    }
}

bool PlayerKam::tick(double time)
{
    if (!World::INSTANCE)
    {
        return 1;
    }
    __int64 style = 0;
    if (hasStyle(Style::Movable)) style |= Style::Movable;
    if (hasStyle(Style::Rotatable)) style |= Style::Rotatable;
    if (hasStyle(Style::Zoomable)) style |= Style::Zoomable;
    removeStyle(Style::Movable | Style::Rotatable | Style::Zoomable);
    bool result = Cam3D::tick(time);
    addStyle(style);
    if (kameraControll)
    {
        Point dir
            = window->getSize() / 2 - (getMousePos() - window->getPosition());
        setRotation(
            {min(max(getRotation().x - dir.y * (float)time * 0.2f, 0.4f), 3.1f),
                getRotation().y,
                getRotation().z - dir.x * (float)time * 0.2f});
        if (getRotation().z > 2 * PI)
            setRotation({getRotation().x,
                getRotation().y,
                getRotation().z - 2.f * (float)PI});
        if (getRotation().z < -2 * PI)
            setRotation({getRotation().x,
                getRotation().y,
                getRotation().z + 2.f * (float)PI});
        SetCursorPos(window->getPosition().x + window->getBodySize().x / 2,
            window->getPosition().y + window->getBodySize().y / 2);
        setShowCursor(false);
        setMousePos(window->getPosition() + window->getSize() / 2);
    }
    Vec3<float> direction = getDirection();
    if (direction != lastDirection)
    {
        World::INSTANCE->zClient()->sendPlayerFaceDirection(direction);
        lastDirection = direction;
    }
    return 1;
}

void PlayerKam::setEntityId(int id)
{
    entityId = id;
}

void PlayerKam::setControlEnabled(bool enabled)
{
    kameraControll = enabled;
    setShowCursor(!kameraControll);
    if (kameraControll)
    {
        SetCursorPos(window->getPosition().x + window->getBodySize().x / 2,
            window->getPosition().y + window->getBodySize().y / 2);
    }
}

int PlayerKam::getEntityId() const
{
    return entityId;
}

Framework::Vec3<float> PlayerKam::getDirection() const
{
    return getWorldDirection(getScreenPos() + getScreenSize() / 2);
}