/*
 * buffer_pool.cpp - buffer pool
 *
 *  Copyright (c) 2014-2015 Intel Corporation
 *
 * 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.
 *
 * Author: Wind Yuan <feng.yuan@intel.com>
 */

#include "buffer_pool.h"

namespace XCam {

BufferProxy::BufferProxy (const VideoBufferInfo &info, const SmartPtr<BufferData> &data)
    : VideoBuffer (info)
    , _data (data)
{
    XCAM_ASSERT (data.ptr ());
}

BufferProxy::BufferProxy (const SmartPtr<BufferData> &data)
    : _data (data)
{
    XCAM_ASSERT (data.ptr ());
}

BufferProxy::~BufferProxy ()
{
    if (_pool.ptr ()) {
        _pool->release (_data);
    }
    _data.release ();
}

uint8_t *
BufferProxy::map ()
{
    XCAM_ASSERT (_data.ptr ());
    return _data->map ();
}

bool
BufferProxy::unmap ()
{
    XCAM_ASSERT (_data.ptr ());
    return _data->unmap ();
}

int
BufferProxy::get_fd ()
{
    XCAM_ASSERT (_data.ptr ());
    return _data->get_fd ();
}

BufferPool::BufferPool ()
    : _allocated_num (0)
    , _max_count (0)
    , _started (false)
{
}

BufferPool::~BufferPool ()
{
}

bool
BufferPool::set_video_info (const VideoBufferInfo &info)
{
    VideoBufferInfo new_info = info;
    SmartLock lock (_mutex);

    XCAM_FAIL_RETURN (
        ERROR,
        fixate_video_info (new_info),
        false,
        "BufferPool fixate video info failed");
    update_video_info_unsafe (new_info);
    return true;
}

void
BufferPool::update_video_info_unsafe (const VideoBufferInfo &info)
{
    _buffer_info = info;
}

bool
BufferPool::reserve (uint32_t max_count)
{
    uint32_t i = 0;

    XCAM_ASSERT (max_count);

    SmartLock lock (_mutex);

    for (i = _allocated_num; i < max_count; ++i) {
        SmartPtr<BufferData> new_data = allocate_data (_buffer_info);
        if (!new_data.ptr ())
            break;
        _buf_list.push (new_data);
    }

    XCAM_FAIL_RETURN (
        ERROR,
        i > 0,
        false,
        "BufferPool reserve failed with none buffer data allocated");

    if (i != max_count) {
        XCAM_LOG_WARNING ("BufferPool expect to reserve %d data but only reserved %d", max_count, i);
    }
    _max_count = i;
    _allocated_num = _max_count;
    _started = true;

    return true;
}

bool
BufferPool::add_data_unsafe (const SmartPtr<BufferData> &data)
{
    if (!data.ptr ())
        return false;

    _buf_list.push (data);
    ++_allocated_num;

    XCAM_ASSERT (_allocated_num <= _max_count || !_max_count);
    return true;
}

SmartPtr<VideoBuffer>
BufferPool::get_buffer (const SmartPtr<BufferPool> &self)
{
    SmartPtr<BufferProxy> ret_buf;
    SmartPtr<BufferData> data;

    {
        SmartLock lock (_mutex);
        if (!_started)
            return NULL;
    }

    XCAM_ASSERT (self.ptr () == this);
    XCAM_FAIL_RETURN(
        WARNING,
        self.ptr () == this,
        NULL,
        "BufferPool get_buffer failed since parameter<self> not this");

    data = _buf_list.pop ();
    if (!data.ptr ()) {
        XCAM_LOG_DEBUG ("BufferPool failed to get buffer");
        return NULL;
    }
    ret_buf = create_buffer_from_data (data);
    ret_buf->set_buf_pool (self);

    return ret_buf;
}

SmartPtr<VideoBuffer>
BufferPool::get_buffer ()
{
    return get_buffer (SmartPtr<BufferPool>(this));
}

void
BufferPool::stop ()
{
    {
        SmartLock lock (_mutex);
        _started = false;
    }
    _buf_list.pause_pop ();
}

void
BufferPool::release (SmartPtr<BufferData> &data)
{
    {
        SmartLock lock (_mutex);
        if (!_started)
            return;
    }
    _buf_list.push (data);
}

bool
BufferPool::fixate_video_info (VideoBufferInfo &info)
{
    XCAM_UNUSED (info);
    return true;
}

SmartPtr<BufferProxy>
BufferPool::create_buffer_from_data (SmartPtr<BufferData> &data)
{
    const VideoBufferInfo &info = get_video_info ();

    XCAM_ASSERT (data.ptr ());
    return new BufferProxy (info, data);
}

};
