/*
 * Copyright (C) 2010 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.
 */

#define LOG_TAG "OpenGLRenderer"

#include "ResourceCache.h"
#include "Caches.h"

namespace android {

using namespace uirenderer;
ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);

namespace uirenderer {

///////////////////////////////////////////////////////////////////////////////
// Resource cache
///////////////////////////////////////////////////////////////////////////////

void ResourceCache::logCache() {
    ALOGD("ResourceCache: cacheReport:");
    for (size_t i = 0; i < mCache->size(); ++i) {
        ResourceReference* ref = mCache->valueAt(i);
        ALOGD("  ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
                i, mCache->keyAt(i), mCache->valueAt(i));
        ALOGD("  ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
                i, ref->refCount, ref->destroyed, ref->resourceType);
    }
}

ResourceCache::ResourceCache() {
    Mutex::Autolock _l(mLock);
    mCache = new KeyedVector<const void*, ResourceReference*>();
}

ResourceCache::~ResourceCache() {
    Mutex::Autolock _l(mLock);
    delete mCache;
}

void ResourceCache::lock() {
    mLock.lock();
}

void ResourceCache::unlock() {
    mLock.unlock();
}

const SkBitmap* ResourceCache::insert(const SkBitmap& bitmapResource) {
    Mutex::Autolock _l(mLock);

    BitmapKey bitmapKey(bitmapResource);
    ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
    if (index == NAME_NOT_FOUND) {
        SkBitmap* cachedBitmap = new SkBitmap(bitmapResource);
        index = mBitmapCache.add(bitmapKey, cachedBitmap);
        return cachedBitmap;
    }

    mBitmapCache.keyAt(index).mRefCount++;
    return mBitmapCache.valueAt(index);
}

void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
    Mutex::Autolock _l(mLock);
    incrementRefcountLocked(resource, resourceType);
}

void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
    incrementRefcount((void*) patchResource, kNinePatch);
}

void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
    ssize_t index = mCache->indexOfKey(resource);
    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
    if (ref == nullptr || mCache->size() == 0) {
        ref = new ResourceReference(resourceType);
        mCache->add(resource, ref);
    }
    ref->refCount++;
}

void ResourceCache::decrementRefcount(void* resource) {
    Mutex::Autolock _l(mLock);
    decrementRefcountLocked(resource);
}

void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
    Mutex::Autolock _l(mLock);
    decrementRefcountLocked(bitmapResource);
}

void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
    decrementRefcount((void*) patchResource);
}

void ResourceCache::decrementRefcountLocked(void* resource) {
    ssize_t index = mCache->indexOfKey(resource);
    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
    if (ref == nullptr) {
        // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
        return;
    }
    ref->refCount--;
    if (ref->refCount == 0) {
        deleteResourceReferenceLocked(resource, ref);
    }
}

void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
    BitmapKey bitmapKey(*bitmapResource);
    ssize_t index = mBitmapCache.indexOfKey(bitmapKey);

    LOG_ALWAYS_FATAL_IF(index == NAME_NOT_FOUND,
                    "Decrementing the reference of an untracked Bitmap");

    const BitmapKey& cacheEntry = mBitmapCache.keyAt(index);
    if (cacheEntry.mRefCount == 1) {
        // delete the bitmap and remove it from the cache
        delete mBitmapCache.valueAt(index);
        mBitmapCache.removeItemsAt(index);
    } else {
        cacheEntry.mRefCount--;
    }
}

void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
    decrementRefcountLocked((void*) patchResource);
}

void ResourceCache::destructor(Res_png_9patch* resource) {
    Mutex::Autolock _l(mLock);
    destructorLocked(resource);
}

void ResourceCache::destructorLocked(Res_png_9patch* resource) {
    ssize_t index = mCache->indexOfKey(resource);
    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
    if (ref == nullptr) {
        // If we're not tracking this resource, just delete it
        if (Caches::hasInstance()) {
            Caches::getInstance().patchCache.removeDeferred(resource);
        } else {
            // A Res_png_9patch is actually an array of byte that's larger
            // than sizeof(Res_png_9patch). It must be freed as an array.
            delete[] (int8_t*) resource;
        }
        return;
    }
    ref->destroyed = true;
    if (ref->refCount == 0) {
        deleteResourceReferenceLocked(resource, ref);
    }
}

/**
 * This method should only be called while the mLock mutex is held (that mutex is grabbed
 * by the various destructor() and recycle() methods which call this method).
 */
void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
    if (ref->destroyed) {
        switch (ref->resourceType) {
            case kNinePatch: {
                if (Caches::hasInstance()) {
                    Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
                } else {
                    // A Res_png_9patch is actually an array of byte that's larger
                    // than sizeof(Res_png_9patch). It must be freed as an array.
                    int8_t* patch = (int8_t*) resource;
                    delete[] patch;
                }
            }
            break;
        }
    }
    mCache->removeItem(resource);
    delete ref;
}

///////////////////////////////////////////////////////////////////////////////
// Bitmap Key
///////////////////////////////////////////////////////////////////////////////

void BitmapKey::operator=(const BitmapKey& other) {
    this->mRefCount = other.mRefCount;
    this->mBitmapDimensions = other.mBitmapDimensions;
    this->mPixelRefOrigin = other.mPixelRefOrigin;
    this->mPixelRefStableID = other.mPixelRefStableID;
}

bool BitmapKey::operator==(const BitmapKey& other) const {
    return mPixelRefStableID == other.mPixelRefStableID &&
           mPixelRefOrigin == other.mPixelRefOrigin &&
           mBitmapDimensions == other.mBitmapDimensions;
}

bool BitmapKey::operator<(const BitmapKey& other) const {
    if (mPixelRefStableID != other.mPixelRefStableID) {
        return mPixelRefStableID < other.mPixelRefStableID;
    }
    if (mPixelRefOrigin.x() != other.mPixelRefOrigin.x()) {
        return mPixelRefOrigin.x() < other.mPixelRefOrigin.x();
    }
    if (mPixelRefOrigin.y() != other.mPixelRefOrigin.y()) {
        return mPixelRefOrigin.y() < other.mPixelRefOrigin.y();
    }
    if (mBitmapDimensions.width() != other.mBitmapDimensions.width()) {
        return mBitmapDimensions.width() < other.mBitmapDimensions.width();
    }
    return mBitmapDimensions.height() < other.mBitmapDimensions.height();
}

}; // namespace uirenderer
}; // namespace android
