#include "..\Public\UE4ComCommon.h"

namespace Ventuz
{
namespace UE4
{

// return true if the hash value has changed
bool SharedDatabase::HandleMessage(unsigned char* message, int _length, uint& hash)
{
    AncID fourcc = *((AncID*)message);
    unsigned char* data = message + 4;
    int length = _length - 4;

    switch (fourcc)
    {
    case AncID::CameraMatrix:
    {
        memcpy(cameraMatrix, data, length);
        matricesUpdated = true;
        break;
    }
    case AncID::ProjectionMatrix:
    {
        memcpy(projectionMatrix, data, length);
        matricesUpdated = true;
        break;
    }
    case AncID::Event:
    {
        FromVentuzEvent* event = (FromVentuzEvent*)data;
        events.emplace_back(*event);
        hash = event->paramHash;
        return true;
    }
    case AncID::IntValue:
    {
        FromVentuzInt* intData = (FromVentuzInt*)data;
        intValues[intData->paramHash] = intData->value;
        hash = intData->paramHash;
        return true;
    }
    case AncID::FloatValue:
    {
        FromVentuzFloat* floatData = (FromVentuzFloat*)data;
        floatValues[floatData->paramHash] = floatData->value;
        hash = floatData->paramHash;
        return true;
    }
    case AncID::StringValue:
    {
        hash = ((uint*)data)[0];
        stringValues[hash] = std::string((char*)data + 4, length - 4);
        return true;
    }
    case AncID::BoolValue:
    {
        FromVentuzBool* boolData = (FromVentuzBool*)data;
        boolValues[boolData->paramHash] = boolData->value;
        hash = boolData->paramHash;
        return true;
    }
    case AncID::TransformValue:
    {
        FromVentuzMatrix* transformData = (FromVentuzMatrix*)data;

        if (transformData->nodeID != GUID{})
        {
            auto transformByGUID = transformValuesByGUID.find(transformData->nodeID);
            if (transformByGUID != transformValuesByGUID.end())
            {
                if (memcmp(&(*transformByGUID).second, transformData->value, 16 * sizeof(float)))
                    updatedTransformValues.emplace_back(transformData->nodeID);
            }

            memcpy(&transformValuesByGUID[transformData->nodeID], transformData->value, 16 * sizeof(float));
        }

        if (transformData->paramHash)
        {
            memcpy(transformValues[transformData->paramHash], transformData->value, 16 * sizeof(float));
            hash = transformData->paramHash;
            return true;
        }
        break;
    }
    case AncID::IntArray:
    {
        FromVentuzInt* intData = (FromVentuzInt*)data;
        std::vector<int>& intArray = intArrays[intData->paramHash];

        intArray.clear();
        for (int y = 0; y < (length - sizeof(uint)) / sizeof(int); y++)
            intArray.emplace_back((&(intData->value))[y]);
        hash = intData->paramHash;
        return true;
    }
    case AncID::FloatArray:
    {
        FromVentuzFloat* floatData = (FromVentuzFloat*)data;

        std::vector<float>& floatArray = floatArrays[floatData->paramHash];

        floatArray.clear();
        for (int y = 0; y < (length - sizeof(uint)) / sizeof(float); y++)
            floatArray.emplace_back((&(floatData->value))[y]);
        hash = floatData->paramHash;
        return true;
    }
    case AncID::BoolArray:
    {
        FromVentuzBool* boolData = (FromVentuzBool*)data;
        std::vector<unsigned char>& boolArray = boolArrays[boolData->paramHash];

        boolArray.clear();
        for (int y = 0; y < (length - sizeof(uint)) / sizeof(bool); y++)
            boolArray.emplace_back((&(boolData->value))[y]);
        hash = boolData->paramHash;
        return true;
    }
    case AncID::StringArray:
    {
        char* stringData = (char*)data;

        hash = ((uint*)stringData)[0];

        char* strings = stringData + 4;

        int len = MultiByteToWideChar(CP_ACP, 0, strings, length - 4, 0, 0);
        if (!len)
            break;

        std::vector<wchar_t> wbuff(len + 1);
        if (!MultiByteToWideChar(CP_ACP, 0, strings, length - 4, &wbuff[0], len))
            break;

        stringArrays[hash] = std::wstring(&wbuff[0], len);
        return true;
    }
    case AncID::InputData:
    {
        int size = ((int*)data)[0];

        inputBundles.emplace_back(std::string((char*)data + 4, size));
        return false;
    }
    case AncID::Viewports:
    {
        memcpy(&viewportData,data,length);
        return false;
    }
    case AncID::AlphaType:
    {
        memcpy( &alphaMode, data, length );
        return false;
    }
    case AncID::UnrealVersion:
    {
        memcpy( &unrealVersion, data, length );
        return false;
    }

    default:
        break;
    }

    return false;
}

void SharedDatabase::Reset()
{
    inputBundles.clear();

    events.clear();
    intValues.clear();
    floatValues.clear();
    stringValues.clear();
    boolValues.clear();
    colorValues.clear();
    transformValues.clear();
    transformValuesByGUID.clear();

    intArrays.clear();
    floatArrays.clear();
    stringArrays.clear();
    boolArrays.clear();

    memset(&viewportData,0,sizeof(ViewportData));
}

}
}
