/*
 * Copyright (C) 2014 Apple Inc. All rights reserved.
 *
 * 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.
 */

#ifndef IDBKeyData_h
#define IDBKeyData_h

#if ENABLE(INDEXED_DATABASE)

#include "IDBKey.h"
#include <wtf/text/StringHash.h>

namespace WebCore {

class KeyedDecoder;
class KeyedEncoder;

class IDBKeyData {
public:
    IDBKeyData()
        : m_type(KeyType::Invalid)
        , m_isNull(true)
    {
    }

    WEBCORE_EXPORT IDBKeyData(const IDBKey*);

    static IDBKeyData minimum()
    {
        IDBKeyData result;
        result.m_type = KeyType::Min;
        result.m_isNull = false;
        return result;
    }

    static IDBKeyData maximum()
    {
        IDBKeyData result;
        result.m_type = KeyType::Max;
        result.m_isNull = false;
        return result;
    }

    WEBCORE_EXPORT PassRefPtr<IDBKey> maybeCreateIDBKey() const;

    IDBKeyData isolatedCopy() const;

    WEBCORE_EXPORT void encode(KeyedEncoder&) const;
    WEBCORE_EXPORT static bool decode(KeyedDecoder&, IDBKeyData&);

    // compare() has the same semantics as strcmp().
    //   - Returns negative if this IDBKeyData is less than other.
    //   - Returns positive if this IDBKeyData is greater than other.
    //   - Returns zero if this IDBKeyData is equal to other.
    WEBCORE_EXPORT int compare(const IDBKeyData& other) const;

    void setArrayValue(const Vector<IDBKeyData>&);
    void setStringValue(const String&);
    void setDateValue(double);
    WEBCORE_EXPORT void setNumberValue(double);

    template<class Encoder> void encode(Encoder&) const;
    template<class Decoder> static bool decode(Decoder&, IDBKeyData&);
    
#ifndef NDEBUG
    WEBCORE_EXPORT String loggingString() const;
#endif

    bool isNull() const { return m_isNull; }
    bool isValid() const { return m_type != KeyType::Invalid; }
    KeyType type() const { return m_type; }

    bool operator<(const IDBKeyData&) const;
    bool operator==(const IDBKeyData& other) const;
    bool operator!=(const IDBKeyData& other) const
    {
        return !(*this == other);
    }

    unsigned hash() const
    {
        Vector<unsigned> hashCodes;
        hashCodes.append(static_cast<unsigned>(m_type));
        hashCodes.append(m_isNull ? 1 : 0);
        hashCodes.append(m_isDeletedValue ? 1 : 0);
        switch (m_type) {
        case KeyType::Invalid:
        case KeyType::Max:
        case KeyType::Min:
            break;
        case KeyType::Number:
        case KeyType::Date:
            hashCodes.append(StringHasher::hashMemory<sizeof(double)>(&m_numberValue));
            break;
        case KeyType::String:
            hashCodes.append(StringHash::hash(m_stringValue));
            break;
        case KeyType::Array:
            for (auto& key : m_arrayValue)
                hashCodes.append(key.hash());
            break;
        }

        return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
    }

    static IDBKeyData deletedValue();
    bool isDeletedValue() const { return m_isDeletedValue; }

    String string() const
    {
        ASSERT(m_type == KeyType::String);
        return m_stringValue;
    }

    double date() const
    {
        ASSERT(m_type == KeyType::Date);
        return m_numberValue;
    }

    double number() const
    {
        ASSERT(m_type == KeyType::Number);
        return m_numberValue;
    }

    const Vector<IDBKeyData>& array() const
    {
        ASSERT(m_type == KeyType::Array);
        return m_arrayValue;
    }

private:
    KeyType m_type;
    Vector<IDBKeyData> m_arrayValue;
    String m_stringValue;
    double m_numberValue { 0 };
    bool m_isNull { false };
    bool m_isDeletedValue { false };
};

struct IDBKeyDataHash {
    static unsigned hash(const IDBKeyData& a) { return a.hash(); }
    static bool equal(const IDBKeyData& a, const IDBKeyData& b) { return a == b; }
    static const bool safeToCompareToEmptyOrDeleted = false;
};

struct IDBKeyDataHashTraits : public WTF::CustomHashTraits<IDBKeyData> {
    static const bool emptyValueIsZero = false;
    static const bool hasIsEmptyValueFunction = true;

    static void constructDeletedValue(IDBKeyData& key)
    {
        key = IDBKeyData::deletedValue();
    }

    static bool isDeletedValue(const IDBKeyData& key)
    {
        return key.isDeletedValue();
    }

    static IDBKeyData emptyValue()
    {
        return IDBKeyData();
    }

    static bool isEmptyValue(const IDBKeyData& key)
    {
        return key.isNull();
    }
};

template<class Encoder>
void IDBKeyData::encode(Encoder& encoder) const
{
    encoder << m_isNull;
    if (m_isNull)
        return;

    encoder.encodeEnum(m_type);

    switch (m_type) {
    case KeyType::Invalid:
        break;
    case KeyType::Array:
        encoder << m_arrayValue;
        break;
    case KeyType::String:
        encoder << m_stringValue;
        break;
    case KeyType::Date:
    case KeyType::Number:
        encoder << m_numberValue;
        break;
    case KeyType::Max:
    case KeyType::Min:
        // MaxType and MinType are only used for comparison to other keys.
        // They should never be encoded/decoded.
        ASSERT_NOT_REACHED();
        break;
    }
}

template<class Decoder>
bool IDBKeyData::decode(Decoder& decoder, IDBKeyData& keyData)
{
    if (!decoder.decode(keyData.m_isNull))
        return false;

    if (keyData.m_isNull)
        return true;

    if (!decoder.decodeEnum(keyData.m_type))
        return false;

    switch (keyData.m_type) {
    case KeyType::Invalid:
        break;
    case KeyType::Array:
        if (!decoder.decode(keyData.m_arrayValue))
            return false;
        break;
    case KeyType::String:
        if (!decoder.decode(keyData.m_stringValue))
            return false;
        break;
    case KeyType::Date:
    case KeyType::Number:
        if (!decoder.decode(keyData.m_numberValue))
            return false;
        break;
    case KeyType::Max:
    case KeyType::Min:
        // MaxType and MinType are only used for comparison to other keys.
        // They should never be encoded/decoded.
        ASSERT_NOT_REACHED();
        decoder.markInvalid();
        return false;
    }

    return true;
}

} // namespace WebCore

#endif // ENABLE(INDEXED_DATABASE)
#endif // IDBKeyData_h
