/***************************************************************************
                           kdetvimage.cpp
                           --------------
    begin                : Sat Jun 12 2004
    copyright            : (C) 2004 by Dirk Ziegelmeier
                           (C) 2002 by George Staikos
    email                : dziegel@gmx.de
 ***************************************************************************/

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <qimage.h>
#include <qstring.h>
#include <kdebug.h>

#include "kdetvimage.h"
#include "kdetvimagepool.h"

KdetvImage::KdetvImage()
    : _size(QSize()),
      _format(FORMAT_NONE),
      _type(TYPE_PROGRESSIVE),
      _stride(0),
      _bufSize(0),
      _buf(NULL),
      _bufowner(false)
{
}

KdetvImage::~KdetvImage()
{
    deleteBuffer();
}

QSize KdetvImage::setSize(QSize size)
{
    _size = size;
    return _size;
}

KdetvImage::ImageFormat KdetvImage::setFormat(ImageFormat format)
{
    _format = format;
    return _format;
}

void KdetvImage::setStride(unsigned int stride)
{
    _stride = stride;
}

void KdetvImage::setType(ImageType type)
{
    _type = type;
}

void KdetvImage::setBuffer(unsigned char* buf, unsigned int size, bool bufowner)
{
    deleteBuffer();

    _buf = buf;
    _bufSize = size;
    _bufowner = bufowner;
}

void KdetvImage::createBuffer(unsigned int size)
{
    deleteBuffer();

    _buf = new unsigned char[size];
    _bufSize = size;
    _bufowner = true;
}

void KdetvImage::deleteBuffer()
{
    if(_bufowner) {
        delete[] _buf;
    }
    _buf = 0;
    _bufSize = 0;
    _bufowner = false;
}

bool KdetvImage::toQImage(QImage& img)
{
    if (!_size.isValid()) {
        return false;
    }

    switch (_format) {
    case FORMAT_BGR32:
        img.create(_size.width(), _size.height(), 32);
        memcpy(img.bits(), buffer(), _size.width()*_size.height()*bytesPerPixel());
        break;
    case FORMAT_BGR24:
        {
            img.create(_size.width(), _size.height(), 32);
            uchar *bits = img.bits();
            for (int i = 0; i < _size.width()*_size.height(); i++) {
                bits[4*i  ] = buffer()[3*i  ];
                bits[4*i+1] = buffer()[3*i+1];
                bits[4*i+2] = buffer()[3*i+2];
                bits[4*i+3] = 0;
            }
        }
        break;
    case FORMAT_RGB16_LE:
        kdDebug() <<  "KdetvImage(RGB16_LE)->QImage conversion: "
                  << _size.width() << "x" << _size.height() << " " << bytesPerPixel() << "Bpp" << endl;
        img.create(_size.width(), _size.height(), 16);
        memcpy(img.bits(), buffer(), _size.width()*_size.height()*bytesPerPixel());
        break;
    case FORMAT_RGB15_LE:
        kdDebug() <<  "KdetvImage(RGB15_LE)->QImage conversion: "
                  << _size.width() << "x" << _size.height() << " " << bytesPerPixel() << "Bpp" << endl;
        img.create(_size.width(), _size.height(), 15);
        memcpy(img.bits(), buffer(), _size.width()*_size.height()*bytesPerPixel());
        break;
    default:
        // unknown or unhandled format
        return false;
        break;
    }

    return true;
}

const QString KdetvImage::toString(KdetvImage::ImageFormat fmt)
{
    // Check for multiple formats to produce better output
    int formatCount = 0;
    for(unsigned int i=0; i < 32; i++) {
        if(fmt & (1<<i)) {
            formatCount++;
        }
    }

    QString str = QString::null;

    if(formatCount > 1) {
        str += "{";
    }

    for (unsigned int i=0; i<32; i++) {
        switch(fmt & (1<<i)) {
        case KdetvImage::FORMAT_YUYV:
            str += "YUYV";
            break;
        case KdetvImage::FORMAT_UYVY:
            str += "UYVY";
            break;
        case KdetvImage::FORMAT_RGB24:
            str += "RGB24";
            break;
        case KdetvImage::FORMAT_RGB32:
            str += "RGB32";
            break;
        case KdetvImage::FORMAT_BGR24:
            str += "BGR24";
            break;
        case KdetvImage::FORMAT_BGR32:
            str += "BGR32";
            break;
        case KdetvImage::FORMAT_RGB15_LE:
            str += "RGB15_LE";
            break;
        case KdetvImage::FORMAT_RGB16_LE:
            str += "RGB16_LE";
            break;
        case KdetvImage::FORMAT_RGB15_BE:
            str += "RGB15_BE";
            break;
        case KdetvImage::FORMAT_RGB16_BE:
            str += "RGB16_BE";
            break;
        case KdetvImage::FORMAT_YUV422P:
            str += "YUV422P";
            break;
        case KdetvImage::FORMAT_YUV420P:
            str += "YUV420P";
            break;
        case KdetvImage::FORMAT_GREY:
            str += "GREY";
            break;
        case KdetvImage::FORMAT_HI240:
            str += "HI240";
            break;
        case KdetvImage::FORMAT_NONE:
            break;
        default:
            kdWarning() << "KdetvImage::toString(): Unknown format: " << (fmt & (1<<i)) << endl;
            break;
        }

        if( (formatCount > 1) && (fmt & (1<<i)) ) {
            str += ", ";
        }
    }

    if(formatCount > 1) {
        str = str.left(str.length() - 2);
        str += "}";
    }

    return str;
}

unsigned int KdetvImage::bytesppForFormat(ImageFormat fmt)
{
    switch (fmt) {
    case FORMAT_RGB32:
    case FORMAT_RGB24:
    case FORMAT_BGR32:
    case FORMAT_BGR24:
        return 4;
        
    case FORMAT_RGB15_LE:
    case FORMAT_RGB16_LE:
    case FORMAT_RGB15_BE:
    case FORMAT_RGB16_BE:
    case FORMAT_YUYV:
    case FORMAT_UYVY:
    case FORMAT_YUV422P:
    case FORMAT_YUV420P:
        return 2;
        
    case FORMAT_GREY:
    case FORMAT_HI240:
        return 1;
        
    default:
        kdWarning() << "KdetvImage::bytesppForFormat(): Unknown format: " << fmt << endl;
        // unknown format
        return 0;
    }
}

// ------------------------------------------------------------------------------------

KdetvSharedImage::KdetvSharedImage()
    : KdetvImage(),
      _refCount(1)
{
}

KdetvSharedImage::~KdetvSharedImage()
{
}

KdetvSharedImage& KdetvSharedImage::newRef()
{
    _refCount++;
    return *this;
}

void KdetvSharedImage::deleteRef()
{
    _refCount--;
    if(_refCount == 0) {
        delete this;
    }
}

// ------------------------------------------------------------------------------------

KdetvPooledImage::KdetvPooledImage(KdetvImagePool* pool)
    : KdetvSharedImage(),
      _pool(pool)
{
}

KdetvPooledImage::~KdetvPooledImage()
{
}

void* KdetvPooledImage::operator new(size_t, KdetvImagePool* pool)
{
    return pool->getImageStorage();
}

void KdetvPooledImage::operator delete(void* instance)
{
    ((KdetvPooledImage*)instance)->_pool->putImage((KdetvPooledImage*)instance);
}
