/***************************************************************************
                           kdetvimagefilter.cpp
                           --------------------
    begin                : Sat Jun 12 2004
    copyright            : (C) 2004 by Dirk Ziegelmeier
    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 <kdebug.h>
#include <klocale.h>

#include "kdetvimagefilter.h"
#include "kdetvimagefiltercontext.h"
#include "kdetvformatconversionfilter.h"

KdetvImageFilter::KdetvImageFilter(const QString& name)
    : _inputFormat(KdetvImage::FORMAT_NONE),
      _outputFormat(KdetvImage::FORMAT_NONE),
      _name(name),
      _fullFrameRate(true)
{
}

KdetvImageFilter::~KdetvImageFilter()
{
}

KdetvImage::ImageFormat KdetvImageFilter::setInputFormat(KdetvImage::ImageFormat fmt)
{
    _inputFormat = fmt;
    return fmt;
}

KdetvImage::ImageFormat KdetvImageFilter::setOutputFormat(KdetvImage::ImageFormat fmt)
{
    _outputFormat = fmt;
    return fmt;
}

KdetvImage::ImageFormat KdetvImageFilter::outputFormat()
{
    return _inputFormat;
}

KdetvImage::ImageFormat KdetvImageFilter::outputFormats()
{
    return inputFormats();
}

bool KdetvImageFilter::isValid()
{
    if( (inputFormats()  & _inputFormat)  &&
        (outputFormats() & _outputFormat)    ) {
        return true;
    } else {
        return false;
    }
}

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

KdetvImageFilterChain::KdetvImageFilterChain()
    : KdetvImageFilter("Kdetv image filter chain"),
      _chainOK(false)
{
    _chain.setAutoDelete(false);
}

KdetvImageFilterChain::~KdetvImageFilterChain()
{
}

void KdetvImageFilterChain::append(KdetvImageFilter* filter)
{
    kDebug() << "Append filter: " << filter->name();
    _chain.append(filter);
    setupChain();
}

bool KdetvImageFilterChain::isValid()
{
    return _chainOK;
}

void KdetvImageFilterChain::clear()
{
    kDebug();
    _chain.clear();
    setupChain();
}

KdetvImageFilterContext* KdetvImageFilterChain::operator<< (KdetvImageFilterContext* ctx)
{
    if(ctx->imageCount <= 0) {
        return ctx;
    }

    // Is chain valid? Is input format OK?
    if(isValid()                                  &&
       (ctx->images[0]->format() == _inputFormat)    ) {
        // All OK, process filter chain
        for (Q3PtrListIterator<KdetvImageFilter>it(_chain);
             it.current() != 0;
             ++it) {
            ctx = *it.current() << ctx;
        }
    }
    return ctx;
}

KdetvImage::ImageFormat KdetvImageFilterChain::setInputFormat(KdetvImage::ImageFormat fmt)
{
    kDebug() << KdetvImage::toString(fmt);
    _inputFormat = fmt;
    setupChain();
    return fmt;
}

KdetvImage::ImageFormat KdetvImageFilterChain::setOutputFormat(KdetvImage::ImageFormat fmt)
{
    kDebug() << KdetvImage::toString(fmt);
    _outputFormat = fmt;
    setupChain();
    return fmt;
}

KdetvImage::ImageFormat KdetvImageFilterChain::inputFormats()
{
    if(_chain.first()) {
        return _chain.first()->inputFormats();
    } else {
        return KdetvImage::FORMAT_NONE;
    }
}

KdetvImage::ImageFormat KdetvImageFilterChain::outputFormat()
{
    if(_chain.last()) {
        return _chain.last()->outputFormat();
    } else {
        return KdetvImage::FORMAT_NONE;
    }
}

KdetvImage::ImageFormat KdetvImageFilterChain::outputFormats()
{
    if(_chain.last()) {
        return _chain.last()->outputFormats();
    } else {
        return KdetvImage::FORMAT_NONE;
    }
}

void KdetvImageFilterChain::setupChain()
{
    _chainOK = false;
    _fullFrameRate = true;

    Q3PtrListIterator<KdetvImageFilter> current(_chain);
    Q3PtrListIterator<KdetvImageFilter> next(_chain);

    if(next.current() != 0) {
        ++next;
    }

    KdetvImage::ImageFormat f = chooseFormat(_inputFormat);
    for (;
         current.current() != 0;
         ++current, ++next) {

        (*current)->setInputFormat(f);

        if(next.current() != 0) {
            f = chooseFormat((KdetvImage::ImageFormat)((*current)->outputFormats() & (*next)->inputFormats()));
        } else {
            f = chooseFormat(_outputFormat);
        }

        (*current)->setOutputFormat(f);

        if(!(*current)->isValid()) {
            return;
        }

        if(!(*current)->supportsFullFrameRate()) {
            _fullFrameRate = false;
        }
    }

    _chainOK = true;
}

const QString KdetvImageFilterChain::filterChainStatus() const
{
    QString status;

    status += i18n("All image filters are operational: %1\n",_chainOK? i18n("Yes") : i18n("No"));
    status += i18n("All filters support full frame rate: %1\n",_fullFrameRate? i18n("Yes") : i18n("No"));
    status += i18n("Input format: %1\n",KdetvImage::toString(_inputFormat));
    status += i18n("Output format: %1\n",KdetvImage::toString(_outputFormat));

    for (Q3PtrListIterator<KdetvImageFilter> f(_chain);
        f.current() != 0;
        ++f) {
        KdetvImageFilter* flt = f.current();
        status += i18n("\n\nFilter %1:\n",flt->name());

        status += i18n("Operational: %1\n",flt->isValid()? i18n("Yes") : i18n("No"));
        status += i18n("Supports full frame rate: %1\n",flt->supportsFullFrameRate()? i18n("Yes") : i18n("No"));
        status += i18n("Input format: %1\n",KdetvImage::toString(flt->inputFormat()));
        status += i18n("(Supported input formats: %1)\n",KdetvImage::toString(flt->inputFormats()));

        status += i18n("Output format: %1\n",KdetvImage::toString(flt->outputFormat()));
        status += i18n("(Supported output formats: %1)\n",KdetvImage::toString(flt->outputFormats()));

        if(!flt->isValid() && ((flt->outputFormat() & flt->outputFormats()) == 0)) {
            status += i18n("\nThe filter is not operational because the kdetv cannot find a suitable output format.");
            status += i18n("Try removing this filter or reconfiguring the video plugin to use another display method.");
        }

        if(!flt->isValid() && ((flt->inputFormat() & flt->inputFormats()) == 0)) {
            status += i18n("\nThe filter is not operational because the kdetv cannot find a suitable input format.");
            status += i18n("Try removing this filter or reconfiguring the video plugin to use another display method.");
        }

        if(!flt->isValid()) {
            return status;
        }
    }
    return status;
}

KdetvImage::ImageFormat KdetvImageFilterChain::chooseFormat(KdetvImage::ImageFormat fmts)
{
    if(fmts & KdetvImage::FORMAT_YUYV) {
        return KdetvImage::FORMAT_YUYV;
    }
    if(fmts & KdetvImage::FORMAT_UYVY) {
        return KdetvImage::FORMAT_UYVY;
    }
    if(fmts & KdetvImage::FORMAT_BGR24) {
        return KdetvImage::FORMAT_BGR24;
    }
    if(fmts & KdetvImage::FORMAT_BGR32) {
        return KdetvImage::FORMAT_BGR32;
    }
    if(fmts & KdetvImage::FORMAT_RGB24) {
        return KdetvImage::FORMAT_RGB24;
    }
    if(fmts & KdetvImage::FORMAT_RGB32) {
        return KdetvImage::FORMAT_RGB32;
    }
    if(fmts & KdetvImage::FORMAT_RGB16_LE) {
        return KdetvImage::FORMAT_RGB16_LE;
    }
    if(fmts & KdetvImage::FORMAT_RGB15_LE) {
        return KdetvImage::FORMAT_RGB15_LE;
    }
    if(fmts & KdetvImage::FORMAT_RGB16_BE) {
        return KdetvImage::FORMAT_RGB16_BE;
    }
    if(fmts & KdetvImage::FORMAT_RGB15_BE) {
        return KdetvImage::FORMAT_RGB15_BE;
    }
    if(fmts & KdetvImage::FORMAT_YUV422P) {
        return KdetvImage::FORMAT_YUV422P;
    }
    if(fmts & KdetvImage::FORMAT_YUV420P) {
        return KdetvImage::FORMAT_YUV420P;
    }
    if(fmts & KdetvImage::FORMAT_GREY) {
        return KdetvImage::FORMAT_GREY;
    }
    if(fmts & KdetvImage::FORMAT_HI240) {
        return KdetvImage::FORMAT_HI240;
    }
    return KdetvImage::FORMAT_NONE;
}
