/******************************************************************************
 *
 *  Copyright 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
 *
 *  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 of the License, 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *******************************************************************************/

#include "utils/configurethemesdialog.h"
#include "utils/configurethemesdialog_p.h"

#include "utils/themeeditor.h"
#include "core/theme.h"

#include "core/manager.h"

#include <QGridLayout>
#include <QPushButton>
#include <QFrame>
#include <QHash>

#include <KLocalizedString>
#include <KIconLoader>
#include <KMessageBox>
#include <KFileDialog>
#include <KConfigGroup>

namespace MessageList
{

namespace Utils
{

class ThemeListWidgetItem : public QListWidgetItem
{
public:
    ThemeListWidgetItem( QListWidget * par, const Core::Theme &set )
        : QListWidgetItem( set.name(), par )
    {
        mTheme = new Core::Theme( set );
    }
    ~ThemeListWidgetItem()
    {
        delete mTheme;
    }

    Core::Theme * theme() const
    {
        return mTheme;
    }
    void forgetTheme()
    {
        mTheme = 0;
    }
private:
    Core::Theme * mTheme;
};

class ThemeListWidget : public QListWidget
{
public:
    ThemeListWidget( QWidget * parent )
        : QListWidget( parent )
    {}
public:
    // need a larger but shorter QListWidget
    QSize sizeHint() const
    { return QSize( 450, 128 ); }
};

} // namespace Utils

} // namespace MessageList

using namespace MessageList::Core;
using namespace MessageList::Utils;

ConfigureThemesDialog::ConfigureThemesDialog( QWidget *parent )
    : KDialog( parent ), d( new Private( this ) )
{
    setAttribute( Qt::WA_DeleteOnClose );
    setWindowModality( Qt::ApplicationModal ); // FIXME: Sure ?
    setButtons( Ok | Cancel );
    setWindowTitle( i18n( "Customize Themes" ) );

    QWidget * base = new QWidget( this );
    setMainWidget( base );

    QGridLayout * g = new QGridLayout( base );
    g->setContentsMargins( 0, 0, 0, 0 );

    d->mThemeList = new ThemeListWidget( base );
    d->mThemeList->setSelectionMode(QAbstractItemView::ExtendedSelection);
    d->mThemeList->setSortingEnabled( true );
    g->addWidget( d->mThemeList, 0, 0, 7, 1 );

    connect( d->mThemeList, SIGNAL(itemClicked(QListWidgetItem*)),
             SLOT(themeListItemClicked(QListWidgetItem*)) );

    d->mNewThemeButton = new QPushButton( i18n( "New Theme" ), base );
    d->mNewThemeButton->setIcon( KIcon( QLatin1String( "document-new" ) ) );
    d->mNewThemeButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) );
    g->addWidget( d->mNewThemeButton, 0, 1 );

    connect( d->mNewThemeButton, SIGNAL(clicked()),
             SLOT(newThemeButtonClicked()) );

    d->mCloneThemeButton = new QPushButton( i18n( "Clone Theme" ), base );
    d->mCloneThemeButton->setIcon( KIcon( QLatin1String( "edit-copy" ) ) );
    d->mCloneThemeButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) );
    g->addWidget( d->mCloneThemeButton, 1, 1 );

    connect( d->mCloneThemeButton, SIGNAL(clicked()),
             SLOT(cloneThemeButtonClicked()) );

    QFrame * f = new QFrame( base );
    f->setFrameStyle( QFrame::Sunken | QFrame::HLine );
    f->setMinimumHeight( 24 );
    g->addWidget( f, 2, 1, Qt::AlignVCenter );


    d->mExportThemeButton = new QPushButton( i18n( "Export Theme..." ), base );
    g->addWidget( d->mExportThemeButton, 3, 1 );

    connect( d->mExportThemeButton, SIGNAL(clicked()),
             SLOT(exportThemeButtonClicked()) );

    d->mImportThemeButton = new QPushButton( i18n( "Import Theme..." ), base );
    g->addWidget( d->mImportThemeButton, 4, 1 );
    connect( d->mImportThemeButton, SIGNAL(clicked()),
             SLOT(importThemeButtonClicked()) );

    f = new QFrame( base );
    f->setFrameStyle( QFrame::Sunken | QFrame::HLine );
    f->setMinimumHeight( 24 );
    g->addWidget( f, 5, 1, Qt::AlignVCenter );


    d->mDeleteThemeButton = new QPushButton( i18n( "Delete Theme" ), base );
    d->mDeleteThemeButton->setIcon( KIcon( QLatin1String( "edit-delete" ) ) );
    d->mDeleteThemeButton->setIconSize( QSize( KIconLoader::SizeSmall, KIconLoader::SizeSmall ) );
    g->addWidget( d->mDeleteThemeButton, 6, 1 );

    connect( d->mDeleteThemeButton, SIGNAL(clicked()),
             SLOT(deleteThemeButtonClicked()) );

    d->mEditor = new ThemeEditor( base );
    g->addWidget( d->mEditor, 8, 0, 1, 2 );

    connect( d->mEditor, SIGNAL(themeNameChanged()),
             SLOT(editedThemeNameChanged()) );

    g->setColumnStretch( 0, 1 );
    g->setRowStretch( 4, 1 );

    connect( this, SIGNAL(okClicked()),
             SLOT(okButtonClicked()) );

    d->fillThemeList();
}

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

void ConfigureThemesDialog::selectTheme( const QString &themeId )
{
    ThemeListWidgetItem * item = d->findThemeItemById( themeId );
    if ( item ) {
        d->mThemeList->setCurrentItem( item );
        d->themeListItemClicked(item);
    }
}

void ConfigureThemesDialog::Private::okButtonClicked()
{
    commitEditor();

    Manager::instance()->removeAllThemes();

    const int c = mThemeList->count();
    int i = 0;
    while ( i < c )
    {
        ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
        if ( item )
        {
            Manager::instance()->addTheme( item->theme() );
            item->forgetTheme();
        }
        ++i;
    }

    Manager::instance()->themesConfigurationCompleted();

    q->close(); // this will delete too
}

void ConfigureThemesDialog::Private::commitEditor()
{
    Theme * editedTheme = mEditor->editedTheme();
    if ( !editedTheme )
        return;

    mEditor->commit();

    ThemeListWidgetItem * editedItem = findThemeItemByTheme( editedTheme );
    if ( !editedItem )
        return;

    // We must reset the runtime column state as the columns might have
    // totally changed in the editor
    editedTheme->resetColumnState();

    QString goodName = uniqueNameForTheme( editedTheme->name(), editedTheme );
    editedTheme->setName( goodName );
    editedItem->setText( goodName );
}

void ConfigureThemesDialog::Private::editedThemeNameChanged()
{
    Theme * set = mEditor->editedTheme();
    if ( !set )
        return;

    ThemeListWidgetItem * it = findThemeItemByTheme( set );
    if ( !it )
        return;

    QString goodName = uniqueNameForTheme( set->name(), set );

    it->setText( goodName );
}

void ConfigureThemesDialog::Private::fillThemeList()
{
    const QHash< QString, Theme * >& sets = Manager::instance()->themes();

    QHash< QString, Theme * >::ConstIterator end( sets.constEnd() );
    for( QHash< QString, Theme * >::ConstIterator it = sets.constBegin(); it != end; ++it )
        (void)new ThemeListWidgetItem( mThemeList, *( *it ) );
}


void ConfigureThemesDialog::Private::themeListItemClicked(QListWidgetItem* cur)
{
    commitEditor();

    const int numberOfSelectedItem(mThemeList->selectedItems().count());

    ThemeListWidgetItem * item = cur ? dynamic_cast< ThemeListWidgetItem * >( cur ) : 0;
    mDeleteThemeButton->setEnabled( item && !item->theme()->readOnly() );
    mCloneThemeButton->setEnabled( numberOfSelectedItem == 1 );
    mEditor->editTheme( item ? item->theme() : 0 );
    mExportThemeButton->setEnabled( numberOfSelectedItem > 0 );

    if ( item && !item->isSelected() )
        item->setSelected( true ); // make sure it's true
}

ThemeListWidgetItem * ConfigureThemesDialog::Private::findThemeItemById( const QString &themeId )
{
    const int c = mThemeList->count();
    int i = 0;
    while ( i < c )
    {
        ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
        if ( item )
        {
            if ( item->theme()->id() == themeId )
                return item;
        }
        ++i;
    }
    return 0;
}


ThemeListWidgetItem * ConfigureThemesDialog::Private::findThemeItemByName( const QString &name, Theme * skipTheme )
{
    const int c = mThemeList->count();
    int i = 0;
    while ( i < c )
    {
        ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
        if ( item )
        {
            if ( item->theme() != skipTheme )
            {
                if ( item->theme()->name() == name )
                    return item;
            }
        }
        ++i;
    }
    return 0;
}

ThemeListWidgetItem * ConfigureThemesDialog::Private::findThemeItemByTheme( Theme * set )
{
    const int c = mThemeList->count();
    int i = 0;
    while ( i < c )
    {
        ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->item( i ) );
        if ( item )
        {
            if ( item->theme() == set )
                return item;
        }
        ++i;
    }
    return 0;
}


QString ConfigureThemesDialog::Private::uniqueNameForTheme( const QString& baseName, Theme * skipTheme )
{
    QString ret = baseName;
    if( ret.isEmpty() )
        ret = i18n( "Unnamed Theme" );

    int idx = 1;

    ThemeListWidgetItem * item = findThemeItemByName( ret, skipTheme );
    while ( item )
    {
        idx++;
        ret = QString::fromLatin1( "%1 %2" ).arg( baseName ).arg( idx );
        item = findThemeItemByName( ret, skipTheme );
    }
    return ret;
}

void ConfigureThemesDialog::Private::newThemeButtonClicked()
{
    const int numberOfSelectedItem(mThemeList->selectedItems().count());
    Theme emptyTheme;
    emptyTheme.setName( uniqueNameForTheme( i18n( "New Theme" ) ) );
    Theme::Column * col = new Theme::Column();
    col->setLabel( i18n( "New Column" ) );
    col->setVisibleByDefault( true );
    col->addMessageRow( new Theme::Row() );
    col->addGroupHeaderRow( new Theme::Row() );
    emptyTheme.addColumn( col );
    ThemeListWidgetItem * item = new ThemeListWidgetItem( mThemeList, emptyTheme );

    mThemeList->setCurrentItem( item );
    mEditor->editTheme( item->theme() );

    mDeleteThemeButton->setEnabled( !item->theme()->readOnly() );
    mExportThemeButton->setEnabled( item );
    mCloneThemeButton->setEnabled(numberOfSelectedItem == 1);
}

void ConfigureThemesDialog::Private::cloneThemeButtonClicked()
{
    ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( mThemeList->currentItem() );
    if ( !item )
        return;
    commitEditor();
    item->setSelected(false);
    Theme copyTheme( *( item->theme() ) );
    copyTheme.setReadOnly( false );
    copyTheme.detach(); // detach shared data
    copyTheme.generateUniqueId(); // regenerate id so it becomes different
    copyTheme.setName( uniqueNameForTheme( item->theme()->name() ) );
    item = new ThemeListWidgetItem( mThemeList, copyTheme );

    mThemeList->setCurrentItem( item );
    mEditor->editTheme( item->theme() );

    const int numberOfSelectedItem(mThemeList->selectedItems().count());
    mDeleteThemeButton->setEnabled( !item->theme()->readOnly() );
    mExportThemeButton->setEnabled( true );
    mCloneThemeButton->setEnabled(numberOfSelectedItem == 1);
}

void ConfigureThemesDialog::Private::deleteThemeButtonClicked()
{
    QList<QListWidgetItem *> list = mThemeList->selectedItems();
    if(list.isEmpty()) {
        return;
    }
    //KF5 add i18n
    if (KMessageBox::Yes == KMessageBox::questionYesNo(q, list.count() > 1 ? QLatin1String("Do you want to delete selected themes?")
                                                       : QString::fromLatin1("Do you want to delete \"%1\"?").arg(list.first()->text()), QLatin1String("Delete Theme"))) {
        mEditor->editTheme( 0 ); // forget it
        Q_FOREACH(QListWidgetItem * it, list) {
            ThemeListWidgetItem * item = dynamic_cast< ThemeListWidgetItem * >( it );
            if ( !item )
                return;
            if(!item->theme()->readOnly()) {
                delete item;// this will trigger themeListCurrentItemChanged()
            }
            if ( mThemeList->count() < 2 )
                break; // no way: desperately try to keep at least one option set alive :)
        }

        ThemeListWidgetItem *newItem = dynamic_cast< ThemeListWidgetItem * >(mThemeList->currentItem());
        mDeleteThemeButton->setEnabled( newItem && !newItem->theme()->readOnly() );
        mExportThemeButton->setEnabled( newItem );
        const int numberOfSelectedItem(mThemeList->selectedItems().count());
        mCloneThemeButton->setEnabled(numberOfSelectedItem == 1);
    }
}

void ConfigureThemesDialog::Private::importThemeButtonClicked()
{
    const QString filename = KFileDialog::getOpenFileName(QString(),QString::fromLatin1("*"),q,i18n("Import Theme"));
    if(!filename.isEmpty()) {
        KConfig config(filename);

        if(config.hasGroup(QLatin1String("MessageListView::Themes"))) {
            KConfigGroup grp( &config, QLatin1String("MessageListView::Themes") );
            const int cnt = grp.readEntry( "Count", 0 );
            int idx = 0;
            while ( idx < cnt ) {
                const QString data = grp.readEntry( QString::fromLatin1( "Set%1" ).arg( idx ), QString() );
                if ( !data.isEmpty() )
                {
                    Theme * set = new Theme();
                    if ( set->loadFromString( data ) ) {
                        set->setReadOnly( false );
                        set->detach(); // detach shared data
                        set->generateUniqueId(); // regenerate id so it becomes different
                        set->setName( uniqueNameForTheme( set->name() ) );
                        (void)new ThemeListWidgetItem( mThemeList, *set );
                    } else {
                        delete set;
                    }
                }
                ++idx;
            }
        }
    }
}

void ConfigureThemesDialog::Private::exportThemeButtonClicked()
{
    QList<QListWidgetItem *> list = mThemeList->selectedItems();
    if(list.isEmpty()) {
        return;
    }
    const QString filename = KFileDialog::getSaveFileName(QString(),QString::fromLatin1("*"),q,i18n("Export Theme"), KFileDialog::ConfirmOverwrite);
    if(!filename.isEmpty()) {
        KConfig config(filename);

        KConfigGroup grp( &config, QLatin1String("MessageListView::Themes") );
        grp.writeEntry( "Count", list.count() );

        int idx = 0;
        Q_FOREACH(QListWidgetItem *item, list) {
            ThemeListWidgetItem * themeItem = static_cast< ThemeListWidgetItem * >( item );
            grp.writeEntry( QString::fromLatin1( "Set%1" ).arg( idx ), themeItem->theme()->saveToString() );
            ++idx;
        }
    }
}


#include "moc_configurethemesdialog.cpp"
