/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2006-02-22
 * Description : a generic widget to display metadata
 *
 * Copyright (C) 2006-2008 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 <tqlayout.h>
#include <tqmap.h>
#include <tqfile.h> 
#include <tqmime.h>
#include <tqheader.h>
#include <tqwhatsthis.h>
#include <tqpainter.h>
#include <tqhbuttongroup.h>
#include <tqpushbutton.h>
#include <tqlabel.h>
#include <tqdragobject.h> 
#include <tqclipboard.h>
#include <tqsimplerichtext.h>
#include <tqpaintdevicemetrics.h>
#include <tqstylesheet.h>
#include <tqlistview.h>
#include <tqtooltip.h>

// KDE includes.

#include <kdialogbase.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kglobalsettings.h>
#include <kprinter.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kapplication.h>

// Local includes.

#include "ddebug.h"
#include "metadatalistview.h"
#include "mdkeylistviewitem.h"
#include "searchtextbar.h"
#include "metadatawidget.h"
#include "metadatawidget.moc"

namespace Digikam
{

class MetadataWidgetPriv
{

public:

    MetadataWidgetPriv()
    {
        toolButtons  = 0;
        levelButtons = 0;
        view         = 0;
        mainLayout   = 0;
        searchBar    = 0;
    }

    TQGridLayout            *mainLayout;

    TQHButtonGroup          *toolButtons;
    TQHButtonGroup          *levelButtons;

    TQByteArray              metadata;

    TQString                 fileName;

    MetadataListView       *view;

    SearchTextBar          *searchBar;

    DMetadata::MetaDataMap  metaDataMap;
};

MetadataWidget::MetadataWidget(TQWidget* parent, const char* name)
              : TQWidget(parent, name)
{
    d = new MetadataWidgetPriv;

    d->mainLayout = new TQGridLayout(this, 3, 4, KDialog::spacingHint(), KDialog::spacingHint());
    KIconLoader *iconLoader = KApplication::kApplication()->iconLoader();

    d->levelButtons = new TQHButtonGroup(this);
    d->levelButtons->setInsideMargin( 0 );
    d->levelButtons->setExclusive(true);
    d->levelButtons->setFrameShape(TQFrame::NoFrame);

    TQPushButton *simpleLevel = new TQPushButton( d->levelButtons );
    simpleLevel->setPixmap( iconLoader->loadIcon( "ascii", (KIcon::Group)KIcon::Toolbar ) );
    simpleLevel->setToggleButton(true);
    TQWhatsThis::add( simpleLevel, i18n( "Switch the tags view to a simple human-readable list" ) );
    TQToolTip::add( simpleLevel, i18n( "Simple list" ));
    d->levelButtons->insert(simpleLevel, SIMPLE);

    TQPushButton *fullLevel = new TQPushButton( d->levelButtons );
    fullLevel->setPixmap( iconLoader->loadIcon( "document", (KIcon::Group)KIcon::Toolbar ) );
    fullLevel->setToggleButton(true);
    TQWhatsThis::add( fullLevel, i18n( "Switch the tags view to a full list" ) );
    TQToolTip::add( fullLevel, i18n( "Full list" ));
    d->levelButtons->insert(fullLevel, FULL);

    d->toolButtons = new TQHButtonGroup(this);
    d->toolButtons->setInsideMargin( 0 );
    d->toolButtons->setFrameShape(TQFrame::NoFrame);

    TQPushButton *saveMetadata = new TQPushButton( d->toolButtons );
    saveMetadata->setPixmap( iconLoader->loadIcon( "filesave", (KIcon::Group)KIcon::Toolbar ) );
    TQWhatsThis::add( saveMetadata, i18n( "Save metadata to a binary file" ) );
    TQToolTip::add( saveMetadata, i18n( "Save metadata" ));
    d->toolButtons->insert(saveMetadata);
    
    TQPushButton *printMetadata = new TQPushButton( d->toolButtons );
    printMetadata->setPixmap( iconLoader->loadIcon( "fileprint", (KIcon::Group)KIcon::Toolbar ) );
    TQWhatsThis::add( printMetadata, i18n( "Print metadata to printer" ) );
    TQToolTip::add( printMetadata, i18n( "Print metadata" ));
    d->toolButtons->insert(printMetadata);

    TQPushButton *copy2ClipBoard = new TQPushButton( d->toolButtons );
    copy2ClipBoard->setPixmap( iconLoader->loadIcon( "editcopy", (KIcon::Group)KIcon::Toolbar ) );
    TQWhatsThis::add( copy2ClipBoard, i18n( "Copy metadata to clipboard" ) );
    TQToolTip::add( copy2ClipBoard, i18n( "Copy metadata to clipboard" ));
    d->toolButtons->insert(copy2ClipBoard);

    d->view         = new MetadataListView(this);
    TQString barName = TQString(name) + "SearchBar";
    d->searchBar    = new SearchTextBar(this, barName.ascii());

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

    d->mainLayout->addMultiCellWidget(d->levelButtons, 0, 0, 0, 1);
    d->mainLayout->addMultiCellWidget(d->toolButtons,  0, 0, 4, 4);
    d->mainLayout->addMultiCellWidget(d->view,         1, 1, 0, 4);
    d->mainLayout->addMultiCellWidget(d->searchBar,    2, 2, 0, 4);
    d->mainLayout->setRowStretch(1, 10);
    d->mainLayout->setColStretch(3, 10);

    // -----------------------------------------------------------------
    
    connect(d->levelButtons, TQT_SIGNAL(released(int)),
            this, TQT_SLOT(slotModeChanged(int)));

    connect(copy2ClipBoard, TQT_SIGNAL(clicked()),
            this, TQT_SLOT(slotCopy2Clipboard()));

    connect(printMetadata, TQT_SIGNAL(clicked()),
            this, TQT_SLOT(slotPrintMetadata()));

    connect(saveMetadata, TQT_SIGNAL(clicked()),
            this, TQT_SLOT(slotSaveMetadataToFile()));     

    connect(d->searchBar, TQT_SIGNAL(signalTextChanged(const TQString&)),
            d->view, TQT_SLOT(slotSearchTextChanged(const TQString&)));

    connect(d->view, TQT_SIGNAL(signalTextFilterMatch(bool)),
            d->searchBar, TQT_SLOT(slotSearchResult(bool)));                   
}

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

MetadataListView* MetadataWidget::view()
{
    return d->view;
}

void MetadataWidget::enabledToolButtons(bool b)
{
    d->toolButtons->setEnabled(b);
}

bool MetadataWidget::setMetadata(const TQByteArray& data)
{
    d->metadata = data;
    
    // Cleanup all metadata contents.
    setMetadataMap();

    if (d->metadata.isEmpty())
    {
        setMetadataEmpty();
        return false;
    }

    // Try to decode current metadata.
    if (decodeMetadata())
        enabledToolButtons(true);
    else
        enabledToolButtons(false);
    
    // Refresh view using decoded metadata.
    buildView();

    return true;
}

void MetadataWidget::setMetadataEmpty()
{
    d->view->clear();
    enabledToolButtons(false);
}

const TQByteArray& MetadataWidget::getMetadata()
{
    return d->metadata;
}

bool MetadataWidget::storeMetadataToFile(const KURL& url)
{
    if( url.isEmpty() )
        return false;

    TQFile file(url.path());
    if ( !file.open(IO_WriteOnly) ) 
        return false;
    
    TQDataStream stream( &file );
    stream.writeRawBytes(d->metadata.data(), d->metadata.size());
    file.close();
    return true;
}

void MetadataWidget::setMetadataMap(const DMetadata::MetaDataMap& data)
{
    d->metaDataMap = data;
}

const DMetadata::MetaDataMap& MetadataWidget::getMetadataMap()
{
    return d->metaDataMap;
}

void MetadataWidget::setIfdList(const DMetadata::MetaDataMap &ifds, const TQStringList& tagsFilter)
{
    d->view->setIfdList(ifds, tagsFilter);
}

void MetadataWidget::setIfdList(const DMetadata::MetaDataMap &ifds, const TQStringList& keysFilter,
                                const TQStringList& tagsFilter)
{
    d->view->setIfdList(ifds, keysFilter, tagsFilter);
}

void MetadataWidget::slotModeChanged(int)
{
    buildView();
}

void MetadataWidget::slotCopy2Clipboard()
{
    TQString textmetadata = i18n("File name: %1 (%2)").arg(d->fileName).arg(getMetadataTitle());
    TQListViewItemIterator it( d->view );

    while ( it.current() )
    {
        if ( !it.current()->isSelectable() )
        {
            MdKeyListViewItem *item = dynamic_cast<MdKeyListViewItem *>(it.current());
            textmetadata.append("\n\n>>> ");
            textmetadata.append(item->getMdKey());
            textmetadata.append(" <<<\n\n");
        }
        else
        {
            TQListViewItem *item = it.current();
            textmetadata.append(item->text(0));
            textmetadata.append(" : ");
            textmetadata.append(item->text(1));
            textmetadata.append("\n");
        }

        ++it;
    }

    TQApplication::clipboard()->setData(new TQTextDrag(textmetadata), TQClipboard::Clipboard);
}

void MetadataWidget::slotPrintMetadata()
{
    TQString textmetadata = i18n("<p><big><big><b>File name: %1 (%2)</b></big></big>")
                           .arg(d->fileName)
                           .arg(getMetadataTitle());
    TQListViewItemIterator it( d->view );

    while ( it.current() )
    {
        if ( !it.current()->isSelectable() )
        {
            MdKeyListViewItem *item = dynamic_cast<MdKeyListViewItem *>(it.current());
            textmetadata.append("<br><br><b>");
            textmetadata.append(item->getMdKey());
            textmetadata.append("</b><br><br>");
        }
        else
        {
            TQListViewItem *item = it.current();
            textmetadata.append(item->text(0));
            textmetadata.append(" : <i>");
            textmetadata.append(item->text(1));
            textmetadata.append("</i><br>");
        }

        ++it;
    }

    textmetadata.append("</p>");

    KPrinter printer;
    printer.setFullPage( true );

    if ( printer.setup( this ) )
    {
        TQPainter p( &printer );

        if ( !p.device() ) 
            return;

        TQPaintDeviceMetrics metrics(p.device());
        int dpiy = metrics.logicalDpiY();
        int margin = (int) ( (2/2.54)*dpiy ); // 2 cm margins
        TQRect view( margin, margin, metrics.width() - 2*margin, metrics.height() - 2*margin );
        TQFont font(KApplication::font());
        font.setPointSize( 10 ); // we define 10pt to be a nice base size for printing
        TQSimpleRichText richText( textmetadata, font,
                                  TQString(),
                                  TQStyleSheet::defaultSheet(),
                                  TQMimeSourceFactory::defaultFactory(),
                                  view.height() );
        richText.setWidth( &p, view.width() );
        int page = 1;

        do
        {
            richText.draw( &p, margin, margin, view, colorGroup() );
            view.moveBy( 0, view.height() );
            p.translate( 0 , -view.height() );
            p.setFont( font );
            p.drawText( view.right() - p.fontMetrics().width( TQString::number( page ) ),
                        view.bottom() + p.fontMetrics().ascent() + 5, TQString::number( page ) );

            if ( view.top() - margin >= richText.height() )
                break;

            printer.newPage();
            page++;
        }
        while (true);
    }
}

KURL MetadataWidget::saveMetadataToFile(const TQString& caption, const TQString& fileFilter)
{
    KFileDialog fileSaveDialog(KGlobalSettings::documentPath(),
                               TQString(),
                               this,
                               "MetadataFileSaveDialog",
                               false);

    fileSaveDialog.setOperationMode(KFileDialog::Saving);
    fileSaveDialog.setMode(KFile::File);
    fileSaveDialog.setSelection(d->fileName);
    fileSaveDialog.setCaption(caption);
    fileSaveDialog.setFilter(fileFilter);

    // Check for cancel.
    if ( fileSaveDialog.exec() == KFileDialog::Accepted )
        return fileSaveDialog.selectedURL().path();
    
    return KURL();
}

void MetadataWidget::setMode(int mode)
{
    if (d->levelButtons->selectedId() == mode)
        return;

    d->levelButtons->setButton(mode);
    buildView();
}

int MetadataWidget::getMode()
{
    int level = d->levelButtons->selectedId();
    return level;
}

TQString MetadataWidget::getCurrentItemKey() const
{
    return d->view->getCurrentItemKey();
}

void MetadataWidget::setCurrentItemByKey(const TQString& itemKey)
{
    d->view->setCurrentItemByKey(itemKey);
}

bool MetadataWidget::loadFromData(const TQString& fileName, const TQByteArray& data)
{
    setFileName(fileName);
    return(setMetadata(data));
}

TQString MetadataWidget::getTagTitle(const TQString&)
{
    return TQString();
}

TQString MetadataWidget::getTagDescription(const TQString&)
{
    return TQString();
}

void MetadataWidget::setFileName(const TQString& fileName)
{
    d->fileName = fileName;
}

void MetadataWidget::setUserAreaWidget(TQWidget *w)
{
    TQVBoxLayout *vLayout = new TQVBoxLayout( KDialog::spacingHint() ); 
    vLayout->addWidget(w);
    vLayout->addStretch();
    d->mainLayout->addMultiCellLayout(vLayout, 3, 3, 0, 4);
}

void MetadataWidget::buildView()
{
    d->view->slotSearchTextChanged(d->searchBar->text());
}

}  // namespace Digikam
