/*
 * Copyright (C) 2018 Sony Interactive Entertainment Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "KeyedDecoderGeneric.h"

#include "KeyedEncoderGeneric.h"
#include <wtf/HashMap.h>
#include <wtf/Variant.h>
#include <wtf/Vector.h>
#include <wtf/persistence/PersistentDecoder.h>
#include <wtf/text/StringHash.h>

namespace WebCore {

class KeyedDecoderGeneric::Dictionary {
    WTF_MAKE_FAST_ALLOCATED;
public:
    using Node = Variant<Vector<uint8_t>, bool, uint32_t, uint64_t, int32_t, int64_t, float, double, String, std::unique_ptr<Dictionary>, std::unique_ptr<Array>>;

    template <typename T>
    void add(const String& key, T&& value) { m_map.add(key, std::make_unique<Node>(std::forward<T>(value))); }
    Node& get(const String& key) { return *m_map.get(key); }

private:
    HashMap<String, std::unique_ptr<Node>> m_map;
};

static bool readString(WTF::Persistence::Decoder& decoder, String& result)
{
    size_t size;
    if (!decoder.decode(size))
        return false;
    Vector<uint8_t> buffer(size);
    if (!decoder.decodeFixedLengthData(buffer.data(), size))
        return false;
    result = String::fromUTF8(buffer.data(), size);
    return true;
}

template<typename T>
static bool readSimpleValue(WTF::Persistence::Decoder& decoder, KeyedDecoderGeneric::Dictionary& dictionary)
{
    String key;
    bool ok = readString(decoder, key);
    if (!ok)
        return false;
    T value;
    ok = decoder.decode(value);
    if (!ok)
        return false;
    dictionary.add(key, WTFMove(value));
    return true;
}

std::unique_ptr<KeyedDecoder> KeyedDecoder::decoder(const uint8_t* data, size_t size)
{
    return std::make_unique<KeyedDecoderGeneric>(data, size);
}

KeyedDecoderGeneric::KeyedDecoderGeneric(const uint8_t* data, size_t size)
{
    WTF::Persistence::Decoder decoder(data, size);
    KeyedEncoderGeneric::Type type;
    String key;

    m_rootDictionary = std::make_unique<Dictionary>();
    m_dictionaryStack.append(m_rootDictionary.get());

    bool ok = true;
    while (ok && decoder.decodeEnum(type)) {
        switch (type) {
        case KeyedEncoderGeneric::Type::Bytes: {
            ok = readString(decoder, key);
            if (!ok)
                break;
            size_t size;
            ok = decoder.decode(size);
            if (!ok)
                break;
            Vector<uint8_t> buffer(size);
            ok = decoder.decodeFixedLengthData(buffer.data(), size);
            if (!ok)
                break;
            m_dictionaryStack.last()->add(key, WTFMove(buffer));
            break;
        }
        case KeyedEncoderGeneric::Type::Bool:
            ok = readSimpleValue<bool>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::UInt32:
            ok = readSimpleValue<uint32_t>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::UInt64:
            ok = readSimpleValue<uint64_t>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::Int32:
            ok = readSimpleValue<int32_t>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::Int64:
            ok = readSimpleValue<int64_t>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::Float:
            ok = readSimpleValue<float>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::Double:
            ok = readSimpleValue<double>(decoder, *m_dictionaryStack.last());
            break;
        case KeyedEncoderGeneric::Type::String: {
            ok = readString(decoder, key);
            if (!ok)
                break;
            String value;
            ok = readString(decoder, value);
            if (!ok)
                break;
            m_dictionaryStack.last()->add(key, WTFMove(value));
            break;
        }
        case KeyedEncoderGeneric::Type::BeginObject: {
            ok = readString(decoder, key);
            if (!ok)
                break;
            auto* currentDictinary = m_dictionaryStack.last();
            auto newDictionary = std::make_unique<Dictionary>();
            m_dictionaryStack.append(newDictionary.get());
            currentDictinary->add(key, WTFMove(newDictionary));
            break;
        }
        case KeyedEncoderGeneric::Type::EndObject:
            m_dictionaryStack.removeLast();
            break;
        case KeyedEncoderGeneric::Type::BeginArray: {
            ok = readString(decoder, key);
            if (!ok)
                break;
            auto newArray = std::make_unique<Array>();
            m_arrayStack.append(newArray.get());
            m_dictionaryStack.last()->add(key, WTFMove(newArray));
            break;
        }
        case KeyedEncoderGeneric::Type::BeginArrayElement: {
            auto newDictionary = std::make_unique<Dictionary>();
            m_dictionaryStack.append(newDictionary.get());
            m_arrayStack.last()->append(WTFMove(newDictionary));
            break;
        }
        case KeyedEncoderGeneric::Type::EndArrayElement:
            m_dictionaryStack.removeLast();
            break;
        case KeyedEncoderGeneric::Type::EndArray:
            m_arrayStack.removeLast();
            break;
        }
    }
    while (m_dictionaryStack.size() > 1)
        m_dictionaryStack.removeLast();
    while (!m_arrayStack.isEmpty())
        m_arrayStack.removeLast();
}

bool KeyedDecoderGeneric::decodeBytes(const String& key, const uint8_t*& data, size_t& size)
{
    auto* value = WTF::get_if<Vector<uint8_t>>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    data = value->data();
    size = value->size();
    return true;
}

bool KeyedDecoderGeneric::decodeBool(const String& key, bool& result)
{
    auto* value = WTF::get_if<bool>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeUInt32(const String& key, uint32_t& result)
{
    auto* value = WTF::get_if<uint32_t>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeUInt64(const String& key, uint64_t& result)
{
    auto* value = WTF::get_if<uint64_t>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeInt32(const String& key, int32_t& result)
{
    auto* value = WTF::get_if<int32_t>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeInt64(const String& key, int64_t& result)
{
    auto* value = WTF::get_if<int64_t>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeFloat(const String& key, float& result)
{
    auto* value = WTF::get_if<float>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeDouble(const String& key, double& result)
{
    auto* value = WTF::get_if<double>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::decodeString(const String& key, String& result)
{
    auto* value = WTF::get_if<String>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    result = *value;
    return true;
}

bool KeyedDecoderGeneric::beginObject(const String& key)
{
    auto* value = WTF::get_if<std::unique_ptr<Dictionary>>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    m_dictionaryStack.append(value->get());
    return true;
}

void KeyedDecoderGeneric::endObject()
{
    m_dictionaryStack.removeLast();
}

bool KeyedDecoderGeneric::beginArray(const String& key)
{
    auto* value = WTF::get_if<std::unique_ptr<Array>>(m_dictionaryStack.last()->get(key));
    if (!value)
        return false;
    m_arrayStack.append(value->get());
    m_arrayIndexStack.append(0);
    return true;
}

bool KeyedDecoderGeneric::beginArrayElement()
{
    if (m_arrayIndexStack.last() >= m_arrayStack.last()->size())
        return false;

    auto dictionary = m_arrayStack.last()->at(m_arrayIndexStack.last()++).get();
    m_dictionaryStack.append(dictionary);
    return true;
}

void KeyedDecoderGeneric::endArrayElement()
{
    m_dictionaryStack.removeLast();
}

void KeyedDecoderGeneric::endArray()
{
    m_arrayStack.removeLast();
    m_arrayIndexStack.removeLast();
}

} // namespace WebCore
