#include "backendcontroller.h"
#include "tmixapp.h"

#include <tdeconfig.h>
#include <tdeglobal.h>
#include <tdeapplication.h>
#include <tqtimer.h>

#ifdef WITH_PULSE
#include "../model/pulsemodel.h"
#include "mixerwindow.h"
#endif

#ifdef WITH_ALSA
#include "../model/alsamodel.h"
#include "alsa/alsamixerwindow.h"
#include "alsa/alsatray.h"
#endif

#ifdef WITH_OSS
#include "../model/ossmodel.h"
#include "oss/ossmixerwindow.h"
#include "oss/osstray.h"
#endif

BackendController::BackendController( TQObject *parent )
    : TQObject(parent)
#ifdef WITH_PULSE
    , m_pulseModel(0), m_pulseWin(0)
#endif
#ifdef WITH_ALSA
    , m_alsaModel(0), m_alsaWin(0), m_alsaTray(0)
#endif
#ifdef WITH_OSS
    , m_ossModel(0), m_ossWin(0), m_ossTray(0)
#endif
{}

BackendController::~BackendController()
{
    stop();
}

void BackendController::start()
{
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("General");
    m_currentBackend = cfg->readEntry("Backend", "pulse");

#ifdef WITH_ALSA
    if ( m_currentBackend == "alsa" ) { startAlsa(); return; }
#endif
#ifdef WITH_OSS
    if ( m_currentBackend == "oss" )  { startOss();  return; }
#endif
#ifdef WITH_PULSE
    startPulse();
#endif
}

void BackendController::stop()
{
#ifdef WITH_ALSA
    if ( m_alsaTray )  { delete m_alsaTray;  m_alsaTray  = 0; }
    if ( m_alsaWin )   { delete m_alsaWin;   m_alsaWin   = 0; }
    if ( m_alsaModel ) { delete m_alsaModel; m_alsaModel = 0; }
#endif
#ifdef WITH_OSS
    if ( m_ossTray )  { delete m_ossTray;  m_ossTray  = 0; }
    if ( m_ossWin )   { delete m_ossWin;   m_ossWin   = 0; }
    if ( m_ossModel ) { delete m_ossModel; m_ossModel = 0; }
#endif
#ifdef WITH_PULSE
    // Model first: stops the PA mainloop thread before any widget is destroyed.
    if ( m_pulseModel ) { delete m_pulseModel; m_pulseModel = 0; }
    if ( m_pulseWin )   { delete m_pulseWin;   m_pulseWin   = 0; }
#endif
}

#ifdef WITH_PULSE
void BackendController::startPulse( bool showWindow )
{
    m_pulseModel = new PulseModel( this );
    if ( !m_pulseModel->open() ) {
        delete m_pulseModel;
        m_pulseModel = 0;
        return;
    }
    m_pulseWin = new MixerWindow( m_pulseModel );
    connect( m_pulseWin, TQ_SIGNAL(settingsChanged()),
             this,        TQ_SLOT(onSettingsChanged()) );
    static_cast<TmixApp*>(tdeApp)->setMainWindow( m_pulseWin );

    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("Tray");
    bool dockInTray = cfg->readBoolEntry("DockInTray", true);
    if ( !dockInTray || showWindow )
        m_pulseWin->show();
}
#endif

#ifdef WITH_ALSA
void BackendController::startAlsa( bool showWindow )
{
    m_alsaModel = new AlsaModel( this );
    if ( !m_alsaModel->open() ) {
        delete m_alsaModel;
        m_alsaModel = 0;
        return;
    }
    m_alsaWin = new AlsaMixerWindow( m_alsaModel );
    connect( m_alsaWin, TQ_SIGNAL(settingsChanged()),
             this,       TQ_SLOT(onSettingsChanged()) );
    static_cast<TmixApp*>(tdeApp)->setMainWindow( m_alsaWin );

    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("Tray");
    bool dockInTray = cfg->readBoolEntry("DockInTray", true);
    if ( dockInTray ) {
        m_alsaTray = new AlsaTray( m_alsaModel, m_alsaWin, m_alsaWin );
        m_alsaWin->setTray( m_alsaTray );
        m_alsaTray->show();
    }
    if ( !dockInTray || showWindow )
        m_alsaWin->show();
}
#endif

#ifdef WITH_OSS
void BackendController::startOss( bool showWindow )
{
    m_ossModel = new OssModel( this );
    m_ossModel->open(); // window shows an error page if this fails

    m_ossWin = new OssMixerWindow( m_ossModel );
    connect( m_ossWin, TQ_SIGNAL(settingsChanged()),
             this,      TQ_SLOT(onSettingsChanged()) );
    static_cast<TmixApp*>(tdeApp)->setMainWindow( m_ossWin );

    bool hasError = !m_ossModel->lastError().isEmpty();
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("Tray");
    bool dockInTray = cfg->readBoolEntry("DockInTray", true);
    if ( dockInTray && !hasError ) {
        m_ossTray = new OssTray( m_ossModel, m_ossWin, m_ossWin );
        m_ossWin->setTray( m_ossTray );
        m_ossTray->show();
    }
    if ( !dockInTray || showWindow || hasError )
        m_ossWin->show();
}
#endif

void BackendController::onSettingsChanged()
{
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("General");
    TQString newBackend = cfg->readEntry("Backend", "pulse");
    if ( newBackend != m_currentBackend )
        TQTimer::singleShot( 0, this, TQ_SLOT(doSwitch()) );
}

void BackendController::doSwitch()
{
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("General");
    m_currentBackend = cfg->readEntry("Backend", "pulse");

    // Remember whether the mixer window was open so we can reopen it after the switch.
    bool wasVisible = false;
#ifdef WITH_PULSE
    if ( m_pulseWin ) {
        wasVisible = m_pulseWin->isVisible();
        if ( wasVisible ) {
            cfg->setGroup("MainWindow");
            cfg->writeEntry("XPos", m_pulseWin->x());
            cfg->writeEntry("YPos", m_pulseWin->y());
            cfg->sync();
        }
    }
#endif
#ifdef WITH_ALSA
    if ( m_alsaWin ) {
        wasVisible = wasVisible || m_alsaWin->isVisible();
        if ( m_alsaWin->isVisible() ) {
            cfg->setGroup("MainWindow");
            cfg->writeEntry("XPos", m_alsaWin->x());
            cfg->writeEntry("YPos", m_alsaWin->y());
            cfg->sync();
        }
    }
#endif
#ifdef WITH_OSS
    if ( m_ossWin ) {
        wasVisible = wasVisible || m_ossWin->isVisible();
        if ( m_ossWin->isVisible() ) {
            cfg->setGroup("MainWindow");
            cfg->writeEntry("XPos", m_ossWin->x());
            cfg->writeEntry("YPos", m_ossWin->y());
            cfg->sync();
        }
    }
#endif

    stop();

#ifdef WITH_ALSA
    if ( m_currentBackend == "alsa" ) { startAlsa( wasVisible ); return; }
#endif
#ifdef WITH_OSS
    if ( m_currentBackend == "oss" )  { startOss( wasVisible );  return; }
#endif
#ifdef WITH_PULSE
    startPulse( wasVisible );
#endif
}

#include "backendcontroller.moc"
