/*
 *  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.
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

// This file is a mess. Instead of normal Qt toggle-buttons more flexible
// ones should have been used. 
// The mixer depends on emuConfig-like info to allow correct setting of
// mixing mode and stereo effects. It sends its mixer config with a Qt signal.
//
// Notes: Have to set LEDs manually (toggle/setChecked).

#include <qbuttongroup.h>
#include <qpushbutton.h>
#include <qslider.h>

#include "MixerDialog.h"

// --------------------------------------------------------------------------

const int MixerDialog::voices = _voices;
const int MixerDialog::effects = _effects;

MixerDialog::MixerDialog(QWidget* parent, const char* name)
: MixerDialogData(parent,name)
{
    setFixedSize(width(),height());
    setIcon(*mainIcon);

    mixerOffBtn->setColour(LEDButton::red);
    mixerOffBtn->setText( "Off" );
    mixerOffBtn->setAutoRepeat( FALSE );
    connect( mixerOffBtn, SIGNAL(clicked()), SLOT(setMixerOff()) );
    mixerGrp->insert(mixerOffBtn);

    highQualityBtn->setColour(LEDButton::green);
    highQualityBtn->setText( "High quality" );
    highQualityBtn->setAutoRepeat( FALSE );
    connect( highQualityBtn, SIGNAL(clicked()), SLOT(setHighQuality()) );
    mixerGrp->insert(highQualityBtn);
    
    fullPanningBtn->setColour(LEDButton::green);
    fullPanningBtn->setText( "Full panning" );
    fullPanningBtn->setAutoRepeat( FALSE );
    connect( fullPanningBtn, SIGNAL(clicked()), SLOT(setFullPanning()) );
    mixerGrp->insert(fullPanningBtn);
    
    effectsOffBtn->setColour(LEDButton::red);
    effectsOffBtn->setText( "None" );
    effectsOffBtn->setAutoRepeat( FALSE );
    connect( effectsOffBtn, SIGNAL(clicked()), SLOT(setEffectsOff()) );
    effectsGrp->insert(effectsOffBtn);
    
    surroundBtn->setColour(LEDButton::green);
    surroundBtn->setText( "Surround" );
    surroundBtn->setAutoRepeat( FALSE );
    connect( surroundBtn, SIGNAL(clicked()), SLOT(setStereoSurround()) );
    effectsGrp->insert(surroundBtn);
    
    centeredPanningBtn->setColour(LEDButton::green);
    centeredPanningBtn->setText( "Centered AP" );
    centeredPanningBtn->setAutoRepeat( FALSE );
    connect( centeredPanningBtn, SIGNAL(clicked()), SLOT(setCenteredPanning()) );
    effectsGrp->insert(centeredPanningBtn);

    // Default volume levels.
    config.volHQ[0].l = config.volHQ[1].r = config.volHQ[2].l = config.volHQ[3].r = 255;
    config.volHQ[0].r = config.volHQ[1].l = config.volHQ[2].r = config.volHQ[3].l = 0;
    config.volFP[0].l = config.volFP[1].r = config.volFP[2].l = config.volFP[3].r = 255;
    config.volFP[0].r = config.volFP[1].l = config.volFP[2].r = config.volFP[3].l = 0;
    config.volTotal[0] = config.volTotal[1] = config.volTotal[2] = config.volTotal[3] = 256;  // max
    config.muteMask[0] = config.muteMask[1] = config.muteMask[2] = config.muteMask[3] = 65535; // on

    volSliders[0] = voice1volSld;
    volSliders[1] = voice2volSld;
    volSliders[2] = voice3volSld;
    volSliders[3] = voice4volSld;

    panSliders[0] = voice1panSld;
    panSliders[1] = voice2panSld;
    panSliders[2] = voice3panSld;
    panSliders[3] = voice4panSld;

    muteButtons[0] = voice1muteBtn;
    muteButtons[1] = voice2muteBtn;
    muteButtons[2] = voice3muteBtn;
    muteButtons[3] = voice4muteBtn;

    soloButtons[0] = voice1soloBtn;
    soloButtons[1] = voice2soloBtn;
    soloButtons[2] = voice3soloBtn;
    soloButtons[3] = voice4soloBtn;

    effectWidgets[0] = effectsOffBtn;
    effectWidgets[1] = surroundBtn;
    effectWidgets[2] = centeredPanningBtn;

    dontTouchMuteButtons = false;
    soloIsVoice = (-1);

    changedSignalEnabled = true;

    setButtons();
}

MixerDialog::~MixerDialog()
{
}

// --------------------------------------------------------------------------

void MixerDialog::enableChangedSignal(bool val)
{
    changedSignalEnabled = val;
}

void MixerDialog::emitChangedIfEnabled()
{
    if (changedSignalEnabled)
    {
        emit changed(config);
    }
}

void MixerDialog::setConfig(const MixerConfig& inConfig)
{
    setUpdatesEnabled(false);
    enableChangedSignal(false);
    config = inConfig;
    setButtons();
    enableChangedSignal(true);
    setUpdatesEnabled(true);
    repaint();
}

const MixerConfig& MixerDialog::getConfig() const
{
    return config;
}

void MixerDialog::setButtons()
{
    for (int v=0; v<voices; v++)
    {
        // Voice volume slider: 0=top=max, 256=bottom=min
        int val = volSliders[v]->maxValue()-config.volTotal[v];
        volSliders[v]->setValue(val);
        volSliders[v]->repaint(false);
    }
    adjustPanningSliders();
    
    // Preset LEDs, sliders, buttons.
    
    if (config.channels == SIDEMU_MONO)
    {
        if (config.mixingMode == SIDEMU_NONE)
        {
            setMixerButtons(true,false,false);
            enableVolumeControl(false);
        }
        else if (config.mixingMode == SIDEMU_VOLCONTROL)
        {
            setMixerButtons(false,true,false);
            enableVolumeControl(true);
        }
        setEffectButtons(false,false,false);
        enableEffects(false);
        fullPanningBtn->setEnabled(false);
        enablePanning(false);
    }
    else if (config.channels == SIDEMU_STEREO)
    {
        if (config.mixingMode == SIDEMU_NONE)
        {
            setMixerButtons(true,false,false);
            fullPanningBtn->setEnabled(true);
            enableEffects(false);
            setEffectButtons(false,false,false);
            enableVolumeControl(false);
            enablePanning(false);
        }
        else if (config.mixingMode == SIDEMU_VOLCONTROL)
        {
            setMixerButtons(false,true,false);
            fullPanningBtn->setEnabled(true);
            enableEffects(false);
            setEffectButtons(false,false,false);
            enableVolumeControl(true);
            enablePanning(true);
        }
        else if (config.mixingMode == SIDEMU_FULLPANNING)
        {
            fullPanningBtn->setEnabled(true);
            enableEffects(true);
            enableVolumeControl(true);
            setMixerButtons(false,false,true);
            if (config.panningMode == SIDEMU_NONE)
            {
                setEffectButtons(true,false,false);
                enablePanning(true);
            }
            else if (config.panningMode == SIDEMU_CENTEREDAUTOPANNING)
            {
                setEffectButtons(false,false,true);
                enablePanning(false);
            }
        }
        else if (config.mixingMode == SIDEMU_STEREOSURROUND)
        {
            fullPanningBtn->setEnabled(true);
            enableEffects(true);
            enableVolumeControl(true);
            setMixerButtons(false,false,true);
            setEffectButtons(false,true,false);
            enablePanning(false);
        }
    }
}

void MixerDialog::setMixerButtons(bool off, bool hq, bool fp)
{
    mixerOffBtn->setChecked(off);
    highQualityBtn->setChecked(hq);
    fullPanningBtn->setChecked(fp);
}

void MixerDialog::setEffectButtons(bool off, bool ss, bool cap)
{
    centeredPanningBtn->setChecked(cap);
    surroundBtn->setChecked(ss);
    effectsOffBtn->setChecked(off);
}

void MixerDialog::enableVolumeControl(bool val)
{
    for (int i = 0; i < voices; i++)
    {
        volSliders[i]->setEnabled(val);
        volSliders[i]->repaint(false);
    }
    for (int i = 0; i < voices; i++)
    {
        muteButtons[i]->setEnabled(val);
        muteButtons[i]->repaint(false);
    }
    for (int i = 0; i < voices; i++)
    {
        soloButtons[i]->setEnabled(val);
        soloButtons[i]->repaint(false);
    }
}

void MixerDialog::enableEffects(bool val)
{
    for (int i=0; i < effects; i++)
    {
        effectWidgets[i]->setEnabled(val);
        effectWidgets[i]->repaint(false);
    }
}

void MixerDialog::enablePanning(bool val)
{
    for (int i=0; i < voices; i++)
    {
        panSliders[i]->setEnabled(val);
        panSliders[i]->repaint(false);
    }
}

void MixerDialog::adjustMuteButtons()
{
    for (int v=0; v < voices; v++)
    {
        if ( !dontTouchMuteButtons )
        {
            if (config.muteMask[v]==0)
                muteButtons[v]->setOn(true);
            else
                muteButtons[v]->setOn(false);
        }
    }
}

void MixerDialog::adjustPanningSliders()
{
    // Choose pan-position dependent on left volume level.
    // Panning slider: 0=left, 255=right 
    for (int v=0; v<voices; v++)
    {
        int val = panSliders[v]->maxValue();
        if (config.mixingMode == SIDEMU_VOLCONTROL)
            val -= config.volHQ[v].l;
        else if (config.panningMode != SIDEMU_NONE)
            val >>= 1;  // middle: irrelevant, but looks better
        else if (config.mixingMode == SIDEMU_FULLPANNING)
            val -= config.volFP[v].l;
        else
            val >>= 1;  // middle: same as above
        panSliders[v]->setValue(val);
        panSliders[v]->repaint(false);
    }
}

// ------------------------------------------------------------------- Slots.

void MixerDialog::setMixerOff()
{
    if ( !mixerOffBtn->isChecked() )
    {
        enableChangedSignal(false);
        
        config.mixingMode = SIDEMU_NONE;
        config.panningMode = SIDEMU_NONE;
        // Here we could set all buttons to defaults. However, as they
        // get disabled anyway, it was just for the look.
        setButtons();

        enableChangedSignal(true);
        emitChangedIfEnabled();
    }
}

void MixerDialog::setHighQuality()
{
    if ( !highQualityBtn->isChecked() )
    {
        enableChangedSignal(false);
        
        config.mixingMode = SIDEMU_VOLCONTROL;
        config.panningMode = SIDEMU_NONE;
        unMuteAllVoices();
        allMuteSoloButtonsOff();
        setButtons();
        
        enableChangedSignal(true);
        emitChangedIfEnabled();
    }
}

void MixerDialog::setFullPanning()
{
    if ( !fullPanningBtn->isChecked() )
    {
        enableChangedSignal(false);
        
        config.mixingMode = SIDEMU_FULLPANNING;
        config.panningMode = SIDEMU_NONE;
        unMuteAllVoices();
        allMuteSoloButtonsOff();
        setButtons();
        
        enableChangedSignal(true);
        emitChangedIfEnabled();
    }
}

void MixerDialog::setEffectsOff()
{
    if ( !effectsOffBtn->isChecked() )
    {
        enableChangedSignal(false);
        
        config.mixingMode = SIDEMU_FULLPANNING;
        config.panningMode = SIDEMU_NONE;
        unMuteAllVoices();
        setButtons();
        
        enableChangedSignal(true);
        emitChangedIfEnabled();
    }
}

void MixerDialog::setStereoSurround()
{
    if ( !surroundBtn->isChecked() )
    {
        enableChangedSignal(false);
        
        config.mixingMode = SIDEMU_STEREOSURROUND;
        config.panningMode = SIDEMU_NONE;
        unMuteAllVoices();
        setButtons();
        
        enableChangedSignal(true);
        emitChangedIfEnabled();
    }
}

void MixerDialog::setCenteredPanning()
{
    if ( !centeredPanningBtn->isChecked() )
    {
        enableChangedSignal(false);
        
        config.mixingMode = SIDEMU_FULLPANNING;
        config.panningMode = SIDEMU_CENTEREDAUTOPANNING;
        unMuteAllVoices();
        setButtons();
        
        enableChangedSignal(true);
        emitChangedIfEnabled();
    }
}

// -------------------------------------------------------------------- Slots

void MixerDialog::setVoice1Volume(int val)
{
    newVoiceGain(1,val);
    emitChangedIfEnabled();
}

void MixerDialog::setVoice2Volume(int val)
{
    newVoiceGain(2,val);
    emitChangedIfEnabled();
}

void MixerDialog::setVoice3Volume(int val)
{
    newVoiceGain(3,val);
    emitChangedIfEnabled();
}

void MixerDialog::setVoice4Volume(int val)
{
    newVoiceGain(4,val);
    emitChangedIfEnabled();
}

void MixerDialog::setVoice1Pan(int val)
{
    newVoicePanPos(1,val);
    if ((config.channels==SIDEMU_STEREO)
        &&(config.mixingMode==SIDEMU_VOLCONTROL))
    {
        voice2panSld->setValue(255-val);
        newVoicePanPos(2,val);
    }
    emitChangedIfEnabled();
}

void MixerDialog::setVoice2Pan(int val)
{
    newVoicePanPos(2,val);
    if ((config.channels==SIDEMU_STEREO)
        &&(config.mixingMode==SIDEMU_VOLCONTROL))
    {
        voice1panSld->setValue(255-val);
        newVoicePanPos(1,val);
    }
    emitChangedIfEnabled();
}

void MixerDialog::setVoice3Pan(int val)
{
    newVoicePanPos(3,val);
    if ((config.channels==SIDEMU_STEREO)
        &&(config.mixingMode==SIDEMU_VOLCONTROL))
    {
        voice4panSld->setValue(255-val);
        newVoicePanPos(4,val);
    }
    emitChangedIfEnabled();
}

void MixerDialog::setVoice4Pan(int val)
{
    newVoicePanPos(4,val);
    if ((config.channels==SIDEMU_STEREO)
        &&(config.mixingMode==SIDEMU_VOLCONTROL))
    {
        voice3panSld->setValue(255-val);
        newVoicePanPos(3,val);
    }
    emitChangedIfEnabled();
}

void MixerDialog::soloVoice1(bool val)
{
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(1,false);
        muteVoice(2,true);
        muteVoice(3,true);
        muteVoice(4,true);
        adjustMuteButtons();
        soloIsVoice = 1;
    }
    else
    {
        soloIsVoice = (-1);
        if (!dontTouchMuteButtons)
        {
            unMuteAllVoices();
            muteVoice(2,false);
            muteVoice(3,false);
            muteVoice(4,false);
            adjustMuteButtons();
        }
    }
    emitChangedIfEnabled();
}

void MixerDialog::soloVoice2(bool val)
{
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(2,false);
        muteVoice(1,true);
        muteVoice(3,true);
        muteVoice(4,true);
        adjustMuteButtons();
        soloIsVoice = 2;
    }
    else
    {
        soloIsVoice = (-1);
        if (!dontTouchMuteButtons)
        {
            unMuteAllVoices();
            muteVoice(1,false);
            muteVoice(3,false);
            muteVoice(4,false);
            adjustMuteButtons();
        }
    }
    emitChangedIfEnabled();
}

void MixerDialog::soloVoice3(bool val)
{
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(3,false);
        muteVoice(1,true);
        muteVoice(2,true);
        muteVoice(4,true);
        adjustMuteButtons();
        soloIsVoice = 3;
    }
    else
    {
        soloIsVoice = (-1);
        if (!dontTouchMuteButtons)
        {
            unMuteAllVoices();
            muteVoice(1,false);
            muteVoice(2,false);
            muteVoice(4,false);
            adjustMuteButtons();
        }
    }
    emitChangedIfEnabled();
}

void MixerDialog::soloVoice4(bool val)
{
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(4,false);
        muteVoice(1,true);
        muteVoice(2,true);
        muteVoice(3,true);
        adjustMuteButtons();
        soloIsVoice = 4;
    }
    else
    {
        soloIsVoice = (-1);
        if (!dontTouchMuteButtons)
        {
            unMuteAllVoices();
            muteVoice(1,false);
            muteVoice(2,false);
            muteVoice(3,false);
            adjustMuteButtons();
        }
    }
    emitChangedIfEnabled();
}

void MixerDialog::muteVoice1(bool val)
{
    dontTouchMuteButtons = true;
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(1,true);
        adjustMuteButtons();
    }
    else
    {
        currentSoloButtonOff();
        muteVoice(1,false);
        adjustMuteButtons();
    }
    dontTouchMuteButtons = false;
    emitChangedIfEnabled();
}

void MixerDialog::muteVoice2(bool val)
{
    dontTouchMuteButtons = true;
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(2,true);
        adjustMuteButtons();
    }
    else
    {
        currentSoloButtonOff();
        muteVoice(2,false);
        adjustMuteButtons();
    }
    dontTouchMuteButtons = false;
    emitChangedIfEnabled();
}

void MixerDialog::muteVoice3(bool val)
{
    dontTouchMuteButtons = true;
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(3,true);
        adjustMuteButtons();
    }
    else
    {
        currentSoloButtonOff();
        muteVoice(3,false);
        adjustMuteButtons();
    }
    dontTouchMuteButtons = false;
    emitChangedIfEnabled();
}

void MixerDialog::muteVoice4(bool val)
{
    dontTouchMuteButtons = true;
    if (val)
    {
        currentSoloButtonOff();
        muteVoice(4,true);
        adjustMuteButtons();
    }
    else
    {
        currentSoloButtonOff();
        muteVoice(4,false);
        adjustMuteButtons();
    }
    dontTouchMuteButtons = false;
    emitChangedIfEnabled();
}

// --------------------------------------------------------------------------

void MixerDialog::currentSoloButtonOff()
{
    if (soloIsVoice > 0)  // none is solo = (-1)
    {
        soloButtons[soloIsVoice-1]->setOn(false);
        soloIsVoice = (-1);
    }
}

void MixerDialog::allMuteSoloButtonsOff()
{
    for (int v=0; v < voices; v++)
    {
        if ( !dontTouchMuteButtons )
            muteButtons[v]->setOn(false);
    }
    currentSoloButtonOff();
}

void MixerDialog::newVoiceGain(int voice, int val)
{
    if ((voice>=1)&&(voice<=voices))
    {
        config.volTotal[voice-1] = 256-val;  // slider value -> volume
    }
}

void MixerDialog::newVoicePanPos(int voice, int val)
{
    if ((voice>=1)&&(voice<=voices))
    {
        int vi = voice-1;
        int left = 255-val;
        int right = val;
        if (config.channels == SIDEMU_STEREO)
        {
            if (config.mixingMode == SIDEMU_VOLCONTROL)
            {
                config.volHQ[vi].l = left;
                config.volHQ[vi].r = right;
            }
            else
            {
                config.volFP[vi].l = left;
                config.volFP[vi].r = right;
            }
            emitChangedIfEnabled();
        }
    }
}

void MixerDialog::muteVoice(int voice, bool val)
{
    if ((voice>=1)&&(voice<=voices))
    {
        if (val)
            config.muteMask[voice-1] = 0;  // mask, mute
        else
            config.muteMask[voice-1] = 65535;  // unmask, no mute
    }
}

void MixerDialog::unMuteAllVoices()
{
    for (int v=1; v <= voices; v++)
        muteVoice(v,false);
}
