/***************************************************************************
    begin                : Tue Nov 9 2004
    copyright            : (C) 2004 by Scott Wheeler
    email                : wheeler@kde.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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <kiconloader.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <kurldrag.h>
#include <tdeio/netaccess.h>

#include <tqimage.h>
#include <tqlayout.h>
#include <tqevent.h>
#include <tqdragobject.h>
#include <tqimage.h>
#include <tqtimer.h>
#include <tqpoint.h>

#include "nowplaying.h"
#include "playlistcollection.h"
#include "playermanager.h"
#include "coverinfo.h"
#include "covermanager.h"
#include "tag.h"
#include "playlistitem.h"
#include "collectionlist.h"
#include "historyplaylist.h"

static const int imageSize = 64;

struct Line : public TQFrame
{
    Line(TQWidget *parent) : TQFrame(parent) { setFrameShape(VLine); }
};

////////////////////////////////////////////////////////////////////////////////
// NowPlaying
////////////////////////////////////////////////////////////////////////////////

NowPlaying::NowPlaying(TQWidget *parent, PlaylistCollection *collection, const char *name) :
    TQHBox(parent, name),
    m_observer(this, collection),
    m_collection(collection)
{
    // m_observer is set to watch the PlaylistCollection, also watch for
    // changes that come from CollectionList.

    CollectionList::instance()->addObserver(&m_observer);

    layout()->setMargin(5);
    layout()->setSpacing(3);
    setFixedHeight(imageSize + 2 + layout()->margin() * 2);

    setStretchFactor(new CoverItem(this), 0);
    setStretchFactor(new TrackItem(this), 2);
    setStretchFactor(new Line(this), 0);
    setStretchFactor(new HistoryItem(this), 1);

    connect(PlayerManager::instance(), TQ_SIGNAL(signalPlay()), this, TQ_SLOT(slotUpdate()));
    connect(PlayerManager::instance(), TQ_SIGNAL(signalStop()), this, TQ_SLOT(slotUpdate()));

    hide();
}

void NowPlaying::addItem(NowPlayingItem *item)
{
    m_items.append(item);
}

PlaylistCollection *NowPlaying::collection() const
{
    return m_collection;
}

void NowPlaying::slotUpdate()
{
    FileHandle file = PlayerManager::instance()->playingFile();

    if(file.isNull()) {
        hide();
        return;
    }
    else
        show();

    for(TQValueList<NowPlayingItem *>::Iterator it = m_items.begin();
        it != m_items.end(); ++it)
    {
        (*it)->update(file);
    }
}

////////////////////////////////////////////////////////////////////////////////
// CoverItem
////////////////////////////////////////////////////////////////////////////////

CoverItem::CoverItem(NowPlaying *parent) :
    TQLabel(parent, "CoverItem"),
    NowPlayingItem(parent)
{
    setFixedHeight(parent->height() - parent->layout()->margin() * 2);
    setFrameStyle(Box | Plain);
    setLineWidth(1);
    setMargin(1);
    setAcceptDrops(true);
}

void CoverItem::update(const FileHandle &file)
{
    m_file = file;

    if(file.coverInfo()->hasCover()) {
        show();
        TQImage image = file.coverInfo()->pixmap(CoverInfo::Thumbnail).convertToImage();
        setPixmap(image.smoothScale(imageSize, imageSize, TQImage::ScaleMin));
    }
    else
        hide();
}

void CoverItem::mouseReleaseEvent(TQMouseEvent *event)
{
    if(m_dragging) {
        m_dragging = false;
        return;
    }

    if(event->x() >= 0 && event->y() >= 0 &&
       event->x() < width() && event->y() < height() &&
       event->button() == TQt::LeftButton &&
       m_file.coverInfo()->hasCover())
    {
        m_file.coverInfo()->popup();
    }
    
    TQLabel::mousePressEvent(event);
}

void CoverItem::mousePressEvent(TQMouseEvent *e)
{
    m_dragging = false;
    m_dragStart = e->globalPos();
}

void CoverItem::mouseMoveEvent(TQMouseEvent *e)
{
    if(m_dragging)
        return;

    TQPoint diff = m_dragStart - e->globalPos();
    if(TQABS(diff.x()) > 1 || TQABS(diff.y()) > 1) {

        // Start a drag.

        m_dragging = true;

        CoverDrag *drag = new CoverDrag(m_file.coverInfo()->coverId(), this);
        drag->drag();
    }
}

void CoverItem::dragEnterEvent(TQDragEnterEvent *e)
{
    e->accept(TQImageDrag::canDecode(e) || KURLDrag::canDecode(e) || CoverDrag::canDecode(e));
}

void CoverItem::dropEvent(TQDropEvent *e)
{
    TQImage image;
    KURL::List urls;
    coverKey key;

    if(e->source() == this)
        return;

    if(TQImageDrag::decode(e, image)) {
        m_file.coverInfo()->setCover(image);
        update(m_file);
    }
    else if(CoverDrag::decode(e, key)) {
        m_file.coverInfo()->setCoverId(key);
        update(m_file);
    }
    else if(KURLDrag::decode(e, urls)) {
        TQString fileName;

        if(TDEIO::NetAccess::download(urls.front(), fileName, this)) {
            if(image.load(fileName)) {
                m_file.coverInfo()->setCover(image);
                update(m_file);
            }
            else
                kdError(65432) << "Unable to load image from " << urls.front() << endl;

            TDEIO::NetAccess::removeTempFile(fileName);
        }
        else
            kdError(65432) << "Unable to download " << urls.front() << endl;
    }
}

////////////////////////////////////////////////////////////////////////////////
// TrackItem
////////////////////////////////////////////////////////////////////////////////

TrackItem::TrackItem(NowPlaying *parent) :
    TQWidget(parent, "TrackItem"),
    NowPlayingItem(parent)
{
    setFixedHeight(parent->height() - parent->layout()->margin() * 2);
    setSizePolicy(TQSizePolicy::Preferred, TQSizePolicy::Fixed);

    TQVBoxLayout *layout = new TQVBoxLayout(this);

    m_label = new LinkLabel(this);
    m_label->setLinkUnderline(false);

    layout->addStretch();
    layout->addWidget(m_label);
    layout->addStretch();

    connect(m_label, TQ_SIGNAL(linkClicked(const TQString &)), this,
            TQ_SLOT(slotOpenLink(const TQString &)));
}

void TrackItem::update(const FileHandle &file)
{
    m_file = file;
    TQTimer::singleShot(0, this, TQ_SLOT(slotUpdate()));
}

void TrackItem::slotOpenLink(const TQString &link)
{
    PlaylistCollection *collection = NowPlayingItem::parent()->collection();

    if(link == "artist")
        collection->showMore(m_file.tag()->artist());
    else if(link == "album")
        collection->showMore(m_file.tag()->artist(), m_file.tag()->album());
    else if(link == "clear")
        collection->clearShowMore();

    update(m_file);
}

void TrackItem::slotUpdate()
{
    TQString title  = TQStyleSheet::escape(m_file.tag()->title());
    TQString artist = TQStyleSheet::escape(m_file.tag()->artist());
    TQString album  = TQStyleSheet::escape(m_file.tag()->album());
    TQString separator = (artist.isNull() || album.isNull()) ? TQString() : TQString(" - ");

    // This block-o-nastiness makes the font smaller and smaller until it actually fits.

    int size = 4;
    TQString format =
        "<font size=\"+%1\"><b>%2</b></font>"
        "<br />"
        "<font size=\"+%3\"><b><a href=\"artist\">%4</a>%5<a href=\"album\">%6</a></b>";

    if(NowPlayingItem::parent()->collection()->showMoreActive())
        format.append(TQString(" (<a href=\"clear\">%1</a>)").arg(i18n("back to playlist")));

    format.append("</font>");

    do {
        m_label->setText(format.arg(size).arg(title).arg(size - 2)
                         .arg(artist).arg(separator).arg(album));
        --size;
    } while(m_label->heightForWidth(m_label->width()) > imageSize && size >= 0);

    m_label->setFixedHeight(TQMIN(imageSize, m_label->heightForWidth(m_label->width())));
}

////////////////////////////////////////////////////////////////////////////////
// HistoryItem
////////////////////////////////////////////////////////////////////////////////

HistoryItem::HistoryItem(NowPlaying *parent) :
    LinkLabel(parent, "HistoryItem"),
    NowPlayingItem(parent)
{
    setFixedHeight(parent->height() - parent->layout()->margin() * 2);
    setSizePolicy(TQSizePolicy::Preferred, TQSizePolicy::Fixed);
    setLinkUnderline(false);
    setText(TQString("<b>%1</b>").arg(i18n("History")));

    m_timer = new TQTimer(this);
    connect(m_timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotAddPlaying()));
}

void HistoryItem::update(const FileHandle &file)
{
    if(file.isNull() || (!m_history.isEmpty() && m_history.front().file == file))
        return;

    if(m_history.count() >= 10)
        m_history.remove(m_history.fromLast());

    TQString format = "<br /><a href=\"%1\"><font size=\"-1\">%2</font></a>";
    TQString current = TQString("<b>%1</b>").arg(i18n("History"));
    TQString previous;

    for(TQValueList<Item>::ConstIterator it = m_history.begin();
        it != m_history.end(); ++it)
    {
        previous = current;
        current.append(format.arg((*it).anchor).arg(TQStyleSheet::escape((*it).file.tag()->title())));
        setText(current);
        if(heightForWidth(width()) > imageSize) {
            setText(previous);
            break;
        }
    }

    m_file = file;
    m_timer->stop();
    m_timer->start(HistoryPlaylist::delay(), true);
}

void HistoryItem::openLink(const TQString &link)
{
    for(TQValueList<Item>::ConstIterator it = m_history.begin();
        it != m_history.end(); ++it)
    {
        if((*it).anchor == link) {
            if((*it).playlist) {
                CollectionListItem *collectionItem = 
                    CollectionList::instance()->lookup((*it).file.absFilePath());
                PlaylistItem *item = collectionItem->itemForPlaylist((*it).playlist);
                (*it).playlist->clearSelection();
                (*it).playlist->setSelected(item, true);
                (*it).playlist->ensureItemVisible(item);
                NowPlayingItem::parent()->collection()->raise((*it).playlist);
            }
            break;
        }
    }
}

void HistoryItem::slotAddPlaying()
{
    // More or less copied from the HistoryPlaylist

    PlayerManager *manager = PlayerManager::instance();

    if(manager->playing() && manager->playingFile() == m_file) {
        m_history.prepend(Item(TDEApplication::randomString(20),
                               m_file, Playlist::playingItem()->playlist()));
    }

    m_file = FileHandle::null();
}

#include "nowplaying.moc"