/*
 * Copyright (C) 2008 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. ``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
 * 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 "StorageMap.h"

#if ENABLE(DOM_STORAGE)

namespace WebCore {

PassRefPtr<StorageMap> StorageMap::create(unsigned quota)
{
    return adoptRef(new StorageMap(quota));
}

StorageMap::StorageMap(unsigned quota)
    : m_iterator(m_map.end())
    , m_iteratorIndex(UINT_MAX)
    , m_quotaSize(quota)  // quota measured in bytes
    , m_currentLength(0)
{
}

PassRefPtr<StorageMap> StorageMap::copy()
{
    RefPtr<StorageMap> newMap = create(m_quotaSize);
    newMap->m_map = m_map;
    newMap->m_currentLength = m_currentLength;
    return newMap.release();
}

void StorageMap::invalidateIterator()
{
    m_iterator = m_map.end();
    m_iteratorIndex = UINT_MAX;
}

void StorageMap::setIteratorToIndex(unsigned index)
{
    // FIXME: Once we have bidirectional iterators for HashMap we can be more intelligent about this.
    // The requested index will be closest to begin(), our current iterator, or end(), and we
    // can take the shortest route.
    // Until that mechanism is available, we'll always increment our iterator from begin() or current.

    if (m_iteratorIndex == index)
        return;

    if (index < m_iteratorIndex) {
        m_iteratorIndex = 0;
        m_iterator = m_map.begin();
        ASSERT(m_iterator != m_map.end());
    }

    while (m_iteratorIndex < index) {
        ++m_iteratorIndex;
        ++m_iterator;
        ASSERT(m_iterator != m_map.end());
    }
}

unsigned StorageMap::length() const
{
    return m_map.size();
}

String StorageMap::key(unsigned index)
{
    if (index >= length())
        return String();

    setIteratorToIndex(index);
    return m_iterator->first;
}

String StorageMap::getItem(const String& key) const
{
    return m_map.get(key);
}

PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue, bool& quotaException)
{
    ASSERT(!value.isNull());
    quotaException = false;

    // Implement copy-on-write semantics here.  We're guaranteed that the only refs of StorageMaps belong to Storage objects
    // so if more than one Storage object refs this map, copy it before mutating it.
    if (refCount() > 1) {
        RefPtr<StorageMap> newStorageMap = copy();
        newStorageMap->setItem(key, value, oldValue, quotaException);
        return newStorageMap.release();
    }

    // Quota tracking.  This is done in a couple of steps to keep the overflow tracking simple.
    unsigned newLength = m_currentLength;
    bool overflow = newLength + value.length() < newLength;
    newLength += value.length();

    oldValue = m_map.get(key);
    overflow |= newLength - oldValue.length() > newLength;
    newLength -= oldValue.length();

    unsigned adjustedKeyLength = oldValue.isNull() ? key.length() : 0;
    overflow |= newLength + adjustedKeyLength < newLength;
    newLength += adjustedKeyLength;

    ASSERT(!overflow);  // Overflow is bad...even if quotas are off.
    bool overQuota = newLength > m_quotaSize / sizeof(UChar);
    if (m_quotaSize != noQuota && (overflow || overQuota)) {
        quotaException = true;
        return 0;
    }
    m_currentLength = newLength;

    pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
    if (!addResult.second)
        addResult.first->second = value;

    invalidateIterator();

    return 0;
}

PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValue)
{
    // Implement copy-on-write semantics here.  We're guaranteed that the only refs of StorageMaps belong to Storage objects
    // so if more than one Storage object refs this map, copy it before mutating it.
    if (refCount() > 1) {
        RefPtr<StorageMap> newStorage = copy();
        newStorage->removeItem(key, oldValue);
        return newStorage.release();
    }

    oldValue = m_map.take(key);
    if (!oldValue.isNull()) {
        invalidateIterator();
        ASSERT(m_currentLength - key.length() <= m_currentLength);
        m_currentLength -= key.length();
    }
    ASSERT(m_currentLength - oldValue.length() <= m_currentLength);
    m_currentLength -= oldValue.length();

    return 0;
}

bool StorageMap::contains(const String& key) const
{
    return m_map.contains(key);
}

void StorageMap::importItem(const String& key, const String& value)
{
    // Be sure to copy the keys/values as items imported on a background thread are destined
    // to cross a thread boundary
    pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.threadsafeCopy(), value.threadsafeCopy());
    ASSERT(result.second);  // True if the key didn't exist previously.

    ASSERT(m_currentLength + key.length() >= m_currentLength);
    m_currentLength += key.length();
    ASSERT(m_currentLength + value.length() >= m_currentLength);
    m_currentLength += value.length();
}

}

#endif // ENABLE(DOM_STORAGE)
