/***************************************************************************
 *   Copyright (C) 2004 by Paulo Moura Guedes                              *
 *   moura@tdewebdev.org                                                        *
 *                                                                         *
 *   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 <klocale.h>
#include <kiconloader.h>
#include <kapplication.h>
#include <kurl.h>
#include <krun.h>
#include <dcopref.h>
#include <kmessagebox.h>
#include <dcopclient.h>
#include <kcharsets.h>

#include <tqvaluevector.h>
#include <tqheader.h>
#include <tqclipboard.h>

#include "treeview.h"
#include "../global.h"
#include "../engine/linkstatus.h"
#include "../engine/linkfilter.h"
#include "../cfg/klsconfig.h"


TreeView::TreeView(TQWidget *parent, const char *name)
        : KListView(parent, name),
        ResultView(),
        current_column_(0)
{
    setShowToolTips(true);
    //setAllColumnsShowFocus(true);
    setSorting(1000); // don't start sorting any column
    setShowSortIndicator(true);
    //setFocusPolicy( WheelFocus );
    setRootIsDecorated(KLSConfig::displayTreeView());
//     setResizeMode(TQListView::LastColumn);

    sub_menu_ = new TQPopupMenu(this, "sub_menu_referrers");
    
    connect(this, TQT_SIGNAL( rightButtonClicked ( TQListViewItem *, const TQPoint &, int )),
            this, TQT_SLOT( slotPopupContextMenu( TQListViewItem *, const TQPoint &, int )) );
}


TreeView::~TreeView()
{
   saveLayout(KLSConfig::self()->config(), "klinkstatus");
}

void TreeView::setColumns(TQStringList const& columns)
{
    ResultView::setColumns(columns);
    removeColunas();

//     resetColumns is called automatically
    for(uint i = 0; i != columns.size(); ++i)
    {
        addColumn(i18n(columns[i]));        
        setColumnWidthMode(i, TQListView::Manual);
    }

    setColumnAlignment(col_status_ - 1, TQt::AlignCenter);
    if(KLSConfig::showMarkupStatus())
        setColumnAlignment(col_markup_ - 1, TQt::AlignCenter);
}

void TreeView::resetColumns()
{
    setColumnWidth(col_url_ - 1, (int)(0.45 * width()));
    
    setResizeMode(TQListView::LastColumn); // fit to the window
    // resize again
    setColumnWidthMode(col_label_ - 1, TQListView::Manual);
    setResizeMode(TQListView::NoColumn);
}

double TreeView::columnsWidth() const
{
    kdDebug(23100) << "columns: " << columns() << endl;
    
    double width = 0.0;
    for(int i = 0; i != columns(); ++i)
    {
        kdDebug(23100) << "column width: " << columnWidth(i) << endl;
        width += columnWidth(i);
    }
    return width;
}

void TreeView::clear()
{
    KListView::clear();
}

void TreeView::removeColunas()
{
    clear();
}

void TreeView::show(ResultView::Status const& status)
{
    TQListViewItemIterator it(static_cast<KListView*> (this));
    while(it.current())
    {
        TreeViewItem* item = myItem(it.current());
        if(!ResultView::displayableWithStatus(item->linkStatus(), status))
        {
            item->setVisible(false);
            //kdDebug(23100) << "Hide: " << item->linkStatus()->absoluteUrl().url() << endl;
        }
        else
        {
            item->setVisible(true);
            //item->setEnabled(true);
            /*
            if(KLSConfig::displayTreeView() && status != ResultView::good && item->parent())
            {
                TreeViewItem* parent = myItem(item->parent());
                while(parent)
                {
                    kdDebug(23100) << "Show: " << parent->linkStatus()->absoluteUrl().url() << endl;

                    parent->setVisible(true);
                    //parent->setEnabled(false);
                    
                    if(parent->parent())
                        parent = myItem(parent->parent());
                    else
                        parent = 0;
                }
            }
            */
        }
//         
        ++it;
    }
}

void TreeView::show(LinkMatcher link_matcher)
{
    TQListViewItemIterator it(this);
    while(it.current())
    {
        TreeViewItem* item = myItem(it.current());
        bool match = link_matcher.matches(*(item->linkStatus()));
        
        if(tree_display_)
            item->setEnabled(match);
        else
            item->setVisible(match);
        
        ++it;
    }
}

void TreeView::showAll()
{
    TQListViewItemIterator it(this);
    while(it.current())
    {
        it.current()->setVisible(true);
        //it.current()->setEnabled(true);
        ++it;
    }
}

void TreeView::ensureRowVisible(const TQListViewItem * i, bool tree_display)
{
    TQScrollBar* vertical_scroll_bar = verticalScrollBar();

    if(tree_display ||
            vertical_scroll_bar->value() > (vertical_scroll_bar->maxValue() - vertical_scroll_bar->lineStep()))
        ensureItemVisible(i);
}

bool TreeView::isEmpty() const
{
    return !childCount();
}

void TreeView::resizeEvent(TQResizeEvent *e)
{
    KListView::resizeEvent(e);
    resetColumns();
    clipper()->repaint();
}

void TreeView::slotPopupContextMenu(TQListViewItem* item, const TQPoint& pos, int col)
{
    current_column_ = col;
    
    TreeViewItem* tree_item = myItem(item);
    if(tree_item)
    {
        TQValueVector<KURL> referrers = tree_item->linkStatus()->referrers();
        loadContextTableMenu(referrers, tree_item->linkStatus()->isRoot());
        context_table_menu_.popup(pos);
    }
}

void TreeView::slotCopyUrlToClipboard() const
{
    TreeViewItem* _item = myItem(currentItem());
    TQString content(_item->linkStatus()->absoluteUrl().prettyURL());
    TQClipboard* cb = kapp->clipboard();
    cb->setText(content);
}

void TreeView::slotCopyParentUrlToClipboard() const
{
    TreeViewItem* _item = myItem(currentItem());
    TQString content(_item->linkStatus()->parent()->absoluteUrl().prettyURL());
    TQClipboard* cb = kapp->clipboard();
    cb->setText(content);
}

void TreeView::slotCopyCellTextToClipboard() const
{
    TreeViewItem* _item = myItem(currentItem());
    TQString cell_text(_item->text(current_column_));
    TQClipboard* cb = kapp->clipboard();
    cb->setText(cell_text);
}

void TreeView::slotEditReferrersWithQuanta()
{
    TreeViewItem* _item = myItem(currentItem());
    TQValueVector<KURL> referrers = _item->linkStatus()->referrers();

    if(Global::isQuantaAvailableViaDCOP())
    {
        for(uint i = 0; i != referrers.size(); ++i)
            slotEditReferrerWithQuanta(referrers[i]);
    }
    else
    {
        TQStringList list_urls;

        for(uint i = 0; i != referrers.size(); ++i)
            list_urls.append(referrers[i].url());

        Global::openQuanta(list_urls);
    }
}

void TreeView::slotEditReferrerWithQuanta(int id)
{
    int index = sub_menu_->indexOf(id);

    if(index == 0)
        return;
    Q_ASSERT(index != -1);
    Q_ASSERT(index != 1); // separator

    //kdDebug(23100) << "id: " << id << endl;
    //kdDebug(23100) << "index: " << index << endl;

    index -= 2; // The list of referrers starts on index = 2

    TreeViewItem* _item = myItem(currentItem());
    TQValueVector<KURL> referrers = _item->linkStatus()->referrers();
    Q_ASSERT(index >= 0 && (uint)index < referrers.size());

    slotEditReferrerWithQuanta(referrers[index]);
}

void TreeView::slotEditReferrerWithQuanta(KURL const& url)
{
    TQString filePath = url.url();

    if(Global::isQuantaAvailableViaDCOP())
    {
        DCOPRef quanta(Global::quantaDCOPAppId(),"WindowManagerIf");
        bool success = quanta.send("openFile", filePath, 0, 0);

        if(!success)
        {
            TQString message = i18n("<qt>File <b>%1</b> cannot be opened. Might be a DCOP problem.</qt>").arg(filePath);
            KMessageBox::error(parentWidget(), message);
        }
    }
    else
    {
        TQStringList args(url.url());
        Global::openQuanta(args);
    }
}

void TreeView::slotViewUrlInBrowser()
{
    TreeViewItem* _item = myItem(currentItem());
    KURL url = _item->linkStatus()->absoluteUrl();

    if(url.isValid())
    {
        (void) new KRun (url, 0, url.isLocalFile(), true);
    }
    else
        KMessageBox::sorry(this, i18n("Invalid URL."));
}

void TreeView::slotViewParentUrlInBrowser()
{
    TreeViewItem* _item = myItem(currentItem());
 
    if(_item->linkStatus()->isRoot())
    {
        KMessageBox::sorry(this, i18n("ROOT URL."));
    }
    else
    {
        LinkStatus const* ls_parent = _item->linkStatus()->parent();
        Q_ASSERT(ls_parent);

        KURL url = ls_parent->absoluteUrl();

        if(url.isValid())
            (void) new KRun (url, 0, url.isLocalFile(), true);
        else
            KMessageBox::sorry(this, i18n("Invalid URL."));
    }
}

void TreeView::loadContextTableMenu(TQValueVector<KURL> const& referrers, bool is_root)
{
    context_table_menu_.clear();
    sub_menu_->clear();

    if(!is_root)
    {
        sub_menu_->insertItem(i18n("All"), this, TQT_SLOT(slotEditReferrersWithQuanta()));
        sub_menu_->insertSeparator();

        for(uint i = 0; i != referrers.size(); ++i)
        {
            sub_menu_->insertItem(referrers[i].prettyURL());
        }
        connect(sub_menu_, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotEditReferrerWithQuanta(int)));

        context_table_menu_.insertItem(SmallIconSet("edit"), i18n("Edit Referrer with Quanta"),
                                       sub_menu_);
        context_table_menu_.insertSeparator();
    }
    else
    {
        int id = context_table_menu_.insertItem(SmallIconSet("fileopen"), i18n("Edit Referrer with Quanta"));
        context_table_menu_.setItemEnabled(id, false);
    }

    context_table_menu_.insertItem(SmallIconSet("fileopen"), i18n("Open URL"),
                                   this, TQT_SLOT(slotViewUrlInBrowser()));

    context_table_menu_.insertItem(/*SmallIconSet("fileopen"), */i18n("Open Referrer URL"),
                                   this, TQT_SLOT(slotViewParentUrlInBrowser()));

    context_table_menu_.insertSeparator();

    context_table_menu_.insertItem(SmallIconSet("editcopy"), i18n("Copy URL"),
                                   this, TQT_SLOT(slotCopyUrlToClipboard()));

    context_table_menu_.insertItem(/*SmallIconSet("editcopy"), */i18n("Copy Referrer URL"),
                                   this, TQT_SLOT(slotCopyParentUrlToClipboard()));

    context_table_menu_.insertItem(/*SmallIconSet("editcopy"), */i18n("Copy Cell Text"),
                                   this, TQT_SLOT(slotCopyCellTextToClipboard()));
}

TreeViewItem* TreeView::myItem(TQListViewItem* item) const
{
    TreeViewItem* _item = dynamic_cast<TreeViewItem*> (item);
    Q_ASSERT(_item);
    return _item;
}


/* ******************************* TreeViewItem ******************************* */

TreeViewItem::TreeViewItem(TreeView* parent, TQListViewItem* after,
                           LinkStatus const* linkstatus)
        : KListViewItem(parent, after),
        last_child_(0), root_(parent)
{
    init(linkstatus);
}

TreeViewItem::TreeViewItem(TreeView* root, TQListViewItem* listview_item, TQListViewItem* after,
                           LinkStatus const* linkstatus)
        : KListViewItem(listview_item, after),
        last_child_(0), root_(root)

{
    init(linkstatus);
}

TreeViewItem::~TreeViewItem()
{}

void TreeViewItem::init(LinkStatus const* linkstatus)
{
    setOpen(true);

    for(int i = 0; i != root_->numberOfColumns(); ++i)
    {
        TreeColumnViewItem item(root_, linkstatus, i + 1);
        column_items_.push_back(item);
        
        if(i + 1 == root_->urlColumnIndex()) {
            setText(item.columnIndex() - 1, KURL::decode_string(
                    KCharsets::resolveEntities(item.text(i + 1))));
        }
        else {
            setText(item.columnIndex() - 1, KCharsets::resolveEntities(item.text(i + 1)));
        }
        
        setPixmap(item.columnIndex() - 1, item.pixmap(i + 1));
    }
}

void TreeViewItem::setLastChild(TQListViewItem* last_child)
{
    Q_ASSERT(last_child);
    last_child_ = last_child;
}

TQListViewItem* TreeViewItem::lastChild() const
{
    return last_child_;
}

TQString TreeViewItem::key(int column, bool) const
{
    // FIXME magic numbers
    switch(column)
    {
    case 1: // status column
        return linkStatus()->statusText();
    }

    return text(column);
}

LinkStatus const* TreeViewItem::linkStatus() const
{
    return column_items_[0].linkStatus();
}

void TreeViewItem::paintCell(TQPainter * p, const TQColorGroup & cg, int column, int width, int align)
{
    TreeColumnViewItem item = column_items_[column];

    // Get a color to draw the text
    TQColorGroup m_cg(cg);
    TQColor color(item.textStatusColor());
    m_cg.setColor(TQColorGroup::Text, color);

    KListViewItem::paintCell(p, m_cg, column, width, align);

    setHeight(22);
}


/* ******************************* TreeColumnViewItem ******************************* */

TreeColumnViewItem::TreeColumnViewItem(TreeView* root, LinkStatus const* linkstatus, int column_index)
    : root_(root), ls_(linkstatus), column_index_(column_index)
{
    Q_ASSERT(ls_);
//     Q_ASSERT(column_index_ > 0);
}

TreeColumnViewItem::~TreeColumnViewItem()
{}

/*
void TreeColumnViewItem::setColumnIndex(int i)
{
    Q_ASSERT(i > 0);
    column_index_ = i;
}
*/

int TreeColumnViewItem::columnIndex() const
{
    return column_index_;
}

LinkStatus const* TreeColumnViewItem::linkStatus() const
{
    Q_ASSERT(ls_);
    return ls_;
}

TQColor const& TreeColumnViewItem::textStatusColor() const
{
    if(columnIndex() == root_->urlColumnIndex() || columnIndex() == root_->statusColumnIndex())
    {
        if(linkStatus()->status() == LinkStatus::BROKEN)
            return TQt::red;
        else if(linkStatus()->status() == LinkStatus::HTTP_CLIENT_ERROR)
            return TQt::red;
        else if(linkStatus()->status() == LinkStatus::HTTP_REDIRECTION)
            return TQt::black;
        else if(linkStatus()->status() == LinkStatus::HTTP_SERVER_ERROR)
            return TQt::darkMagenta;
        else if(linkStatus()->status() == LinkStatus::MALFORMED)
            return TQt::red;
        else if(linkStatus()->status() == LinkStatus::NOT_SUPPORTED)
            return TQt::lightGray;
        else if(linkStatus()->status() == LinkStatus::SUCCESSFULL)
            return TQt::black;
        else if(linkStatus()->status() == LinkStatus::TIMEOUT)
            return TQt::darkMagenta;
        else if(linkStatus()->status() == LinkStatus::UNDETERMINED)
            return TQt::blue;
        
        return TQt::red;
    }        
    else
        return TQt::black;
}


TQString TreeColumnViewItem::text(int column) const
{
    Q_ASSERT(column > 0);

    
    if(column == root_->urlColumnIndex())
    {
        if(linkStatus()->node() && linkStatus()->malformed())
        {
            if(linkStatus()->node()->url().isEmpty())
                return linkStatus()->node()->content().simplifyWhiteSpace();
            else
                return linkStatus()->node()->url();
        }
        else
        {
            KURL url = linkStatus()->absoluteUrl();
            return Url::convertToLocal(linkStatus());
        }        
    }
    else if(column == root_->statusColumnIndex())
    {
        return TQString();
    }
    else if(column == root_->labelColumnIndex())
    {
        TQString label(linkStatus()->label());
        if(!label.isNull())
            return label.simplifyWhiteSpace();
    }
        
    return TQString();
}

TQPixmap TreeColumnViewItem::pixmap(int column) const
{
    Q_ASSERT(column > 0);

    if(column == root_->statusColumnIndex())
    {
        if(linkStatus()->status() == LinkStatus::BROKEN)
            return SmallIcon("no");
        else if(linkStatus()->status() == LinkStatus::HTTP_CLIENT_ERROR)
            return SmallIcon("no");
        else if(linkStatus()->status() == LinkStatus::HTTP_REDIRECTION) 
        {
            if(linkStatus()->statusText() == "304")
                return UserIcon("304");
            else
                return SmallIcon("redo");
        }
        else if(linkStatus()->status() == LinkStatus::HTTP_SERVER_ERROR)
            return SmallIcon("no");
        else if(linkStatus()->status() == LinkStatus::MALFORMED)
            return SmallIcon("editdelete");
        else if(linkStatus()->status() == LinkStatus::NOT_SUPPORTED)
            return SmallIcon("help");
        else if(linkStatus()->status() == LinkStatus::SUCCESSFULL)
            return SmallIcon("ok");
        else if(linkStatus()->status() == LinkStatus::TIMEOUT)
            return SmallIcon("history_clear");
        else if(linkStatus()->status() == LinkStatus::UNDETERMINED)
            return SmallIcon("help");
    }
    
    return TQPixmap();
}


#include "treeview.moc"
