/* -*- c++ -*-
 *
 * searchtabresult.cpp
 *
 * Copyright (C) 2003-2004 Petter Stokke <ummo@hellokitty.com>
 * Copyright (C) 2003-2004 Sebastian Sauer <mail@dipe.org>
 * Copyright (C) 2006      Christian Muehlhaeuser <chris@chris.de>
 *
 * 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 Steet, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <network.h>
#include <searchinfo.h>
#include <searchquery.h>

#include <qheader.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpainter.h>
#include <qpopupmenu.h>
#include <qregexp.h>
#include <qtimer.h>
#include <qvbox.h>

#include <kdebug.h>
#include <kdeversion.h>
#include <kiconloader.h>
#include <kinputdialog.h>
#include <klineedit.h>
#include <klistview.h>
#include <klocale.h>
#include <kmimetype.h>

#include "imageloader.h"
#include "kmldonkey.h"
#include "searchcore.h"
#include "searchtabresult.h"


SearchResultItem::SearchResultItem( KListView *parent, int num, const ResultInfo *searchinfo ) : InfoItem( parent,num )
{
    number = num;
    name = searchinfo->resultName();
    names = searchinfo->resultNames();
    filesize = searchinfo->resultSize();

    availability = 0;
    const QMap<QString,QVariant>& tags = searchinfo->resultTags();
    if( tags.contains( "availability" ) )
        availability = tags["availability"].toInt();

    alreadydone = searchinfo->resultAlreadyDone();
    Network* nw = KMLDonkey::App->donkey->findNetworkNo( searchinfo->resultNetwork() );
    nwName = (nw) ? nw->networkName() : QString::number( searchinfo->resultNetwork() );
    format = searchinfo->resultFormat();
    comment = searchinfo->resultComment();
    uids = searchinfo->resultUids();
    md4 = searchinfo->resultUid( "ed2k" );

    if ( nw )
        setPixmap( 0, ImageLoader::imageForNetwork( nw ) );
    refresh();
}


SearchResultItem::~SearchResultItem()
{
}


QString SearchResultItem::xtext( int col ) const
{
    switch ( col )
    {
        case 0:
            return name;
        case 1:
            return humanReadableSize( filesize );
        case 2:
            return KGlobal::locale()->formatNumber( availability, 0 );
        case 3:
            return nwName;
        case 4:
            return KMimeType::findByURL( KURL( "file:/" + name ), 0, false, true )->comment();
        case 5:
            return format;
        case 6:
            return comment;
        case 7:
            return uids.first();

        default:
            return "ERROR";
    }
}


double SearchResultItem::numeric( int col ) const
{
    switch ( col )
    {
        case 1:
            return (double)filesize;
        case 2:
            return (double)availability;

        default:
            return 0.0;
    }
}


bool SearchResultItem::isNumeric( int col ) const
{
    switch ( col )
    {
        case 1:
        case 2:
            return true;

        default:
            return false;
    }
}


void SearchResultItem::paintCell( QPainter* p, const QColorGroup& cg, int col, int w, int align )
{
    QColorGroup colgrp( cg );
    if ( KMLDonkey::App->coloredViews )
    {
        if ( alreadydone )
            colgrp.setColor( QColorGroup::Text, KMLDonkey::App->colorSearchAlreadyDone );
        else
            if ( availability < (int32)KMLDonkey::App->searchThreshold )
                colgrp.setColor( QColorGroup::Text, KMLDonkey::App->colorSearchFewSources );
            else
                colgrp.setColor( QColorGroup::Text, KMLDonkey::App->colorSearchManySources );
    }

    p->save();
    InfoItem::paintCell( p, colgrp, col, w, align );
    p->restore();
}


SearchResultView::SearchResultView( QWidget *parent, const char *name )
    : InfoList( parent, name, true )
    , QToolTip( viewport() )
{
    addColumn( i18n( "File name" ), 300 );
    addColumn( i18n( "Size" ) );
    addColumn( i18n( "Availability" ) );
    addColumn( i18n( "Network" ) );
    addColumn( i18n( "File type" ) );
    addColumn( i18n( "Format" ) );
    addColumn( i18n( "Comment" ) );
    addColumn( i18n( "Hash" ) );

    initialise();
}


void SearchResultView::maybeTip( const QPoint& p )
{
    SearchResultItem* item = (SearchResultItem*)itemAt( p );
    if ( !item )
        return;

    QRect r( itemRect( item ) );
    if ( !r.isValid() )
        return;

    QHeader* h = header();
    if ( !h )
        return;

    int cell = h->mapToLogical( h->cellAt( p.x() - margin() ) );
    QStringList l;
    switch ( cell )
    {
        case 0:
            l = item->getNames();
            break;

        case 7:
            l = item->getUids();
            break;

        default:
            return;
    }

    QString s;
    if ( l.count() == 1 )
        s = l.first();
    else
        for ( unsigned int i = 1; i < l.count(); i++ )
        {
            if ( i > 1 ) s += "<br>";
            s += "<nobr>" + l[i] + "</nobr>";
        }

    tip( r, s );
}


SearchResult::SearchResult( QWidget *parent, const QString &tablabel, int sno )
    : SearchTabInterface( parent, "searchResult", tablabel, sno )
    , visibleCount( 0 )
{
    statusBox = new QHBox(this, "resultBox");

    QHBox *filterbox = new QHBox(statusBox, "filterBox");
    new QLabel(i18n("Filter"), filterbox);
    filterEdit = new KLineEdit(filterbox);
    connect(filterEdit, SIGNAL( textChanged(const QString &) ), this, SLOT( filterChanged() ));
    filterTimer = new QTimer(this);
    connect(filterTimer, SIGNAL( timeout() ), this, SLOT( filterTimerDone() ));

    statusLabel = new QLabel(i18n("zero of zero search results", "0/0"), statusBox);
    statusLabel->setFrameStyle(QFrame::Sunken + QFrame::Box);
    searchLabel = new KSqueezedTextLabel(statusBox);
    searchLabel->setFrameStyle(QFrame::Sunken + QFrame::Box);
    statusBox->setStretchFactor(searchLabel,1);

    resultView = new SearchResultView( this, "searchResult" );
    connect(resultView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
            this, SLOT(contextSearchResult(KListView*, QListViewItem*, const QPoint&)));
    connect(resultView, SIGNAL(doubleClicked(QListViewItem*)),
            this, SLOT(doubleClick(QListViewItem*)));
}


SearchResult::~SearchResult()
{
}


void SearchResult::contextSearchResult(KListView*,QListViewItem*,const QPoint& pt)
{
    QPopupMenu *pop = (QPopupMenu*)(KMLDonkey::App->factory())->container("search_actions", KMLDonkey::App);
    if (!pop)
        KMLDonkey::App->showBadInstallDialog();
    else
        pop->popup(pt);
}


void SearchResult::doubleClick(QListViewItem*)
{
    DownloadSelectedItems(false, true);
}


void SearchResult::addItem( const ResultInfo *searchinfo )
{
    if ( m_hashes.end() != m_hashes.find( searchinfo->resultUid( "ed2k" ) ) )
        return;
    m_hashes.append( searchinfo->resultUid( "ed2k" ) );

    SearchResultItem* item = new SearchResultItem( resultView, searchinfo->resultNo(), searchinfo );
    bool visible = ! filterItem( item );
    if ( visible ) visibleCount++;
    item->setVisible( visible );

    setStatusLabel();
}


void SearchResult::DownloadSelectedItems(bool force, bool askForFilename)
{
    QStringList names;
    QString filename;
    bool ok;
    QPtrList<QListViewItem> list = resultView->selectedItems();
    SearchResultItem *item;
    for (item = (SearchResultItem*)list.first(); item; item = (SearchResultItem*)list.next()) {
        filename = item->text(0);
        if (askForFilename || ! filename.length()) {
            filename = KInputDialog::getText( i18n("Download As"),
                                              i18n("Choose a filename for the new download:"),
                                              filename, &ok, this );
            if (! ok) continue;
        }
        names.clear();
        names.append(filename);
        if (filename != item->text(0)) names.append(item->text(0));
        KMLDonkey::App->donkey->startDownload(names, item->getNum(), force);
    }
}


void SearchResult::filterChanged()
{
    filterTimer->stop();
    if (resultView->childCount()) filterTimer->start(500, true);
}


void SearchResult::filterTimerDone()
{
    visibleCount = 0;
    filters = QStringList::split(" ", filterEdit->text().lower().stripWhiteSpace().simplifyWhiteSpace() );
    QListViewItemIterator it(resultView);
    bool visible;
    for ( ; it.current(); ++it ) {
        visible = ! filterItem( (SearchResultItem*)it.current() );
        if(visible) visibleCount++;
        it.current()->setVisible(visible);
        if (it.current()->isSelected() && ! visible) it.current()->setSelected(false);
    }
    setStatusLabel();
}


void SearchResult::setStatusLabel()
{
    statusLabel->setText( i18n("visible/total search results", "%1/%2").arg(KGlobal::locale()->formatNumber(visibleCount, 0))
                          .arg(KGlobal::locale()->formatNumber(resultView->childCount(), 0)) );
}


bool SearchResult::filterItem(SearchResultItem *item)
{
    unsigned int i;
    bool minsize;
    int64 size;
    for (i = 0; i < filters.count(); i++) {
        minsize = filters[i].startsWith(">");
        if (minsize || filters[i].startsWith("<")) { // filter max/min filesize
            size = filesizeStr2Int( filters[i].right(filters[i].length() - 1) );
            if (minsize) {
                if (item->getSize() <= size) return true;
            }
            else {
                if (item->getSize() >= size) return true;
            }
        }
        else { // filter filename
            if (filters[i].startsWith("~")) { // regular expression
                QRegExp rx( filters[i].right(filters[i].length() - 1) );
                if (rx.search( item->text(0) ) < 0) return true;
            }
            else if (! item->text(0).contains(filters[i], false))
                return true;
        }
    }
    return false;
}

#include "searchtabresult.moc"

