/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2008-08-20
 * Description : editor tool template class.
 *
 * Copyright (C) 2008-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General
 * Public License as published by the Free Software Foundation;
 * either version 2, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * ============================================================ */

// TQt includes.

#include <tqwidget.h>
#include <tqtimer.h>

// KDE includes.

#include <kcursor.h>

// Local includes.

#include "ddebug.h"
#include "imagewidget.h"
#include "imageguidewidget.h"
#include "imagepanelwidget.h"
#include "dimgthreadedfilter.h"
#include "editortoolsettings.h"
#include "editortooliface.h"
#include "editortool.h"
#include "editortool.moc"

namespace Digikam
{

class EditorToolPriv
{

public:

    EditorToolPriv()
    {
        timer    = 0;
        view     = 0;
        settings = 0;
    }

    TQString             helpAnchor;
    TQString             name;

    TQWidget            *view;

    TQPixmap             icon;

    TQTimer             *timer;

    EditorToolSettings *settings;
};

EditorTool::EditorTool(TQObject *parent)
          : TQObject(parent)
{
    d = new EditorToolPriv;
    d->timer = new TQTimer(this);

    connect(d->timer, TQ_SIGNAL(timeout()),
            this, TQ_SLOT(slotEffect()));
}

EditorTool::~EditorTool()
{
    delete d;
}

void EditorTool::init()
{
    TQTimer::singleShot(0, this, TQ_SLOT(slotInit()));
}

TQPixmap EditorTool::toolIcon() const
{
    return d->icon;
}

void EditorTool::setToolIcon(const TQPixmap& icon)
{
    d->icon = icon;
}

TQString EditorTool::toolName() const
{
    return d->name;
}

void EditorTool::setToolName(const TQString& name)
{
    d->name = name;
}

TQWidget* EditorTool::toolView() const
{
    return d->view;
}

void EditorTool::setToolView(TQWidget *view)
{
    d->view = view;
    // Will be unblocked in slotInit()
    // This will prevent resize event signals emit during tool init.
    d->view->blockSignals(true);
}

EditorToolSettings* EditorTool::toolSettings() const
{
    return d->settings;
}

void EditorTool::setToolSettings(EditorToolSettings *settings)
{
    d->settings = settings;

    connect(d->settings, TQ_SIGNAL(signalOkClicked()),
            this, TQ_SLOT(slotOk()));

    connect(d->settings, TQ_SIGNAL(signalCancelClicked()),
            this, TQ_SLOT(slotCancel()));

    connect(d->settings, TQ_SIGNAL(signalDefaultClicked()),
            this, TQ_SLOT(slotResetSettings()));

    connect(d->settings, TQ_SIGNAL(signalSaveAsClicked()),
            this, TQ_SLOT(slotSaveAsSettings()));

    connect(d->settings, TQ_SIGNAL(signalLoadClicked()),
            this, TQ_SLOT(slotLoadSettings()));

    connect(d->settings, TQ_SIGNAL(signalTryClicked()),
            this, TQ_SLOT(slotEffect()));

    // Will be unblocked in slotInit()
    // This will prevent signals emit during tool init.
    d->settings->blockSignals(true);
}

void EditorTool::slotInit()
{
    readSettings();
    // Unlock signals from preview and settings widgets when init is done.
    d->view->blockSignals(false);
    d->settings->blockSignals(false);
}

void EditorTool::setToolHelp(const TQString& anchor)
{
    d->helpAnchor = anchor;
    // TODO: use this anchor with editor Help menu
}

TQString EditorTool::toolHelp() const
{
    if (d->helpAnchor.isEmpty())
        return (name() + TQString(".anchor"));

    return d->helpAnchor;
}

void EditorTool::setBusy(bool state)
{
    d->settings->setBusy(state);
}

void EditorTool::readSettings()
{
    d->settings->readSettings();
}

void EditorTool::writeSettings()
{
    d->settings->writeSettings();
}

void EditorTool::slotResetSettings()
{
    d->settings->resetSettings();
}

void EditorTool::slotTimer()
{
    d->timer->start(500, true);
}

void EditorTool::slotOk()
{
    writeSettings();
    finalRendering();
    emit okClicked();
}

void EditorTool::slotCancel()
{
    writeSettings();
    emit cancelClicked();
}

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

class EditorToolThreadedPriv
{

public:

    EditorToolThreadedPriv()
    {
        threadedFilter       = 0;
        currentRenderingMode = EditorToolThreaded::NoneRendering;
    }

    EditorToolThreaded::RenderingMode  currentRenderingMode;

    TQString                            progressMess;

    DImgThreadedFilter                *threadedFilter;
};

EditorToolThreaded::EditorToolThreaded(TQObject *parent)
                  : EditorTool(parent)
{
    d = new EditorToolThreadedPriv;
}

EditorToolThreaded::~EditorToolThreaded()
{
    delete d->threadedFilter;
    delete d;
}

EditorToolThreaded::RenderingMode EditorToolThreaded::renderingMode() const
{
    return d->currentRenderingMode;
}

void EditorToolThreaded::setProgressMessage(const TQString& mess)
{
    d->progressMess = mess;
}

DImgThreadedFilter* EditorToolThreaded::filter() const
{
    return d->threadedFilter;
}

void EditorToolThreaded::setFilter(DImgThreadedFilter *filter)
{
    d->threadedFilter = filter;
}

void EditorToolThreaded::slotResized()
{
    if (d->currentRenderingMode == EditorToolThreaded::FinalRendering)
    {
       toolView()->update();
       return;
    }
    else if (d->currentRenderingMode == EditorToolThreaded::PreviewRendering)
    {
       if (filter())
          filter()->stopComputation();
    }

    TQTimer::singleShot(0, this, TQ_SLOT(slotEffect()));
}

void EditorToolThreaded::slotAbort()
{
    d->currentRenderingMode = EditorToolThreaded::NoneRendering;

    if (filter())
        filter()->stopComputation();

    EditorToolIface::editorToolIface()->setToolStopProgress();

    toolSettings()->enableButton(EditorToolSettings::Ok,      true);
    toolSettings()->enableButton(EditorToolSettings::Load,    true);
    toolSettings()->enableButton(EditorToolSettings::SaveAs,  true);
    toolSettings()->enableButton(EditorToolSettings::Try,     true);
    toolSettings()->enableButton(EditorToolSettings::Default, true);

    renderingFinished();
}

void EditorToolThreaded::customEvent(TQCustomEvent *e)
{
    if (!e) return;

    DImgThreadedFilter::EventData *ed = (DImgThreadedFilter::EventData*)e->data();

    if (!ed) return;

    if (ed->starting)           // Computation in progress !
    {
        EditorToolIface::editorToolIface()->setToolProgress(ed->progress);
    }
    else
    {
        if (ed->success)        // Computation Completed !
        {
            switch (d->currentRenderingMode)
            {
                case EditorToolThreaded::PreviewRendering:
                {
                    DDebug() << "Preview " << toolName() << " completed..." << endl;
                    putPreviewData();
                    slotAbort();
                    break;
                }

                case EditorToolThreaded::FinalRendering:
                {
                    DDebug() << "Final" << toolName() << " completed..." << endl;
                    putFinalData();
                    EditorToolIface::editorToolIface()->setToolStopProgress();
                    kapp->restoreOverrideCursor();
                    emit okClicked();
                    break;
                }

                default:
                    break;
            }
        }
        else                   // Computation Failed !
        {
            switch (d->currentRenderingMode)
            {
                case EditorToolThreaded::PreviewRendering:
                {
                    DDebug() << "Preview " << toolName() << " failed..." << endl;
                    slotAbort();
                    break;
                }

                case EditorToolThreaded::FinalRendering:
                default:
                    break;
            }
        }
    }

    delete ed;
}

void EditorToolThreaded::setToolView(TQWidget *view)
{
    EditorTool::setToolView(view);

    if (dynamic_cast<ImageWidget*>(view) || dynamic_cast<ImageGuideWidget*>(view) ||
        dynamic_cast<ImagePanelWidget*>(view))
    {
        connect(view, TQ_SIGNAL(signalResized()),
                this, TQ_SLOT(slotResized()));
    }
}

void EditorToolThreaded::slotOk()
{
    writeSettings();

    d->currentRenderingMode = EditorToolThreaded::FinalRendering;
    DDebug() << "Final " << toolName() << " started..." << endl;
    writeSettings();

    toolSettings()->enableButton(EditorToolSettings::Ok,      false);
    toolSettings()->enableButton(EditorToolSettings::SaveAs,  false);
    toolSettings()->enableButton(EditorToolSettings::Load,    false);
    toolSettings()->enableButton(EditorToolSettings::Default, false);
    toolSettings()->enableButton(EditorToolSettings::Try,     false);

    EditorToolIface::editorToolIface()->setToolStartProgress(d->progressMess.isEmpty() ? toolName() : d->progressMess);
    kapp->setOverrideCursor( KCursor::waitCursor() );

    if (d->threadedFilter)
    {
        delete d->threadedFilter;
        d->threadedFilter = 0;
    }

    prepareFinal();
}

void EditorToolThreaded::slotEffect()
{
    // Computation already in process.
    if (d->currentRenderingMode != EditorToolThreaded::NoneRendering)
        return;

    d->currentRenderingMode = EditorToolThreaded::PreviewRendering;
    DDebug() << "Preview " << toolName() << " started..." << endl;

    toolSettings()->enableButton(EditorToolSettings::Ok,      false);
    toolSettings()->enableButton(EditorToolSettings::SaveAs,  false);
    toolSettings()->enableButton(EditorToolSettings::Load,    false);
    toolSettings()->enableButton(EditorToolSettings::Default, false);
    toolSettings()->enableButton(EditorToolSettings::Try,     false);

    EditorToolIface::editorToolIface()->setToolStartProgress(d->progressMess.isEmpty() ? toolName() : d->progressMess);

    if (d->threadedFilter)
    {
        delete d->threadedFilter;
        d->threadedFilter = 0;
    }

    prepareEffect();
}

void EditorToolThreaded::slotCancel()
{
    writeSettings();
    slotAbort();
    kapp->restoreOverrideCursor();
    emit cancelClicked();
}

}  // namespace Digikam
