/*
    Visual Transform NUI Window
    Created By: Daz
*/

#include "inc_nui"

const string VT_WINDOW_ID                       = "VT";
const string VT_WINDOW_JSON                     = "VT_WINDOW_JSON";
const string VT_WINDOW_GEOMETRY                 = "VT_WINDOW_GEOMETRY";

const string VT_VALUE_BIND_PREFIX               = "vt_value_";
const string VT_DISPLAY_BIND_PREFIX             = "vt_display_";
const string VT_CLEAR_BUTTON_ID_PREFIX          = "vt_btn_clear_";

const string VT_TARGET_BUTTON_ID                = "vt_btn_target";
const string VT_CURRENT_TARGET                  = "VT_CURRENT_TARGET";
const string VT_TARGETING_MODE                  = "VT_TARGETING_MODE";

const float VT_SCALE_MIN                        = 1.0f;
const float VT_SCALE_MAX                        = 10.0f;
const float VT_SCALE_STEP                       = 0.1f;
const float VT_SCALE_DEFAULT                    = 1.0f;

const float VT_ROTATE_MIN                       = 0.0f;
const float VT_ROTATE_MAX                       = 359.0f;
const float VT_ROTATE_STEP                      = 1.0f;

const float VT_TRANSLATE_MIN                    = -10.0f;
const float VT_TRANSLATE_MAX                    = 10.0f;
const float VT_TRANSLATE_STEP                   = 0.1f;

void VT_HandleNUIEvents(object oPlayer, int nToken, string sType, string sElement, int nArrayIndex, json jPayload);
string VT_GetValueBind(int nType);
string VT_GetDisplayBind(int nType);
string VT_GetClearButtonId(int nType);
json VT_CreateVisualTransformRow(string sName, int nType, float fMin, float fMax, float fStep);
void VT_SetValueBindToCurrentValue(object oPlayer, int nToken, int nType);
void VT_ShowWindow(object oPlayer);
void VT_SetCurrentTarget(object oPlayer, object oTarget);
object VT_GetCurrentTarget(object oPlayer);
void VT_DeleteCurrentTarget(object oPlayer);
void VT_EnterTargetMode(object oPlayer);
void VT_HandleTargetEvent(object oPlayer, object oTarget, vector vPosition);

void VT_HandleNUIEvents(object oPlayer, int nToken, string sType, string sElement, int nArrayIndex, json jPayload)
{
    if (sType == NUI_EVENT_CLICK)
    {
        if (sElement == VT_TARGET_BUTTON_ID)
        {
            VT_EnterTargetMode(oPlayer);
        }
        else if (GetStringLeft(sElement, GetStringLength(VT_CLEAR_BUTTON_ID_PREFIX)) == VT_CLEAR_BUTTON_ID_PREFIX)
        {
            int nType = StringToInt(GetStringRight(sElement, 2));
            NuiSetBind(oPlayer, nToken, VT_GetValueBind(nType), JsonFloat(nType == OBJECT_VISUAL_TRANSFORM_SCALE ? VT_SCALE_DEFAULT : 0.0f));
        }
    }
    else if (sType == NUI_EVENT_WATCH)
    {
        if (GetStringLeft(sElement, GetStringLength(VT_VALUE_BIND_PREFIX)) == VT_VALUE_BIND_PREFIX)
        {
            int nType = StringToInt(GetStringRight(sElement, 2));
            float fValue = JsonGetFloat(NuiGetBind(oPlayer, nToken, VT_GetValueBind(nType)));
            object oTarget = VT_GetCurrentTarget(oPlayer);

            SetObjectVisualTransform(oTarget, nType, fValue);

            NuiSetBind(oPlayer, nToken, VT_GetDisplayBind(nType), JsonString(FloatToString(fValue, 2, 1)));
        }
        else if (sElement == NUI_WINDOW_GEOMETRY_BIND)
        {
            SetLocalJson(oPlayer, VT_WINDOW_GEOMETRY, NuiGetBind(oPlayer, nToken, NUI_WINDOW_GEOMETRY_BIND));
        }
    }
    else if (sType == NUI_EVENT_MOUSESCROLL)
    {
        if (GetStringLeft(sElement, GetStringLength(VT_VALUE_BIND_PREFIX)) == VT_VALUE_BIND_PREFIX)
        {
            int nType = StringToInt(GetStringRight(sElement, 2));
            float fDelta = NuiGetMouseScrollDelta(jPayload);

            float fStep;
            switch (nType)
            {
                case OBJECT_VISUAL_TRANSFORM_SCALE:
                    fStep = VT_SCALE_STEP;
                    break;
                case OBJECT_VISUAL_TRANSFORM_ROTATE_X:
                case OBJECT_VISUAL_TRANSFORM_ROTATE_Y:
                case OBJECT_VISUAL_TRANSFORM_ROTATE_Z:
                    fStep = VT_ROTATE_STEP;
                    break;
                case OBJECT_VISUAL_TRANSFORM_TRANSLATE_X:
                case OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y:
                case OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z:
                    fStep = VT_TRANSLATE_STEP;
                    break;
            }

            float fCurrentValue = JsonGetFloat(NuiGetBind(oPlayer, nToken, sElement));
            NuiSetBind(oPlayer, nToken, sElement, JsonFloat(fCurrentValue + (fDelta > 0.0f ? fStep : -fStep)));
        }
    }
    else if (sType == NUI_EVENT_CLOSE)
    {
        if (sElement == NUI_WINDOW_ROOT_GROUP)
        {
            VT_DeleteCurrentTarget(oPlayer);
        }
    }
}

string VT_GetValueBind(int nType)
{
    return VT_VALUE_BIND_PREFIX + IntToString(nType);
}

string VT_GetDisplayBind(int nType)
{
    return VT_DISPLAY_BIND_PREFIX + IntToString(nType);
}

string VT_GetClearButtonId(int nType)
{
    return VT_CLEAR_BUTTON_ID_PREFIX + IntToString(nType);
}

json VT_CreateVisualTransformRow(string sName, int nType, float fMin, float fMax, float fStep)
{
    json jRow = JsonArray();

    json jLabel = NuiLabel(JsonString(sName), JsonInt(NUI_HALIGN_LEFT), JsonInt(NUI_VALIGN_MIDDLE));
         jLabel = NuiWidth(jLabel, 100.0f);
    jRow = JsonArrayInsert(jRow, jLabel);

    jRow = JsonArrayInsert(jRow, NuiSpacer());

    json jSlider = NuiSliderFloat(NuiBind(VT_GetValueBind(nType)), JsonFloat(fMin), JsonFloat(fMax), JsonFloat(fStep));
         jSlider = NuiId(jSlider, VT_GetValueBind(nType));
         jSlider = NuiWidth(jSlider, 175.0f);
    jRow = JsonArrayInsert(jRow, jSlider);

    json jText = NuiTextEdit(JsonString(""), NuiBind(VT_GetDisplayBind(nType)), 10, FALSE);
         jText = NuiEnabled(jText, JsonBool(FALSE));
         jText = NuiWidth(jText, 75.0f);
    jRow = JsonArrayInsert(jRow, jText);

    json jButtonClear = NuiButton(JsonString("X"));
         jButtonClear = NuiId(jButtonClear, VT_GetClearButtonId(nType));
         jButtonClear = NuiWidth(jButtonClear, 35.0f);
         jButtonClear = NuiHeight(jButtonClear, 35.0f);
    jRow = JsonArrayInsert(jRow, jButtonClear);

    return NuiRow(jRow);
}

void VT_SetValueBindToCurrentValue(object oPlayer, int nToken, int nType)
{
    object oTarget = VT_GetCurrentTarget(oPlayer);
    NuiSetBind(oPlayer, nToken, VT_GetValueBind(nType), JsonFloat(GetObjectVisualTransform(oTarget, nType)));
}

void VT_ShowWindow(object oPlayer)
{
    int nToken = NuiFindWindow(oPlayer, VT_WINDOW_ID);

    if (nToken)
        return;

    object oModule = GetModule();
    json jWindow = GetLocalJson(oModule, VT_WINDOW_JSON);
    if (!JsonGetType(jWindow))
    {
        json jCol;
        json jRow;

        jCol = JsonArray();

        jRow = JsonArray();
        {
            jRow = JsonArrayInsert(jRow, NuiSpacer());

            json jButtonTarget = NuiButton(JsonString("Target"));
                 jButtonTarget = NuiId(jButtonTarget, VT_TARGET_BUTTON_ID);
                 jButtonTarget = NuiWidth(jButtonTarget, 100.0f);
                 jButtonTarget = NuiHeight(jButtonTarget, 35.0f);
            jRow = JsonArrayInsert(jRow, jButtonTarget);

        }
        jCol = JsonArrayInsert(jCol, NuiRow(jRow));

        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Scale", OBJECT_VISUAL_TRANSFORM_SCALE, VT_SCALE_MIN, VT_SCALE_MAX, VT_SCALE_STEP));
        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Rotate X", OBJECT_VISUAL_TRANSFORM_ROTATE_X, VT_ROTATE_MIN, VT_ROTATE_MAX, VT_ROTATE_STEP));
        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Rotate Y", OBJECT_VISUAL_TRANSFORM_ROTATE_Y, VT_ROTATE_MIN, VT_ROTATE_MAX, VT_ROTATE_STEP));
        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Rotate Z", OBJECT_VISUAL_TRANSFORM_ROTATE_Z, VT_ROTATE_MIN, VT_ROTATE_MAX, VT_ROTATE_STEP));
        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Translate X", OBJECT_VISUAL_TRANSFORM_TRANSLATE_X, VT_TRANSLATE_MIN, VT_TRANSLATE_MAX, VT_TRANSLATE_STEP));
        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Translate Y", OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y, VT_TRANSLATE_MIN, VT_TRANSLATE_MAX, VT_TRANSLATE_STEP));
        jCol = JsonArrayInsert(jCol, VT_CreateVisualTransformRow("Translate Z", OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z, VT_TRANSLATE_MIN, VT_TRANSLATE_MAX, VT_TRANSLATE_STEP));

        jRow = JsonArray();
        {
            jRow = JsonArrayInsert(jRow, NuiSpacer());
        }
        jCol = JsonArrayInsert(jCol, NuiRow(jRow));

        json jRoot = NuiCol(jCol);
        jWindow = NuiWindow(jRoot, NuiBind(NUI_WINDOW_TITLE_BIND), NuiBind(NUI_WINDOW_GEOMETRY_BIND), JsonBool(FALSE), JsonNull(), JsonBool(TRUE), JsonBool(FALSE), JsonBool(TRUE));
        SetLocalJson(oModule, VT_WINDOW_JSON, jWindow);
    }

    nToken = NuiCreate(oPlayer, jWindow, VT_WINDOW_ID);

    json jGeometry = GetLocalJson(oPlayer, VT_WINDOW_GEOMETRY);
    if (!JsonGetType(jGeometry))
        jGeometry = NuiGetCenteredGeometryRect(oPlayer, 450.0f, 425.0f);

    VT_SetCurrentTarget(oPlayer, oPlayer);

    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_SCALE), TRUE);
    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_ROTATE_X), TRUE);
    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_ROTATE_Y), TRUE);
    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_ROTATE_Z), TRUE);
    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_TRANSLATE_X), TRUE);
    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y), TRUE);
    NuiSetBindWatch(oPlayer, nToken, VT_GetValueBind(OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z), TRUE);

    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_SCALE);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_ROTATE_X);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_ROTATE_Y);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_ROTATE_Z);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_TRANSLATE_X);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z);

    NuiSetBindWatch(oPlayer, nToken, NUI_WINDOW_GEOMETRY_BIND, TRUE);
    NuiSetBind(oPlayer, nToken, NUI_WINDOW_GEOMETRY_BIND, jGeometry);
    NuiSetBind(oPlayer, nToken, NUI_WINDOW_TITLE_BIND, JsonString("Visually Transforming: " + GetName(oPlayer)));
}

void VT_SetCurrentTarget(object oPlayer, object oTarget)
{
    SetLocalObject(oPlayer, VT_CURRENT_TARGET, oTarget);
}

object VT_GetCurrentTarget(object oPlayer)
{
    return GetLocalObject(oPlayer, VT_CURRENT_TARGET);
}

void VT_DeleteCurrentTarget(object oPlayer)
{
    DeleteLocalObject(oPlayer, VT_CURRENT_TARGET);
}

void VT_EnterTargetMode(object oPlayer)
{
    SetLocalInt(oPlayer, VT_TARGETING_MODE, TRUE);
    EnterTargetingMode(oPlayer, OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR | OBJECT_TYPE_TILE);
}

void VT_HandleTargetEvent(object oPlayer, object oTarget, vector vPosition)
{
    if (!GetLocalInt(oPlayer, VT_TARGETING_MODE))
        return;

    DeleteLocalInt(oPlayer, VT_TARGETING_MODE);

    if (!GetIsObjectValid(oTarget))
        return;

    if (GetArea(oPlayer) == oTarget)
    {
        oTarget = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR, Location(oTarget, vPosition, 0.0f));

        if (!GetIsObjectValid(oTarget))
            return;
    }
    else
    {
        int nObjectType = GetObjectType(oTarget);

        if (nObjectType != OBJECT_TYPE_CREATURE &&
            nObjectType != OBJECT_TYPE_PLACEABLE &&
            nObjectType != OBJECT_TYPE_DOOR)
            return;
    }

    int nToken = NuiFindWindow(oPlayer, VT_WINDOW_ID);

    if (!nToken)
        return;

    VT_SetCurrentTarget(oPlayer, oTarget);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_SCALE);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_ROTATE_X);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_ROTATE_Y);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_ROTATE_Z);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_TRANSLATE_X);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Y);
    VT_SetValueBindToCurrentValue(oPlayer, nToken, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z);
    NuiSetBind(oPlayer, nToken, NUI_WINDOW_TITLE_BIND, JsonString("Visually Transforming: " + GetName(oTarget)));
}