/***************************************************************************
 *   Copyright (C) 2004, 2005 Max Howell <max.howell@methylblue.com>       *
 *                                                                         *
 *   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 "amarok.h"
#include "amarokconfig.h"
#include "browserbar.h"
#include "debug.h"
#include "enginecontroller.h"
#include "multitabbar.h"   //m_tabBar

#include <tdeapplication.h>  //kapp
#include <tdeconfig.h>
#include <kiconloader.h>   //multiTabBar icons
#include <tdelocale.h>

#include <tqcursor.h>       //for resize cursor
#include <tqpainter.h>
#include <tqsignalmapper.h> //m_mapper
#include <tqstyle.h>        //Amarok::Splitter
#include <tqtooltip.h>


// we emulate a qsplitter, mostly for historic reasons, but there are still a few advantages
// mostly we can stop the browserbar getting resized too small so that switching browser looks wrong


namespace Amarok
{
    class Splitter : public TQWidget {
    public:
        Splitter( BrowserBar *w ) : TQWidget( w, "divider" )
        {
            setCursor( TQCursor(SplitHCursor) );
            styleChange( style() );
        }

        virtual void paintEvent( TQPaintEvent* )
        {
            TQPainter p( this );
            parentWidget()->style().drawPrimitive( TQStyle::PE_Splitter, &p, rect(), colorGroup(), TQStyle::Style_Horizontal );
        }

        virtual void styleChange( TQStyle& )
        {
            setFixedWidth( style().pixelMetric( TQStyle::PM_SplitterWidth, this ) );
        }

        virtual void mouseMoveEvent( TQMouseEvent *e )
        {
            static_cast<BrowserBar*>(parent())->mouseMovedOverSplitter( e );
        }
    };
}

BrowserBar* BrowserBar::s_instance = 0;

BrowserBar::BrowserBar( TQWidget *parent )
        : TQWidget( parent, "BrowserBar" )
        , EngineObserver( EngineController::instance() )
        , m_playlistBox( new TQVBox( this ) )
        , m_divider( new Amarok::Splitter( this ) )
        , m_browserBox( new TQVBox( this ) )
        , m_currentIndex( -1 )
        , m_lastIndex( -1 )
        , m_mapper( new TQSignalMapper( this ) )
{
    m_tabManagementButton = new TQPushButton( SmallIconSet(Amarok::icon( "configure" )), 0, this, "tab_managment_button" );
    connect (m_tabManagementButton, TQ_SIGNAL(clicked()), TQ_SLOT(showBrowserSelectionMenu()));
    m_tabManagementButton->setIsMenuButton ( true ); //deprecated, but since I cannot add menu directly to button it is needed.

    TQToolTip::add (m_tabManagementButton, i18n("Manage tabs")); 


    m_tabBar = new MultiTabBar( MultiTabBar::Vertical, this );


    m_tabManagementButton->setFixedWidth(m_tabBar->sizeHint().width());
    m_tabManagementButton->setFixedHeight(m_tabBar->sizeHint().width());


    s_instance = this;
    m_pos = m_tabBar->sizeHint().width() + 5; //5 = esthetic spacing

    m_tabBar->setStyle( MultiTabBar::AMAROK );
    m_tabBar->setPosition( MultiTabBar::Left );
    m_tabBar->showActiveTabTexts( true );
    m_tabBar->setFixedWidth( m_pos );
    m_tabBar->move( 0, 25 );

    if (m_browserBox && (!m_browserBox->layout())) {
        TQVBoxLayout *layout = new TQVBoxLayout( m_browserBox );
        layout->addSpacing( 3 ); // aesthetics
        layout->setAutoAdd( true );
    }

    m_browserBox->move( m_pos, 0 );
    m_browserBox->hide();
    m_divider->hide();
    m_playlistBox->setSpacing( 1 );

    connect( m_mapper, TQ_SIGNAL(mapped( int )), TQ_SLOT(showHideBrowser( int )) );

 


   
    //m_tabBar->appendButton( Amarok::icon( "configure" ), 1, 0, TQString() );

}

BrowserBar::~BrowserBar()
{
    TDEConfig* const config = Amarok::config( "BrowserBar" );
    config->writeEntry( "CurrentPane", m_currentIndex != -1 ? TQString(currentBrowser()->name()) : TQString() );
    config->writeEntry( "Width", m_browserBox->width() );
}

void
BrowserBar::makeDropProxy( const TQString &name, DropProxyTarget *finalTarget )
{
    int id = m_browserIds[name];
    MultiTabBarButton *button = m_tabBar->tab( id );
    if( button )
        button->proxyDrops( finalTarget );
}

int
BrowserBar::restoreWidth()
{
    const int index = indexForName( Amarok::config( "BrowserBar" )->readEntry( "CurrentPane" ) );
    const int width = Amarok::config( "BrowserBar" )->readNumEntry( "Width", browser( index )->sizeHint().width() );

    m_browserBox->resize( width, height() );
    m_pos = m_browserBox->width() + m_tabBar->width();

    return index;
}

void
BrowserBar::polish()
{
    DEBUG_FUNC_INFO

    TQWidget::polish();

    uint M = 0;
    foreachType( BrowserList, m_browsers ) {
        const uint m = (*it)->minimumWidth();
        if (m > M)
            M = m;
        if (m > 250) {
            warning() << "Browser is too large, mxcl says castrate the developer: " << (*it)->name() << ", " << M << endl;
            M = 250;
        }
    }

    m_browserBox->setMinimumWidth( M );
    const int index = restoreWidth();

    if (index != -1)
        // if we did it for -1 it ruins the browserBox size
        showHideBrowser( index );
}

void
BrowserBar::adjustWidgetSizes()
{
    //TODO set the geometry of the PlaylistWindow before
    // the browsers are loaded so this isn't called twice

    const uint w    = width();
    const uint h    = height();
    const uint maxW = maxBrowserWidth();
    const uint p    = (m_pos < maxW) ? m_pos : maxW;
    const uint ppw  = p + m_divider->width();
    const uint tbw  = m_tabBar->width();

    m_divider->move( p, 0 );

    const uint offset = !m_divider->isHidden() ? ppw : tbw;

    m_browserBox->resize( p - tbw, h );
    m_playlistBox->setGeometry( offset, 0, w - offset, h );
}

void
BrowserBar::mouseMovedOverSplitter( TQMouseEvent *e )
{
    const uint oldPos   = m_pos;
    const uint newPos   = mapFromGlobal( e->globalPos() ).x();
    const uint minWidth = m_tabBar->width() + m_browserBox->minimumWidth();
    const uint maxWidth = maxBrowserWidth();

    if( newPos < minWidth )
        m_pos = minWidth;

    else if( newPos > maxWidth )
        m_pos = maxWidth;

    else
        m_pos = newPos;

    if( m_pos != oldPos )
        adjustWidgetSizes();
}

bool
BrowserBar::event( TQEvent *e )
{
    switch( e->type() )
    {
    case TQEvent::LayoutHint:
        //FIXME include browserholder width
        setMinimumWidth(
                m_tabBar->minimumWidth() +
                m_divider->minimumWidth() +
                m_browserBox->width() +
                m_playlistBox->minimumWidth() );
        break;

    case TQEvent::Resize:
//         DEBUG_LINE_INFO

        m_divider->resize( 0, height() ); //TQt will set width
        m_tabBar->resize( 0, height() ); //TQt will set width

        adjustWidgetSizes();

        return true;

    default:
        ;
    }

    return TQWidget::event( e );
}

void
BrowserBar::addBrowser( const TQString &identifier, TQWidget *widget, const TQString &title, const TQString& icon )
{
    const int id = m_tabBar->tabs()->count(); // the next available id
    const TQString name( widget->name() );
    m_browserIds[name] = id;
    TQWidget *tab;

    widget->reparent( m_browserBox, TQPoint() );
    widget->hide();

    m_tabBar->appendTab( SmallIcon( icon ), id, title, identifier );
    tab = m_tabBar->tab( id );
    tab->setFocusPolicy( TQWidget::NoFocus ); //FIXME you can focus on the tab, but they respond to no input!

    //we use a SignalMapper to show/hide the corresponding browser when tabs are clicked
    connect( tab, TQ_SIGNAL(clicked()), m_mapper, TQ_SLOT(map()) );
    m_mapper->setMapping( tab, id );
    connect( tab, TQ_SIGNAL(initiateDrag ( int ) ), this, TQ_SLOT( showBrowser( int )) );

    m_browsers.push_back( widget );
}

void
BrowserBar::removeMediaBrowser( TQWidget *widget )
{
    BrowserList::iterator it = tqFind( m_browsers.begin(), m_browsers.end(), widget );
    if( it != m_browsers.end() )
        m_browsers.erase( it );
    TQWidget *tab;
    tab = m_tabBar->tab( m_browserIds["MediaBrowser"] );
    m_mapper->removeMappings( tab );
    m_tabBar->removeTab( m_browserIds["MediaBrowser"] );
}

void
BrowserBar::showHideBrowser( int index )
{
    const int prevIndex = m_currentIndex;

    if( m_currentIndex != -1 ) {
        ///first we need to hide the currentBrowser

        m_currentIndex = -1; //to prevent race condition, see CVS history

        m_browsers[prevIndex]->hide();
        m_tabBar->setTab( prevIndex, false );
    }

    if( index == prevIndex ) {
        ///close the BrowserBar

        m_browserBox->hide();
        m_divider->hide();

        adjustWidgetSizes();
    }

    else if( (uint)index < m_browsers.count() ) {
        ///open up target

        TQWidget* const target = m_browsers[index];
        m_currentIndex = index;

        m_divider->show();
        target->show();
        target->setFocus();
        m_browserBox->show();
        m_tabBar->setTab( index, true );

        if( prevIndex == -1 ) {
            // we need to show the browserBox
            // m_pos dictates how everything will be sized in adjustWidgetSizes()
            m_pos = m_browserBox->width() + m_tabBar->width();
            adjustWidgetSizes();
        }
    }

    emit browserActivated( index );
}

void
BrowserBar::showHideVisibleBrowser( int index )
{
    int realindex = -1;
    TQPtrList<MultiTabBarTab> tabs = *m_tabBar->tabs();
    for( int i = 0, n = tabs.count(); i < n; ++i )
    {
        if( tabs.at( i )->visible() )
            index--;
        if( index < 0 )
        {
            realindex = i;
            break;
        }
    }

    if( realindex >= 0 )
        showHideBrowser( realindex );
}

TQWidget*
BrowserBar::browser( const TQString &name ) const
{
    foreachType( BrowserList, m_browsers )
        if( name == (*it)->name() )
            return *it;

    return 0;
}

int
BrowserBar::visibleCount() const
{
    int num = 0;
    TQPtrList<MultiTabBarTab> tabs = *m_tabBar->tabs();
    for( int i = 0, n = tabs.count(); i < n; ++i )
    {
        if( tabs.at( i )->visible() )
            num++;
    }

    return num;
}

int
BrowserBar::indexForName( const TQString &name ) const
{
    for( uint x = 0; x < m_browsers.count(); ++x )
        if( name == m_browsers[x]->name() )
            return x;
    return -1;
}

void
BrowserBar::showBrowserSelectionMenu()
{
      m_tabBar->showTabSelectionMenu(mapToGlobal(TQPoint(m_tabManagementButton->pos().x(), m_tabManagementButton->pos().y() +m_tabManagementButton->height() )));
}

void
BrowserBar::engineStateChanged( Engine::State state, Engine::State oldState )
{
    if( !AmarokConfig::autoShowContextBrowser() || m_currentIndex == -1 )
        return;

    switch( state ) {
    case Engine::Playing:

        if( oldState != Engine::Paused && m_currentIndex != -1 ) {
            m_lastIndex = m_currentIndex;
            showBrowser( "ContextBrowser" );
        }
        break;

    case Engine::Empty:

        if( m_lastIndex >= 0 )
            showBrowser( m_lastIndex );

    default:
        ;
    }
}

#include "browserbar.moc"
