/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_UTILS_LRU_CACHE_H
#define ANDROID_UTILS_LRU_CACHE_H

#include <utils/BasicHashtable.h>
#include <utils/GenerationCache.h>
#include <utils/UniquePtr.h>

namespace android {

// OnEntryRemoved is defined in GenerationCache.h, but maybe should move here.

template <typename TKey, typename TValue>
class LruCache {
public:
    explicit LruCache(uint32_t maxCapacity);

    enum Capacity {
        kUnlimitedCapacity,
    };

    void setOnEntryRemovedListener(OnEntryRemoved<TKey, TValue>* listener);
    size_t size() const;
    const TValue& get(const TKey& key);
    bool put(const TKey& key, const TValue& value);
    bool remove(const TKey& key);
    bool removeOldest();
    void clear();

    class Iterator {
    public:
        Iterator(const LruCache<TKey, TValue>& cache): mCache(cache), mIndex(-1) {
        }

        bool next() {
            mIndex = mCache.mTable->next(mIndex);
            return mIndex != -1;
        }

        size_t index() const {
            return mIndex;
        }

        const TValue& value() const {
            return mCache.mTable->entryAt(mIndex).value;
        }

        const TKey& key() const {
            return mCache.mTable->entryAt(mIndex).key;
        }
    private:
        const LruCache<TKey, TValue>& mCache;
        size_t mIndex;
    };

private:
    LruCache(const LruCache& that);  // disallow copy constructor

    struct Entry {
        TKey key;
        TValue value;
        Entry* parent;
        Entry* child;

        Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
        }
        const TKey& getKey() const { return key; }
    };

    void attachToCache(Entry& entry);
    void detachFromCache(Entry& entry);
    void rehash(size_t newCapacity);

    UniquePtr<BasicHashtable<TKey, Entry> > mTable;
    OnEntryRemoved<TKey, TValue>* mListener;
    Entry* mOldest;
    Entry* mYoungest;
    uint32_t mMaxCapacity;
    TValue mNullValue;
};

// Implementation is here, because it's fully templated
template <typename TKey, typename TValue>
LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
    mNullValue(NULL), mTable(new BasicHashtable<TKey, Entry>), mYoungest(NULL), mOldest(NULL),
    mListener(NULL) {
};

template<typename K, typename V>
void LruCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
    mListener = listener;
}

template <typename TKey, typename TValue>
size_t LruCache<TKey, TValue>::size() const {
    return mTable->size();
}

template <typename TKey, typename TValue>
const TValue& LruCache<TKey, TValue>::get(const TKey& key) {
    hash_t hash = hash_type(key);
    ssize_t index = mTable->find(-1, hash, key);
    if (index == -1) {
        return mNullValue;
    }
    Entry& entry = mTable->editEntryAt(index);
    detachFromCache(entry);
    attachToCache(entry);
    return entry.value;
}

template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::put(const TKey& key, const TValue& value) {
    if (mMaxCapacity != kUnlimitedCapacity && size() >= mMaxCapacity) {
        removeOldest();
    }

    hash_t hash = hash_type(key);
    ssize_t index = mTable->find(-1, hash, key);
    if (index >= 0) {
        return false;
    }
    if (!mTable->hasMoreRoom()) {
        rehash(mTable->capacity() * 2);
    }

    // Would it be better to initialize a blank entry and assign key, value?
    Entry initEntry(key, value);
    index = mTable->add(hash, initEntry);
    Entry& entry = mTable->editEntryAt(index);
    attachToCache(entry);
    return true;
}

template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::remove(const TKey& key) {
    hash_t hash = hash_type(key);
    ssize_t index = mTable->find(-1, hash, key);
    if (index < 0) {
        return false;
    }
    Entry& entry = mTable->editEntryAt(index);
    if (mListener) {
        (*mListener)(entry.key, entry.value);
    }
    detachFromCache(entry);
    mTable->removeAt(index);
    return true;
}

template <typename TKey, typename TValue>
bool LruCache<TKey, TValue>::removeOldest() {
    if (mOldest != NULL) {
        return remove(mOldest->key);
        // TODO: should probably abort if false
    }
    return false;
}

template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::clear() {
    if (mListener) {
        for (Entry* p = mOldest; p != NULL; p = p->child) {
            (*mListener)(p->key, p->value);
        }
    }
    mYoungest = NULL;
    mOldest = NULL;
    mTable->clear();
}

template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::attachToCache(Entry& entry) {
    if (mYoungest == NULL) {
        mYoungest = mOldest = &entry;
    } else {
        entry.parent = mYoungest;
        mYoungest->child = &entry;
        mYoungest = &entry;
    }
}

template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::detachFromCache(Entry& entry) {
    if (entry.parent != NULL) {
        entry.parent->child = entry.child;
    } else {
        mOldest = entry.child;
    }
    if (entry.child != NULL) {
        entry.child->parent = entry.parent;
    } else {
        mYoungest = entry.parent;
    }

    entry.parent = NULL;
    entry.child = NULL;
}

template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::rehash(size_t newCapacity) {
    UniquePtr<BasicHashtable<TKey, Entry> > oldTable(mTable.release());
    Entry* oldest = mOldest;

    mOldest = NULL;
    mYoungest = NULL;
    mTable.reset(new BasicHashtable<TKey, Entry>(newCapacity));
    for (Entry* p = oldest; p != NULL; p = p->child) {
        put(p->key, p->value);
    }
}

}

#endif // ANDROID_UTILS_LRU_CACHE_H
