/*
  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.
*/

/*
  Copyright (C) 2004 Peter Simonsson <psn@linux.se>
  Copyright (C) 2006-2008 Eike Hein <hein@kde.org>
*/

#include "topiclabel.h"
#include "konversationapplication.h"
#include "connectionmanager.h"
#include "server.h"
#include "common.h"
#include "channel.h"

#include <tqsimplerichtext.h>
#include <tqtooltip.h>
#include <tqclipboard.h>

#include <krun.h>
#include <kprocess.h>
#include <kshell.h>
#include <kurldrag.h>
#include <kstringhandler.h>
#include <tdeglobal.h>
#include <kdebug.h>
#include <tdepopupmenu.h>
#include <kiconloader.h>
#include <kbookmarkmanager.h>
#include <tdeversion.h>


namespace Konversation
{

    TopicLabel::TopicLabel(TQWidget *parent, const char *name)
        : KActiveLabel(parent, name)
    {
        setWrapPolicy(TQTextEdit::AtWordOrDocumentBoundary);
        setFocusPolicy(TQWidget::ClickFocus);

        m_isOnChannel = false;
        m_copyUrlMenu = false;
        mousePressed=false;

        m_popup = new TQPopupMenu(this,"topiclabel_context_menu");
        m_popup->insertItem(SmallIconSet("edit-copy"),i18n("&Copy"),Copy);
        m_popup->insertItem(i18n("Select All"),SelectAll);

        setupChannelPopupMenu();

        connect(this, TQ_SIGNAL(highlighted(const TQString&)), this, TQ_SLOT(highlightedSlot(const TQString&)));
    }

    TopicLabel::~TopicLabel()
    {
    }

    TQSize TopicLabel::minimumSizeHint() const
    {
        int minHeight = fontMetrics().lineSpacing() + fontMetrics().descent();
        return TQSize(0, minHeight);
    }

    TQSize TopicLabel::sizeHint() const
    {
        int minHeight = fontMetrics().lineSpacing() + fontMetrics().descent();
        return TQSize(0, minHeight);
    }

    void TopicLabel::setServer(Server* server)
    {
        m_server = server;
    }

    void TopicLabel::contentsMousePressEvent(TQMouseEvent *e)
    {
        if (e->button()==TQt::LeftButton)
        {
            pressPosition=e->pos();
            urlToDrag = anchorAt(pressPosition);
            // HACK Replace % with \x03 in the url to keep TQt from doing stupid things
            urlToDrag = urlToDrag.replace ('\x03', "%");
            // Hack to counter the fact that we're given an decoded url
            urlToDrag = KURL::fromPathOrURL(urlToDrag).url();
            if (!urlToDrag.isNull())
            {
                mousePressed=true;
                return;
            }
        }
        KActiveLabel::contentsMousePressEvent(e);
    }

    void TopicLabel::contentsMouseReleaseEvent(TQMouseEvent *e)
    {
        if (e->button()==TQt::LeftButton)
        {
            if (mousePressed) openLink(urlToDrag);
            mousePressed=false;
        }
        KActiveLabel::contentsMouseReleaseEvent(e);
    }

    void TopicLabel::contentsMouseMoveEvent(TQMouseEvent *e)
    {
        if (mousePressed && (pressPosition-e->pos()).manhattanLength() > TQApplication::startDragDistance())
        {
            mousePressed=false;
            removeSelection();
            KURL ux = KURL::fromPathOrURL(urlToDrag);
            //FIXME consistent IRC URL serialization
            if (urlToDrag.startsWith("##")) ux=TQString("irc://%1:%2/%3").arg(m_server->getServerName()).
                    arg(m_server->getPort()).arg(urlToDrag.mid(2));
            KURLDrag* u=new KURLDrag(ux,viewport());
            u->drag();
        }
        KActiveLabel::contentsMouseMoveEvent(e);
    }

    void TopicLabel::leaveEvent(TQEvent*)
    {
       emit clearStatusBarTempText();
       m_lastStatusText = TQString();
    }

    void TopicLabel::openLink(const TQString& link)
    {
        if (!link.isEmpty())
        {
            if (link.startsWith("irc://"))
            {
                KonversationApplication* konvApp = static_cast<KonversationApplication*>(kapp);
                konvApp->getConnectionManager()->connectTo(Konversation::SilentlyReuseConnection, link);
            }
            else if (link.startsWith("#") && m_server && m_server->isConnected())
            {
                TQString channel(link);
                channel.replace("##","#");
                m_server->sendJoinCommand(channel);
            }
            // Always use KDE default mailer.
            else if (!Preferences::useCustomBrowser() || link.lower().startsWith("mailto:"))
            {
                new KRun(KURL::fromPathOrURL(link));
            }
            else
            {
                TQString cmd = Preferences::webBrowserCmd();
                cmd.replace("%u",KURL::fromPathOrURL(link).url());
                TDEProcess *proc = new TDEProcess;
                TQStringList cmdAndArgs = KShell::splitArgs(cmd);
                *proc << cmdAndArgs;
                //      This code will also work, but starts an extra shell process.
                //      kdDebug() << "IRCView::linkClickSlot(): cmd = " << cmd << endl;
                //      *proc << cmd;
                //      proc->setUseShell(true);
                proc->start(TDEProcess::DontCare);
                delete proc;
            }
        }
    }

    void TopicLabel::contentsContextMenuEvent(TQContextMenuEvent* ev)
    {
        bool block = contextMenu(ev);

        if(!block)
        {
            KActiveLabel::contentsContextMenuEvent(ev);
        }
    }

    bool TopicLabel::contextMenu(TQContextMenuEvent* ce)
    {
        if (m_isOnChannel)
        {
            m_channelPopup->exec(ce->globalPos());
            m_isOnChannel = false;
        }
        else
        {
            m_popup->setItemEnabled(Copy,(hasSelectedText()));

            int r = m_popup->exec(ce->globalPos());

            switch(r)
            {
                case -1:
                    // dummy. -1 means, no entry selected. we don't want -1to go in default, so
                    // we catch it here
                    break;
                case Copy:
                    copy();
                    break;
                case CopyUrl:
                {
                    TQClipboard *cb = TDEApplication::kApplication()->clipboard();
                    cb->setText(m_urlToCopy,TQClipboard::Selection);
                    cb->setText(m_urlToCopy,TQClipboard::Clipboard);
                    break;
                }
                case SelectAll:
                    selectAll();
                    break;
                case Bookmark:
                {
                    KBookmarkManager* bm = KBookmarkManager::userBookmarksManager();
                    KBookmarkGroup bg = bm->addBookmarkDialog(m_urlToCopy, TQString());
                    bm->save();
                    bm->emitChanged(bg);
                    break;
                }
                default:
                    break;
            }
        }
        return true;
    }

    void TopicLabel::setupChannelPopupMenu()
    {
        m_channelPopup = new TDEPopupMenu(this,"channel_context_menu");
        m_channelPopupId = m_channelPopup->insertTitle(m_currentChannel);
        m_channelPopup->insertItem(i18n("&Join"),Konversation::Join);
        m_channelPopup->insertItem(i18n("Get &user list"),Konversation::Names);
        m_channelPopup->insertItem(i18n("Get &topic"),Konversation::Topic);

        connect(m_channelPopup, TQ_SIGNAL(activated(int)), this, TQ_SIGNAL(popupCommand(int)));
    }

    void TopicLabel::setText(const TQString& text)
    {
        m_fullText = text;
        updateSqueezedText();
    }

    void TopicLabel::updateSqueezedText()
    {
        TQToolTip::remove(this);

        if (m_fullText.isEmpty())
        {
            KActiveLabel::setText(TQString());

            return;
        }

        TQFontMetrics fm(currentFont());
        TQString text = m_fullText;
        // text.replace("&", "&amp;"). Not needed as we do it in tagURLs
        text.replace("<", "\x0blt;"). // tagUrls will replace \x0b with &
            replace(">", "\x0bgt;");
        text = tagURLs(text, "", false);

        if(height() < (fm.lineSpacing() * 2))
        {
            text = rPixelSqueeze(text, visibleWidth() - 10);
            setWordWrap(NoWrap);
            TQToolTip::add(this, "<qt>" + TQStyleSheet::escape(m_fullText) + "</qt>");
        }
        else
        {
            setWordWrap(WidgetWidth);

            if(height() < contentsHeight())
            {
                TQToolTip::add(this, "<qt>" + TQStyleSheet::escape(m_fullText) + "</qt>");
            }
        }

        KActiveLabel::setText("<qt>" + text + "</qt>");
    }

    void TopicLabel::resizeEvent(TQResizeEvent* ev)
    {
        KActiveLabel::resizeEvent(ev);
        updateSqueezedText();
    }

    TQString TopicLabel::rPixelSqueeze(const TQString& text, uint maxPixels)
    {
        TQFontMetrics fm(currentFont());
        uint tw = textWidth(text, fm);

        if(tw > maxPixels)
        {
            TQString tmp = text;
            const uint em = fm.maxWidth();
            maxPixels -= fm.width("...");
            int len, delta;

            while((tw > maxPixels) && !tmp.isEmpty())
            {
                len = tmp.length();
                delta = (tw - maxPixels) / em;
                delta = kClamp(delta, 1, len);

                tmp.remove(len - delta, delta);
                tw = textWidth(tmp, fm);
            }

            return tmp.append("...");
        }

        return text;
    }

    uint TopicLabel::textWidth(const TQString& text, const TQFontMetrics& fm)
    {
        TQSimpleRichText richText("<qt>" + text + "</qt>", currentFont());
        richText.setWidth(fm.width(text));

        return richText.widthUsed();
    }

    void TopicLabel::highlightedSlot(const TQString& _link)
    {
        TQString link = KURL::fromPathOrURL(_link).url();
        //we just saw this a second ago.  no need to reemit.
        if (link == m_lastStatusText && !link.isEmpty())
            return;

        // remember current URL to overcome link clicking problems in TQTextBrowser
        m_highlightedURL = link;

        if (link.isEmpty())
        {
            if (!m_lastStatusText.isEmpty())
            {
                emit clearStatusBarTempText();
                m_lastStatusText = TQString();
            }
        } else {
            m_lastStatusText = link;
        }

        if (!link.startsWith("#"))
        {
            m_isOnChannel = false;

            if (!link.isEmpty()) {
                //link therefore != m_lastStatusText  so emit with this new text
                emit setStatusBarTempText(link);
            }
            if (link.isEmpty() && m_copyUrlMenu)
            {
                m_popup->removeItem(CopyUrl);
                m_popup->removeItem(Bookmark);
                m_copyUrlMenu = false;
            }
            else if (!link.isEmpty() && !m_copyUrlMenu)
            {
                m_popup->insertItem(SmallIcon("edit-copy"), i18n("Copy URL to Clipboard"), CopyUrl, 0);
                m_popup->insertItem(SmallIcon("bookmark"), i18n("Add to Bookmarks"), Bookmark, 1);
                m_copyUrlMenu = true;
                m_urlToCopy = link;
            }
        }
        else if (link.startsWith("##"))
        {
            m_currentChannel = link.mid(1);

            emit currentChannelChanged(m_currentChannel);

            TQString prettyId = m_currentChannel;

            if (prettyId.length()>15)
            {
                prettyId.truncate(15);
                prettyId.append("...");
            }

            m_channelPopup->changeTitle(m_channelPopupId,prettyId);
            m_isOnChannel = true;
            emit setStatusBarTempText(i18n("Join the channel %1").arg(m_currentChannel));
        }
    }
}

#include "topiclabel.moc"
