#include <qlistview.h>
#include <qlayout.h>
#include <qheader.h>

#include <kdebug.h>
#include <kcompletion.h>
#include <klineedit.h>

#include "bugsystem.h"
#include "kbbprefs.h"

#include "packageselectdialog.h"
#include "packageselectdialog.moc"

PackageListView::PackageListView( QWidget *parent ) :
    QListView( parent )
{
    setFocusPolicy( QWidget::StrongFocus );
}

void PackageListView::resetTyped()
{
    mTyped = "";
}

void PackageListView::keyPressEvent( QKeyEvent *e )
{
    // Disable listview text completion for now
    QListView::keyPressEvent( e );
    return;

    int k = e->key();
    if ( k == Key_Return || k == Key_Escape ) e->ignore();

    QString key = e->text();
    mTyped.append(key);
    emit typed( mTyped );
}


class PackageItem : public QListViewItem
{
  public:
    PackageItem( QListView *list,Package pkg ) :
        QListViewItem( list, pkg.name() ), mPackage( pkg ) {}

    Package package() { return mPackage; }

  private:
    Package mPackage;
};


PackageSelectDialog::PackageSelectDialog(QWidget *parent,const char *name) :
  KDialogBase( parent, name, true, i18n("Select Package"), Ok|Cancel )
{
    QWidget *topWidget = new QWidget( this );
    setMainWidget( topWidget );

    QBoxLayout *topLayout = new QVBoxLayout( topWidget );

    mRecentList = new QListView( topWidget );
    mRecentList->addColumn( i18n("Recent") );
    mRecentList->header()->hide();
    mRecentList->setMaximumHeight( mRecentList->fontMetrics().height() *
                                   KBBPrefs::instance()->mRecentPackagesCount );
    topLayout->addWidget( mRecentList, 0 );

    QStringList::ConstIterator it;
    for( it = KBBPrefs::instance()->mRecentPackages.begin();
         it != KBBPrefs::instance()->mRecentPackages.end();
         ++it) {
        new QListViewItem( mRecentList, *it );
    }

    connect( mRecentList, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint &, int) ),
             SLOT( recentSelected( int, QListViewItem * ) ) );
    connect( mRecentList, SIGNAL( doubleClicked( QListViewItem * ) ),
             SLOT( slotOk() ) );

    mCompletion = new KCompletion;
    mCompletion->setCompletionMode( KGlobalSettings::CompletionAuto );

    mCompleteList = new PackageListView( topWidget );
    mCompleteList->addColumn( i18n("All") );
    mCompleteList->header()->hide();
    connect( mCompleteList, SIGNAL( typed( const QString & ) ),
             SLOT( completeTyped( const QString & ) ) );
    topLayout->addWidget( mCompleteList, 1 );

    connect( mCompleteList, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint &, int) ),
             SLOT( completeSelected( int, QListViewItem * ) ) );
    connect( mCompleteList, SIGNAL( doubleClicked( QListViewItem * ) ),
             SLOT( slotOk() ) );

    mPackageEdit = new KLineEdit( topWidget );
    mPackageEdit->setFocus();
    topLayout->addWidget( mPackageEdit );
    connect( mPackageEdit, SIGNAL( textChanged( const QString & ) ),
             SLOT( completeTyped( const QString & ) ) );
    enableButtonOK( !mPackageEdit->text().isEmpty() );
}

PackageSelectDialog::~PackageSelectDialog()
{
    delete mCompletion;
}

void PackageSelectDialog::setPackages( const Package::List &pkgs )
{
    mCompletion->clear();
    mCompletionDict.clear();
    Package::List::ConstIterator it;
    for( it = pkgs.begin(); it != pkgs.end(); ++it ) {
        PackageItem *item = new PackageItem( mCompleteList, (*it) );
        mCompletion->addItem( (*it).name() );
        mCompletionDict.insert((*it).name(),item);
    }
}

void PackageSelectDialog::recentSelected( int, QListViewItem *item )
{
    kdDebug() << "PackageSelectDialog::recentSelected()" << endl;
    if ( item ) {
        mCompleteList->clearSelection();
        // Why does a QLineEdit->setText() call emit the textChanged() signal?
        mPackageEdit->blockSignals( true );
        mPackageEdit->setText( item->text( 0 ) );
        enableButtonOK(true);
        mPackageEdit->blockSignals( false );
    }
}

void PackageSelectDialog::completeSelected( int, QListViewItem *item )
{
    if ( item ) {
        mRecentList->clearSelection();
        mPackageEdit->setText( item->text( 0 ) );
    }
}

void PackageSelectDialog::slotOk()
{
    PackageItem *item = (PackageItem *)mCompleteList->selectedItem();
    if ( item ) {
        mSelectedPackage = item->package();
        QStringList recent = KBBPrefs::instance()->mRecentPackages;
        if( !recent.contains( mSelectedPackage.name() ) ) {
            recent.prepend( mSelectedPackage.name() );
            if ( int( recent.count() ) > KBBPrefs::instance()->mRecentPackagesCount ) {
                recent.remove( recent.last() );
            }
            KBBPrefs::instance()->mRecentPackages = recent;
        }
    } else {
        QListViewItem *recentItem = mRecentList->selectedItem();
        if ( recentItem ) {
            mSelectedPackage = BugSystem::self()->package( recentItem->text( 0 ) );
        }
    }
    mCompleteList->resetTyped();
    accept();
}

Package PackageSelectDialog::selectedPackage()
{
    return mSelectedPackage;
}

Package PackageSelectDialog::getPackage( QWidget *parent )
{
    PackageSelectDialog *dlg = new PackageSelectDialog( parent );
    dlg->setPackages( BugSystem::self()->packageList() );
    dlg->exec();
    return dlg->selectedPackage();
}

void PackageSelectDialog::completeTyped( const QString &typed )
{
    kdDebug() << "completeTyped: " << typed << endl;
    QString completed = mCompletion->makeCompletion( typed );
    kdDebug() << "completed:     " << completed << endl;
    if ( !completed.isEmpty() ) {
      mCompleteList->setSelected( mCompletionDict[ completed ], true );
      mCompleteList->ensureItemVisible( mCompletionDict[ completed ] );
    } else {
      mCompleteList->resetTyped();
    }
    enableButtonOK( !typed.isEmpty() );
}
