/*
 *
 * Copyright (C) 2002 Richard Moore <rich@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 <qaccel.h>
#include <qlcdnumber.h>
#include <qpoint.h>
#include <qslider.h>
#include <qstylesheet.h>
#include <qtooltip.h>
#include <qvbox.h>

#include <kdebug.h>
#include <klocale.h>
#include <kmainwindow.h>
#include <kmenubar.h>
#include <kstatusbar.h>
#include <ktoolbar.h>
#include <kdockwidget.h>

#include "kdetv.h"
#include "actions.h"
#include "actions.moc"

//
// LCD Number Action
//

LCDNumberAction::LCDNumberAction( const QString &text, int accel, 
                                  QObject* receiver, const char* slot, 
                                  QObject *parent, const char *name )
    :KAction( text, accel, receiver, slot, parent, name ),
     numDig(3), val("  0")
{
}

int LCDNumberAction::plug( QWidget *widget, int index )
{
    //do not call the previous implementation here

    if ( widget->inherits( "KToolBar" ) ) {
        
        KToolBar *tb = static_cast<KToolBar *>(widget);
        int id = KAction::getToolButtonID();
        
        QLCDNumber *lcd = createWidget( tb );
        tb->insertWidget( id, lcd->width(), lcd, index );
        addContainer( tb, id );
        
        connect( tb, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
        return containerCount() - 1;
    }

    if ( widget->inherits( "QPopupMenu" ) ) {
        QPopupMenu *pop = static_cast<QPopupMenu *>(widget);
        
        // Create item
        QHBox *box = new QHBox( pop );
        box->setMargin( 4 );
        box->setSpacing( 6 );
        
        // Icon
        QLCDNumber *num = createWidget( box );
        num->setFixedSize( QSize(18,18) );
        
        // Label
        QLabel *l = new QLabel( box );
        l->setText( text() );

        // Insert item
        int id = pop->insertItem( box, -1, index );
        addContainer( box, id );
        connect( box, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
        
        return containerCount() - 1;
    }

    return -1;
}

void LCDNumberAction::unplug( QWidget *widget )
{
    if ( widget->inherits( "KToolBar" ) ) {
        KToolBar *bar = static_cast<KToolBar *>(widget);
        int idx = findContainer( bar );

        if ( idx != -1 ) {
            bar->removeItem( menuId( idx ) );
            removeContainer( idx );
        }
    }
    else if ( widget->inherits( "QPopupMenu" ) ) {
        QPopupMenu *pop = static_cast<QPopupMenu *>(widget);
        
        int idx = findContainer( pop );
        if ( idx != -1 ) {
            pop->removeItem( menuId( idx ) );
            removeContainer( idx );
        }
    }
}

QLCDNumber *LCDNumberAction::createWidget( QWidget *parent, const char *name )
{
    QLCDNumber *lcd = new QLCDNumber( parent, name );
    lcd->setFrameStyle( QFrame::Panel | QFrame::Sunken );
    lcd->setLineWidth(2);
    lcd->setMidLineWidth(1);

    lcd->setSegmentStyle( QLCDNumber::Flat );
    lcd->setBackgroundColor( Qt::black );
    lcd->setPaletteForegroundColor( Qt::green );

    lcd->setNumDigits( numDig );
    lcd->display( val );

    if ( !text().isEmpty() )
        QToolTip::add( lcd, text() );

    connect( this, SIGNAL( valueChanged(const QString &) ),
             lcd, SLOT( display(const QString &) ) );
    return lcd;
}

void LCDNumberAction::setNumDigits( int nDigits )
{
    numDig = nDigits;
}

void LCDNumberAction::display( int num )
{
    display( QString::number(num) );
}

void LCDNumberAction::display( const QString &s )
{
    val = s;
    emit valueChanged( val );
}

//
// Slider Action
//

KdetvSlider::KdetvSlider( int minValue, int maxValue, int pageStep, int value, Orientation o,
                          QWidget *parent, const char* name )
    : QSlider( minValue, maxValue, pageStep, value, o, parent, name)
{
}

KdetvSlider::~KdetvSlider()
{
}

void KdetvSlider::setOrientation( Orientation o )
{
    QSlider::setOrientation(o);
    emit orientationChanged(o);
}

void KdetvSlider::updateOrientation()
{
    if (!parent()->inherits("QDockWindow"))
        return;

    QDockWindow* d = static_cast<QDockWindow*>(parent());
    setOrientation( d->orientation() );
}


SliderAction::SliderAction( int min_, int max_, int step_, int val_,
                            const QString &text, QObject *parent, 
                            const char *name )
    : KAction( parent, name ), inhibitRecursion(false), min(min_),
      max(max_), step(step_), val(val_), tickStep(-1)
{
    setText( text );
}

int SliderAction::plug( QWidget *widget, int index )
{
    //do not call the previous implementation here
    kdDebug() << "Plugging Slider into class '" << widget->className() << "'" << endl;

    if ( widget->inherits( "KToolBar" ) || widget->isA("KToolBar")) {
        KToolBar *bar = static_cast<KToolBar *>(widget);

        int id = KAction::getToolButtonID();

        KdetvSlider* s = createWidget( bar, "ToolbarSlider" );
        s->setOrientation( bar->orientation() );

        int sz = (s->orientation() == Horizontal) ? s->width() : s->height();
        bar->insertWidget( id, sz, s, index );
        addContainer( bar, id );

        connect( bar, SIGNAL( orientationChanged(Orientation) ),
                 s, SLOT( setOrientation(Orientation) ) );

        /*
         * FIXME: This is a really bad hack to get events
         *        _after_ the GUI has been created.
         *        If I don't do this, the slider orientation
         *        is not updated at startup.
         *        It seems QToolBar does not emit orientationChanged()
         *        during startup phase.
         *        This connection creates loads of unnesscessary
         *        updateOrientation() calls...
         *        I tried lots of other signals (QToolBar::visibilityChanged(),
         *        QMainWindow::dockWindowPositionChanged() and many others)
         *        but none of them works.
         */
        if (bar->mainWindow()->inherits("KDockMainWindow")) {
            KDockMainWindow* kdmw = static_cast<KDockMainWindow*>(bar->mainWindow());
            connect( kdmw->manager(), SIGNAL( change() ), 
                     s, SLOT( updateOrientation() ) );
        }

        connect( bar, SIGNAL( destroyed() ),
                 this, SLOT( slotDestroyed() ) );

        return containerCount() - 1;
    }

    if ( widget->inherits( "QPopupMenu" ) ) {
        QPopupMenu *pop = static_cast<QPopupMenu *>(widget);

        // Create item
        QHBox *box = new QHBox( pop );
        box->setMargin( 4 );
        box->setSpacing( 6 );

        // Icon
        QLabel *p = new QLabel( box );
        if ( hasIconSet() ) {
            QPixmap pix = iconSet().pixmap( QIconSet::Small, true );
            p->setPixmap( pix );
        }
        p->setFixedSize( QSize(18,18) );

        // Label
        QLabel *l = new QLabel( box );
        l->setText( text() );

        // Slider
        KdetvSlider* s = createWidget( box, "PopupSlider" );

        // Focus handling
        s->setFocusPolicy( QWidget::TabFocus );
        l->setBuddy( s );
        box->setFocusProxy( s );

        // Insert item
        int id = pop->insertItem( box, -1, index );
        addContainer( pop, id );
        connect( box, SIGNAL( destroyed() ),
                 this, SLOT( slotDestroyed() ) );

        return containerCount() - 1;
    }

    return -1;

}

void SliderAction::unplug( QWidget *widget )
{
    if ( widget->inherits( "KToolBar" ) )
        {
            KToolBar *bar = static_cast<KToolBar *>(widget);

            int idx = findContainer( bar );

            if ( idx != -1 ) {
                bar->removeItem( menuId( idx ) );
                removeContainer( idx );
            }

            return;
        }

    if ( widget->inherits( "QPopupMenu" ) ) {
        QPopupMenu *pop = static_cast<QPopupMenu *>(widget);

        int idx = findContainer( pop );

        if ( idx != -1 ) {
            pop->removeItem( menuId( idx ) );
            removeContainer( idx );
        }

        return;
    }
}

void SliderAction::setOrientation( Orientation o )
{
    const QObject* cobj = sender();
    QObject* obj = const_cast<QObject*>(cobj);
    
    if (!obj->inherits("KdetvSlider"))
        return;

    KdetvSlider* s = static_cast<KdetvSlider*>(obj);

    switch( o ) {
    case Horizontal:
        s->setTickmarks( QSlider::Below );
        disconnect( s, SIGNAL(valueChanged(int)), this, SLOT(setInverseInternal(int)) );
        connect( s, SIGNAL(valueChanged(int)), this, SLOT(setValueInternal(int)));
        s->setValue( val );
        break;
    case Vertical:
        s->setTickmarks( QSlider::Right );
        disconnect( s, SIGNAL(valueChanged(int)), this, SLOT(setValueInternal(int)));
        connect( s, SIGNAL(valueChanged(int)), this, SLOT(setInverseInternal(int)) );
        s->setValue( max-val );
        break;
    default:
        break;
    }
}

void SliderAction::setValueInternal( int num )
{
    if (inhibitRecursion)
        return;

    inhibitRecursion = true;
    setValue(num);
    inhibitRecursion = false;
    emit valueChanged(num);
}

void SliderAction::setInverseInternal( int num )
{
    setValueInternal (max - num);
} 

void SliderAction::setValue( int num )
{
    if (val == num)
        return;
    val = num;

    for (QPtrListIterator<KdetvSlider> it(_sliders);
         it.current() != 0;
         ++it) {
        if (it.current()->orientation() == Qt::Horizontal) {
            it.current()->setValue(val);
        } else {
            it.current()->setValue(max - val);
        }
    }
}

void SliderAction::setTickInterval( int ticks )
{
    tickStep = ticks;
    for (QPtrListIterator<KdetvSlider> it(_sliders);
         it.current() != 0;
         ++it) {
        it.current()->setTickInterval( ticks );
    }
}

KdetvSlider *SliderAction::createWidget( QWidget *parent, const char *name )
{
    KdetvSlider *s = new KdetvSlider( min, max, step, val, Horizontal, parent, name );

    _sliders.append(s);
    connect( s, SIGNAL( destroyed(QObject*) ),
             this, SLOT( removeSlider(QObject*) ) );

    connect( s, SIGNAL( valueChanged(int) ),
             this, SLOT( setValueInternal(int) ) );
    connect( s, SIGNAL( orientationChanged(Orientation) ),
             this, SLOT( setOrientation(Orientation) ) );

    if ( tickStep > 0 )
        s->setTickInterval( tickStep );
        
    s->setTickmarks( QSlider::Below );

    if ( !text().isEmpty() )
        QToolTip::add( s, text() );

    return s;
}

void SliderAction::removeSlider( QObject* o )
{
    KdetvSlider* s = static_cast<KdetvSlider*>(o);
    _sliders.remove(s);
}

int SliderAction::value() const
{ 
    return val;
}

//
// Channel import/export action
//

ImpExChannelsAction::ImpExChannelsAction( const QString &text, int accel, const QString& fmt, Kdetv* ktv,
                                          int direction, QObject *parent, const char *name)
    : KAction(text, accel, parent, name),
      _fmt(fmt),
      _ktv(ktv),
      _direction(direction)
{
    connect(this, SIGNAL( activated() ),
            this, SLOT( slotActivated() ));
}

ImpExChannelsAction::~ImpExChannelsAction()
{
}

void ImpExChannelsAction::slotActivated()
{
    if (_direction) {
        _ktv->importChannelFile(_fmt);
    } else {
        _ktv->exportChannelFile(_fmt);
    }
}

//
// Device action
//

DeviceAction::DeviceAction( const QString &text, int accel, const QString& dev, 
                            Kdetv* ktv, QObject *parent, const char *name)
    : KToggleAction(text, accel, parent, name),
      _dev(dev),
      _ktv(ktv)
{
    connect(this, SIGNAL( activated() ),
            this, SLOT( slotActivated() ));
}

DeviceAction::~DeviceAction()
{
}

void DeviceAction::slotActivated()
{
    _ktv->playDevice(_dev);
}

//
// AudioMode action
//

AudioModeAction::AudioModeAction( const QString &text, int accel, const QString& mode, 
                                  Kdetv* ktv, QObject *parent, const char *name)
    : KToggleAction(text, accel, parent, name),
      _mode(mode),
      _ktv(ktv)
{
    connect(this, SIGNAL( activated() ),
            this, SLOT( slotActivated() ));
}

AudioModeAction::~AudioModeAction()
{
}

void AudioModeAction::slotActivated()
{
    _ktv->setAudioMode(_mode);
}
