/*
    This file is part of kenvy24 KDE multimedia utility
    Copyright (c) 2007  Valentin RUSU kenvy24@rusu.info

    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) version 3 or, at the discretion of KDE e.V. (which shall
    act as a proxy as in section 14 of the GPLv3), 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, see <http://www.gnu.org/licenses/>.
*/

#include "mixerpartchannel.h"
#include "mixerpart.h"
#include "mixerpartmonovumeter.h"
#include "envycard.h"

#include <QSlider>
#include <QPushButton>
#include <QToolButton>
#include <QGroupBox>

#include <kconfiggroup.h>

#include <kdebug.h>
#include <assert.h>
#include <algorithm>

// TODO reset peaks when vu are clicked (also define a keyboard shortcut for this)

MixerPartChannel::MixerPartChannel( QGroupBox* group, int index, MixerPart* mixerPart ) :
    QObject( mixerPart ),
    channelIndex( index ),
    leftVu(0), rightVu(0),
    leftVol(0), rightVol(0),
    inSlotFlag(false), inEventFlag(false),
    envyCard(0), volumeMaxValue(0),
    stereoLinkButton(0),
    muteLeftButton(0), muteRightButton(0),
    groupBox(group),
    hideButton(0)
{
}

MixerPartChannel::~MixerPartChannel()
{
    // TODO save controls state into config file
}

void MixerPartChannel::setVuMeters( MixerPartMonoVuMeter* left, MixerPartMonoVuMeter* right )
{
    leftVu = left;
    rightVu = right;
}

void MixerPartChannel::setVolumes( QSlider* left, QSlider* right, int maxValue )
{
    leftVol = left;
    rightVol = right;
    volumeMaxValue = maxValue;

    if ( leftVol )
    {
        connect( leftVol, SIGNAL( valueChanged(int)), SLOT( leftVolumeChange(int)));
        leftVol->setMaximum( volumeMaxValue );
        leftVol->setMinimum( 0 );
        // TODO restore saved value
    }
    if ( rightVol )
    {
        connect( rightVol, SIGNAL( valueChanged(int)), SLOT( rightVolumeChange(int)));
        rightVol->setMaximum( volumeMaxValue );
        rightVol->setMinimum( 0 );
        // TODO restore saved value
    }
}

void MixerPartChannel::setMuteButtons( QToolButton* btnL, QToolButton* btnR )
{
    muteLeftButton = btnL;
    muteRightButton = btnR;
    if ( btnL )
    {
        connect( muteLeftButton, SIGNAL( toggled(bool) ), SLOT( muteLeftButtonToggle( bool ) ) );
        // TODO restore saved state
    }
    if ( btnR )
    {
        connect( muteRightButton, SIGNAL( toggled(bool) ), SLOT( muteRightButtonToggle(bool) ) );
        // TODO restore saved state
    }
}

void MixerPartChannel::leftVolumeChange( int vol )
{
    ExclusiveFlag inEvent( inEventFlag );
    if ( !inSlotFlag )
    {
        emit volumeChange( channelIndex, LEFT, vol, 0 );
        emit volumeChange( LEFT, vol );
        // TODO save value to config file
    }
}

void MixerPartChannel::rightVolumeChange( int vol )
{
    ExclusiveFlag inEvent( inEventFlag );
    if ( !inSlotFlag )
    {
        emit volumeChange( channelIndex, RIGHT, 0, vol );
        emit volumeChange( RIGHT, vol );
        // TODO save value to config file
    }
}

void MixerPartChannel::muteLeftButtonToggle( bool on)
{
#ifdef TRACE_DRIVER_EVENTS
    kDebug();
#endif
    if ( !inSlotFlag )
    {
        ExclusiveFlag inEvent( inEventFlag );
        emit muteChanged( channelIndex, LEFT, on );
        if ( stereoLinkButton->isChecked() )
        {
            muteRightButton->setChecked( on );
        }
        // TODO save value to config file
    }
}

void MixerPartChannel::muteRightButtonToggle( bool on)
{
#ifdef TRACE_DRIVER_EVENTS
    kDebug();
#endif
    if ( !inSlotFlag )
    {
        ExclusiveFlag inEvent( inEventFlag );
        emit muteChanged( channelIndex, RIGHT, on );
        if ( stereoLinkButton->isChecked() )
        {
            muteLeftButton->setChecked( on );
        }
        // TODO save value to config file
    }
}

void MixerPartChannel::parentResizeEvent()
{
}

void MixerPartChannel::levelUpdated( int index, const StereoLevels& levels )
{
    if (channelIndex == index)
        levelUpdated( levels );
}

void MixerPartChannel::levelUpdated( const StereoLevels& levels )
{
    leftVu->levelUpdated( levels.left );
    rightVu->levelUpdated( levels.right );
}

void MixerPartChannel::timerTick()
{
    leftVu->timerTick();
    rightVu->timerTick();
}

void MixerPartChannel::mixerUpdatePlaybackVolume( int ch, LeftRight lr, int volLeft, int volRight)
{
#ifdef TRACE_DRIVER_EVENTS
    kDebug() << ch << " side=" << lr << " volLeft=" << volLeft << " volRigh=" << volRight;
#endif
    if ( ch == channelIndex )
    {
        mixerUpdatePlaybackVolume( ch, lr, lr == RIGHT ? volRight : volLeft );
    }
}

void MixerPartChannel::mixerUpdatePlaybackVolume( int ch, LeftRight lr, int vol)
{
#ifdef TRACE_DRIVER_EVENTS
    kDebug() << ch << " side " << lr << " vol " << vol;
#endif
    if ( ch == channelIndex )
    {
        ExclusiveFlag inSlot( inSlotFlag );
        if ( !inEventFlag ) {
//             // disconnect sliders prior to setting values
//             if (stereoLinkButton)
//                 stereoLinkButton->setChecked(false);

            if (lr == LEFT)
            {
                setLeftVolume( vol );
            }
            else
            {
                setRightVolume( vol );
            }
        }
    }
}

void MixerPartChannel::mixerUpdateMuteSwitch( int ch, LeftRight lr, bool on )
{
#ifdef TRACE_DRIVER_EVENTS
    kDebug() << ch << " side " << lr << " on " << on;
#endif
    if ( ch == channelIndex )
    {
        ExclusiveFlag inSlot( inSlotFlag );
        if (!inEventFlag)
        {
            if ( lr == LEFT )
            {
                muteLeftButton->setChecked( on );
            }
            else
            {
                muteRightButton->setChecked( on );
            }
        }
    }
}

void MixerPartChannel::setStereoLinkButton( QPushButton* btn )
{
    assert(btn != 0);
    stereoLinkButton = btn;
    connect( btn, SIGNAL( toggled(bool) ), SLOT( stereoLinkButtonToggle( bool ) ) );
    stereoLinkButtonToggle( btn->isChecked() );
    // TODO restore button state from config file
}

void MixerPartChannel::stereoLinkButtonToggle( bool linkOn )
{
#ifdef TRACE_DRIVER_EVENTS
    kDebug() << linkOn;
#endif
    if ( leftVol != 0 && rightVol != 0 )
    {
        if ( linkOn )
        {
            connect( leftVol, SIGNAL( valueChanged(int) ), rightVol, SLOT( setValue( int ) ) );
            connect( rightVol, SIGNAL( valueChanged(int) ), leftVol, SLOT( setValue( int ) ) );

            int vol = std::min( leftVol->value(), rightVol->value() );
            setLeftVolume( vol );
            setRightVolume( vol );
        }
        else
        {
            leftVol->disconnect( rightVol );
            rightVol->disconnect( leftVol );
        }
        // TODO save value to config file
    }
}

void MixerPartChannel::setLeftVolume( int vol )
{
    leftVol->setValue( vol );
}

void MixerPartChannel::setRightVolume( int vol )
{
    rightVol->setValue( vol );
}

void MixerPartChannel::setEnvyCard( EnvyCard* card)
{
    kDebug();
    envyCard = card;
    // TODO enable/disable UI elements following card != 0
}

void MixerPartChannel::setVisible( bool visible )
{
    assert( groupBox != 0 );
    // TODO restore visibility state from display options dialog and combine with visible parameter
    groupBox->setVisible( visible );
}

void MixerPartChannel::setTitle( const QString& title )
{
    assert( groupBox != 0 );
    groupBox->setTitle( title );
}

void MixerPartChannel::setHideButton( QToolButton* btnHide )
{
    hideButton = btnHide;
    if ( hideButton != 0 )
    {
        connect( hideButton, SIGNAL( toggled(bool) ), SLOT( hideButtonToggle(bool) ) );
    }
}

void MixerPartChannel::hideButtonToggle( bool on )
{
    assert( groupBox != 0 );
    groupBox->setVisible(on);
}

void MixerPartChannel::saveConfig( KConfigGroup* config )
{
    config->writeEntry( QString("%1_leftVol").arg( configPrefix() ), leftVol->value() );
    config->writeEntry( QString("%1_rightVol").arg( configPrefix() ), leftVol->value() );
    config->writeEntry( QString("%1_stereoLink").arg( configPrefix() ), stereoLinkButton->isChecked() );
    if ( muteLeftButton )
        config->writeEntry( QString("%1_muteLeft").arg( configPrefix() ), muteLeftButton->isChecked() );
    if ( muteRightButton )
        config->writeEntry( QString("%1_muteRight").arg( configPrefix() ), muteRightButton->isChecked() );
    if ( hideButton )
        config->writeEntry( QString("%1_visible").arg( configPrefix() ), hideButton->isChecked() );
}

void MixerPartChannel::loadConfig( KConfigGroup*  config )
{
    leftVol->setValue( config->readEntry( QString("%1_leftVol").arg( configPrefix() ) ).toInt() );
    rightVol->setValue( config->readEntry( QString("%1_rightVol").arg( configPrefix() ) ).toInt() );
    stereoLinkButton->setChecked( readBoolConfigValue( config, "stereoLink") );
    if ( muteLeftButton )
        muteLeftButton->setChecked( readBoolConfigValue( config, "muteLeft") );
    if ( muteRightButton )
        muteRightButton->setChecked( readBoolConfigValue( config, "muteRight" ) );
    if ( hideButton )
        hideButton->setChecked( readBoolConfigValue( config, "visible") );
}

bool MixerPartChannel::readBoolConfigValue( KConfigGroup* config, const char* valName, bool defVal ) const
{
    bool result = defVal;
    QString value = config->readEntry( QString("%1_%2").arg( configPrefix() ).arg( valName ) );
    if ( !value.isEmpty() )
        result = value.compare( "true" ) == 0;
    return result;
}

QString MixerPartChannel::configPrefix() const
{
    return QString("channel%1%2").arg( groupBox->title() ).arg( channelIndex );
}

#include "mixerpartchannel.moc"
// kate: space-indent on; indent-width 4; replace-tabs on;
