#include "preferencesdlg.h"

#include <tqlayout.h>
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqspinbox.h>
#include <tqlabel.h>
#include <tqframe.h>
#include <tqgroupbox.h>
#include <tqwidgetstack.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqdir.h>
#include <cstdlib>
#include <tdeglobal.h>
#include <tdeconfig.h>
#include <tdelocale.h>

static TQString autostartPath()
{
    TQString tdehome = TQString::fromLocal8Bit( ::getenv("TDEHOME") );
    if ( tdehome.isEmpty() )
        tdehome = TQDir::homeDirPath() + "/.trinity";
    return tdehome + "/Autostart/tmix.desktop";
}

#ifdef WITH_ALSA
#include "../model/alsamodel.h"
#include "../model/alsadevice.h"
#endif

#ifdef WITH_OSS
#include "../model/ossmodel.h"
#include "../model/ossdevice.h"
#endif

#define PREFS_INIT_LIST \
    m_backend(0), m_dockInTray(0), m_popupMode(0), \
    m_scrollStep(0), m_confirmQuit(0), m_middleClickMute(0), \
    m_startOnLogin(0), m_backendStack(0), \
    m_popupShowOutput(0), m_popupShowMic(0), m_popupShowApps(0), \
    m_showRecTray(0), \
    m_noTabs(0), m_showTabsLabel(0), m_showOutput(0), m_showInput(0), \
    m_showPlayback(0), m_showRecording(0)

// ── Pulse constructor ─────────────────────────────────────────────────────────

PreferencesDlg::PreferencesDlg( TQWidget *parent )
    : KDialogBase( Tabbed, i18n("Configure TMix"),
                   Ok | Apply | Cancel, Ok, parent, 0, false ),
      PREFS_INIT_LIST
#ifdef WITH_ALSA
      , m_alsaModel(0), m_trayDevice(0)
#endif
#ifdef WITH_OSS
      , m_ossModel(0), m_ossTrayDevice(0)
#endif
{
    buildGeneralPage();
    buildBackendPage();
    load();
}

#ifdef WITH_ALSA

// ── ALSA constructor ──────────────────────────────────────────────────────────

PreferencesDlg::PreferencesDlg( AlsaModel *model, TQWidget *parent )
    : KDialogBase( Tabbed, i18n("Configure TMix"),
                   Ok | Apply | Cancel, Ok, parent, 0, false ),
      PREFS_INIT_LIST,
      m_alsaModel(model), m_trayDevice(0)
#ifdef WITH_OSS
      , m_ossModel(0), m_ossTrayDevice(0)
#endif
{
    buildGeneralPage();
    buildBackendPage();
    load();
}

#endif

#ifdef WITH_OSS

// ── OSS constructor ───────────────────────────────────────────────────────────

PreferencesDlg::PreferencesDlg( OssModel *model, TQWidget *parent )
    : KDialogBase( Tabbed, i18n("Configure TMix"),
                   Ok | Apply | Cancel, Ok, parent, 0, false ),
      PREFS_INIT_LIST
#ifdef WITH_ALSA
      , m_alsaModel(0), m_trayDevice(0)
#endif
      , m_ossModel(model), m_ossTrayDevice(0)
{
    buildGeneralPage();
    buildBackendPage();
    load();
}

#endif

// ── General page ──────────────────────────────────────────────────────────────

void PreferencesDlg::buildGeneralPage()
{
    TQFrame *gen = addPage( i18n("General") );
    TQVBoxLayout *gl = new TQVBoxLayout( gen, marginHint(), spacingHint() );

    TQHBoxLayout *backendRow = new TQHBoxLayout( 0, 0, spacingHint() );
    backendRow->addWidget( new TQLabel( i18n("Audio backend:"), gen ) );
    m_backend = new TQComboBox( false, gen );
#ifdef WITH_PULSE
    m_backend->insertItem( i18n("PulseAudio") );
    m_backendIds << "pulse";
#endif
#ifdef WITH_ALSA
    m_backend->insertItem( i18n("ALSA") );
    m_backendIds << "alsa";
#endif
#ifdef WITH_OSS
    m_backend->insertItem( i18n("OSS") );
    m_backendIds << "oss";
#endif
    backendRow->addWidget( m_backend );
    backendRow->addStretch();
    gl->addLayout( backendRow );

    gl->addSpacing( 8 );

    TQGroupBox *trayCard = new TQGroupBox( i18n("System Tray"), gen );
    trayCard->setColumnLayout( 0, TQt::Vertical );
    trayCard->layout()->setSpacing( spacingHint() );
    trayCard->layout()->setMargin( marginHint() );
    TQVBoxLayout *tl = new TQVBoxLayout( trayCard->layout() );

    m_dockInTray = new TQCheckBox( i18n("Dock in system tray"), trayCard );
    tl->addWidget( m_dockInTray );

    TQHBoxLayout *popupRow = new TQHBoxLayout( 0, 0, spacingHint() );
    popupRow->addWidget( new TQLabel( i18n("Left-click:"), trayCard ) );
    m_popupMode = new TQComboBox( false, trayCard );
    m_popupMode->insertItem( i18n("Show mixer window") );
    m_popupMode->insertItem( i18n("Show mini popup") );
    popupRow->addWidget( m_popupMode );
    popupRow->addStretch();
    tl->addLayout( popupRow );

    connect( m_popupMode, TQ_SIGNAL(activated(int)), this, TQ_SLOT(onPopupModeChanged(int)) );

    m_middleClickMute = new TQCheckBox( i18n("Middle-click mutes/unmutes"), trayCard );
    tl->addWidget( m_middleClickMute );

    TQHBoxLayout *stepRow = new TQHBoxLayout( 0, 0, spacingHint() );
    stepRow->addWidget( new TQLabel( i18n("Scroll wheel step:"), trayCard ) );
    m_scrollStep = new TQSpinBox( 1, 20, 1, trayCard );
    m_scrollStep->setSuffix( i18n(" %") );
    stepRow->addWidget( m_scrollStep );
    stepRow->addStretch();
    tl->addLayout( stepRow );

    gl->addWidget( trayCard );

    gl->addSpacing( 4 );

    TQGroupBox *startupCard = new TQGroupBox( i18n("Startup / Exit"), gen );
    startupCard->setColumnLayout( 0, TQt::Vertical );
    startupCard->layout()->setSpacing( spacingHint() );
    startupCard->layout()->setMargin( marginHint() );
    TQVBoxLayout *sl = new TQVBoxLayout( startupCard->layout() );
    m_startOnLogin = new TQCheckBox( i18n("Start TMix when Trinity starts"), startupCard );
    sl->addWidget( m_startOnLogin );
    m_confirmQuit = new TQCheckBox( i18n("Ask for confirmation before quitting"), startupCard );
    sl->addWidget( m_confirmQuit );
    gl->addWidget( startupCard );

    gl->addStretch();
}

// ── Backend settings page (stacked Pulse / ALSA) ──────────────────────────────

void PreferencesDlg::buildBackendPage()
{
    TQFrame *page = addPage( i18n("Audio Settings") );
    TQVBoxLayout *vl = new TQVBoxLayout( page, marginHint(), spacingHint() );

    m_backendStack = new TQWidgetStack( page );
    vl->addWidget( m_backendStack );

    // ── Pulse page (stack index 0) ────────────────────────────────────────────
    TQWidget *pulseWidget = new TQWidget( m_backendStack );
    TQVBoxLayout *pl = new TQVBoxLayout( pulseWidget, 0, spacingHint() );

    TQGroupBox *popupBox = new TQGroupBox( i18n("Mini popup shows:"), pulseWidget );
    popupBox->setColumnLayout( 0, TQt::Vertical );
    popupBox->layout()->setSpacing( spacingHint() );
    popupBox->layout()->setMargin( marginHint() );
    TQVBoxLayout *pcl = new TQVBoxLayout( popupBox->layout() );
    m_popupShowOutput = new TQCheckBox( i18n("Default output (speakers/headphones)"), popupBox );
    m_popupShowMic    = new TQCheckBox( i18n("Microphone inputs"), popupBox );
    m_popupShowApps   = new TQCheckBox( i18n("Active app streams"), popupBox );
    pcl->addWidget( m_popupShowOutput );
    pcl->addWidget( m_popupShowMic );
    pcl->addWidget( m_popupShowApps );
    pl->addWidget( popupBox );

    TQGroupBox *recBox = new TQGroupBox( i18n("Recording"), pulseWidget );
    recBox->setColumnLayout( 0, TQt::Vertical );
    recBox->layout()->setSpacing( spacingHint() );
    recBox->layout()->setMargin( marginHint() );
    TQVBoxLayout *rcl = new TQVBoxLayout( recBox->layout() );
    m_showRecTray = new TQCheckBox( i18n("Show microphone-in-use icon in tray"), recBox );
    rcl->addWidget( m_showRecTray );
    pl->addWidget( recBox );

    pl->addSpacing( 8 );

    TQGroupBox *viewBox = new TQGroupBox( i18n("View"), pulseWidget );
    viewBox->setColumnLayout( 0, TQt::Vertical );
    viewBox->layout()->setSpacing( spacingHint() );
    viewBox->layout()->setMargin( marginHint() );
    TQVBoxLayout *vbl = new TQVBoxLayout( viewBox->layout() );
    m_noTabs = new TQCheckBox( i18n("Show all devices in one view (no tabs)"), viewBox );
    connect( m_noTabs, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(onNoTabsToggled(bool)) );
    vbl->addWidget( m_noTabs );
    vbl->addSpacing( 4 );
    m_showTabsLabel = new TQLabel( i18n("Show tabs:"), viewBox );
    vbl->addWidget( m_showTabsLabel );
    m_showOutput    = new TQCheckBox( i18n("Output"),    viewBox );
    m_showInput     = new TQCheckBox( i18n("Input"),     viewBox );
    m_showPlayback  = new TQCheckBox( i18n("Playback"),  viewBox );
    m_showRecording = new TQCheckBox( i18n("Recording"), viewBox );
    vbl->addWidget( m_showOutput );
    vbl->addWidget( m_showInput );
    vbl->addWidget( m_showPlayback );
    vbl->addWidget( m_showRecording );
    pl->addWidget( viewBox );
    pl->addStretch();

    int nextPage = 0;
    m_backendStack->addWidget( pulseWidget, nextPage++ );

#ifdef WITH_ALSA
    // ── ALSA page ────────────────────────────────────────────────────────────
    TQWidget *alsaWidget = new TQWidget( m_backendStack );
    TQVBoxLayout *al = new TQVBoxLayout( alsaWidget, 0, spacingHint() );

    TQHBoxLayout *trayRow = new TQHBoxLayout( 0, 0, spacingHint() );
    trayRow->addWidget( new TQLabel( i18n("Tray device:"), alsaWidget ) );
    m_trayDevice = new TQComboBox( false, alsaWidget );

    if ( m_alsaModel ) {
        TQPtrList<AlsaDevice> devs = m_alsaModel->devices();
        for ( TQPtrListIterator<AlsaDevice> it(devs); *it; ++it ) {
            AlsaDevice *dev = *it;
            if ( dev->category() == AlsaDevice::Output &&
                 dev->type()     == AlsaDevice::Slider ) {
                m_trayDevice->insertItem(
                    TQString("%1 - %2").arg(dev->cardName()).arg(dev->name()) );
                m_trayCardIndices.append( dev->cardIndex() );
                m_trayDeviceNames.append( dev->name() );
            }
        }
    } else {
        m_trayDevice->setEnabled( false );
    }

    trayRow->addWidget( m_trayDevice, 1 );
    al->addLayout( trayRow );
    al->addStretch();

    m_backendStack->addWidget( alsaWidget, nextPage++ );
#endif

#ifdef WITH_OSS
    // ── OSS page ─────────────────────────────────────────────────────────────
    TQWidget *ossWidget = new TQWidget( m_backendStack );
    TQVBoxLayout *ol = new TQVBoxLayout( ossWidget, 0, spacingHint() );

    TQHBoxLayout *ossTrayRow = new TQHBoxLayout( 0, 0, spacingHint() );
    ossTrayRow->addWidget( new TQLabel( i18n("Tray device:"), ossWidget ) );
    m_ossTrayDevice = new TQComboBox( false, ossWidget );

    if ( m_ossModel ) {
        TQPtrList<OssDevice> devs = m_ossModel->devices();
        for ( TQPtrListIterator<OssDevice> it(devs); *it; ++it ) {
            OssDevice *dev = *it;
            if ( dev->category() == OssDevice::Output ) {
                m_ossTrayDevice->insertItem(
                    TQString("%1 - %2").arg(dev->cardPath()).arg(dev->name()) );
                m_ossTrayCardIndices.append( dev->cardIndex() );
                m_ossTrayDeviceNames.append( dev->name() );
            }
        }
    } else {
        m_ossTrayDevice->setEnabled( false );
    }

    ossTrayRow->addWidget( m_ossTrayDevice, 1 );
    ol->addLayout( ossTrayRow );
    ol->addStretch();

    m_backendStack->addWidget( ossWidget, nextPage++ );
#endif

    // Show the page matching the current backend
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("General");
    TQString backend = cfg->readEntry("Backend", "pulse");
    int backendPage = m_backendIds.findIndex(backend);
    m_backendStack->raiseWidget( backendPage >= 0 ? backendPage : 0 );

    connect( m_backend, TQ_SIGNAL(activated(int)),
             this,       TQ_SLOT(onBackendComboChanged(int)) );
}

// ── Slot: backend combo changed ───────────────────────────────────────────────

void PreferencesDlg::onBackendComboChanged( int idx )
{
    m_backendStack->raiseWidget( idx );
}

void PreferencesDlg::onNoTabsToggled( bool checked )
{
    bool tabsEnabled = !checked;
    m_showTabsLabel->setEnabled( tabsEnabled );
    m_showOutput->setEnabled( tabsEnabled );
    m_showInput->setEnabled( tabsEnabled );
    m_showPlayback->setEnabled( tabsEnabled );
    m_showRecording->setEnabled( tabsEnabled );
}

// ── onPopupModeChanged ────────────────────────────────────────────────────────

void PreferencesDlg::onPopupModeChanged( int idx )
{
    bool popupEnabled = ( idx == 1 );
    if ( m_popupShowOutput ) m_popupShowOutput->setEnabled( popupEnabled );
    if ( m_popupShowMic    ) m_popupShowMic->setEnabled( popupEnabled );
    if ( m_popupShowApps   ) m_popupShowApps->setEnabled( popupEnabled );
}

// ── load / save ───────────────────────────────────────────────────────────────

void PreferencesDlg::load()
{
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("General");

    TQString backend = cfg->readEntry("Backend", "pulse");
    int backendIdx = m_backendIds.findIndex(backend);
    m_backend->setCurrentItem( backendIdx >= 0 ? backendIdx : 0 );
    m_confirmQuit->setChecked( cfg->readBoolEntry("ConfirmQuit", false) );
    m_startOnLogin->setChecked( TQFile::exists( autostartPath() ) );

    cfg->setGroup("Tray");
    m_dockInTray->setChecked( cfg->readBoolEntry("DockInTray", true) );
    int mode = cfg->readNumEntry("PopupMode", 1);
    m_popupMode->setCurrentItem( mode );
    onPopupModeChanged( mode );
    m_middleClickMute->setChecked( cfg->readBoolEntry("MiddleClickMute", false) );
    m_scrollStep->setValue(        cfg->readNumEntry( "ScrollStep",      5    ) );

    m_popupShowOutput->setChecked( cfg->readBoolEntry("PopupShowOutput", true)  );
    m_popupShowMic->setChecked(    cfg->readBoolEntry("PopupShowMic",    false) );
    m_popupShowApps->setChecked(   cfg->readBoolEntry("PopupShowApps",   true)  );
    m_showRecTray->setChecked(     cfg->readBoolEntry("ShowRecordingTray", true) );

    cfg->setGroup("View");
    m_noTabs->setChecked(        cfg->readBoolEntry("NoTabs",        false) );
    m_showOutput->setChecked(    cfg->readBoolEntry("ShowOutput",    true)  );
    m_showInput->setChecked(     cfg->readBoolEntry("ShowInput",     true)  );
    m_showPlayback->setChecked(  cfg->readBoolEntry("ShowPlayback",  true)  );
    m_showRecording->setChecked( cfg->readBoolEntry("ShowRecording", true)  );

#ifdef WITH_ALSA
    if ( m_trayDevice && !m_trayCardIndices.isEmpty() ) {
        cfg->setGroup("Tray");
        int preferredCard     = cfg->readNumEntry("TrayCard",   -1);
        TQString preferredName = cfg->readEntry(  "TrayDevice", "");
        TQValueListConstIterator<int>     ci = m_trayCardIndices.begin();
        TQValueListConstIterator<TQString> ni = m_trayDeviceNames.begin();
        for ( int i = 0; ci != m_trayCardIndices.end(); ++ci, ++ni, ++i ) {
            if ( *ci == preferredCard && *ni == preferredName ) {
                m_trayDevice->setCurrentItem(i);
                break;
            }
        }
    }
#endif

#ifdef WITH_OSS
    if ( m_ossTrayDevice && !m_ossTrayCardIndices.isEmpty() ) {
        cfg->setGroup("OssTray");
        int preferredCard     = cfg->readNumEntry("TrayCard",   -1);
        TQString preferredName = cfg->readEntry(  "TrayDevice", "");
        TQValueListConstIterator<int>     ci = m_ossTrayCardIndices.begin();
        TQValueListConstIterator<TQString> ni = m_ossTrayDeviceNames.begin();
        for ( int i = 0; ci != m_ossTrayCardIndices.end(); ++ci, ++ni, ++i ) {
            if ( *ci == preferredCard && *ni == preferredName ) {
                m_ossTrayDevice->setCurrentItem(i);
                break;
            }
        }
    }
#endif
}

void PreferencesDlg::save()
{
    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup("General");
    int bi = m_backend->currentItem();
    TQString backendKey = (bi >= 0 && bi < (int)m_backendIds.count()) ? m_backendIds[bi] : "pulse";
    cfg->writeEntry( "Backend", backendKey );
    cfg->writeEntry( "ConfirmQuit", m_confirmQuit->isChecked() );

    // Autostart: create or remove ~/.trinity/Autostart/tmix.desktop
    TQString apath = autostartPath();
    if ( m_startOnLogin->isChecked() ) {
        if ( !TQFile::exists( apath ) ) {
            TQFile f( apath );
            if ( f.open( IO_WriteOnly ) ) {
                TQTextStream ts( &f );
                ts << "[Desktop Entry]\n"
                   << "Type=Application\n"
                   << "Name=TMix\n"
                   << "Exec=tmix\n"
                   << "X-TDE-StartupNotify=false\n";
            }
        }
    } else {
        TQFile::remove( apath );
    }

    cfg->setGroup("Tray");
    cfg->writeEntry( "DockInTray",      m_dockInTray->isChecked()      );
    cfg->writeEntry( "PopupMode",       m_popupMode->currentItem()     );
    cfg->writeEntry( "MiddleClickMute", m_middleClickMute->isChecked() );
    cfg->writeEntry( "ScrollStep",      m_scrollStep->value()          );
    cfg->writeEntry( "PopupShowOutput", m_popupShowOutput->isChecked() );
    cfg->writeEntry( "PopupShowMic",    m_popupShowMic->isChecked()    );
    cfg->writeEntry( "PopupShowApps",   m_popupShowApps->isChecked()   );
    cfg->writeEntry( "ShowRecordingTray", m_showRecTray->isChecked()   );

    cfg->setGroup("View");
    cfg->writeEntry( "NoTabs",        m_noTabs->isChecked()        );
    cfg->writeEntry( "ShowOutput",    m_showOutput->isChecked()    );
    cfg->writeEntry( "ShowInput",     m_showInput->isChecked()     );
    cfg->writeEntry( "ShowPlayback",  m_showPlayback->isChecked()  );
    cfg->writeEntry( "ShowRecording", m_showRecording->isChecked() );

#ifdef WITH_ALSA
    if ( m_trayDevice && m_alsaModel ) {
        int ti = m_trayDevice->currentItem();
        if ( ti >= 0 && ti < (int)m_trayCardIndices.count() ) {
            TQValueListConstIterator<int>     ci = m_trayCardIndices.begin();
            TQValueListConstIterator<TQString> ni = m_trayDeviceNames.begin();
            for ( int i = 0; i < ti; ++i ) { ++ci; ++ni; }
            m_alsaModel->setPreferredOutput( *ci, *ni );
        }
    }
#endif

#ifdef WITH_OSS
    if ( m_ossTrayDevice && m_ossModel ) {
        int ti = m_ossTrayDevice->currentItem();
        if ( ti >= 0 && ti < (int)m_ossTrayCardIndices.count() ) {
            TQValueListConstIterator<int>     ci = m_ossTrayCardIndices.begin();
            TQValueListConstIterator<TQString> ni = m_ossTrayDeviceNames.begin();
            for ( int i = 0; i < ti; ++i ) { ++ci; ++ni; }
            m_ossModel->setPreferredOutput( *ci, *ni );
        }
    }
#endif

    cfg->sync();
    emit settingsChanged();
}

void PreferencesDlg::slotOk()    { save(); accept(); }
void PreferencesDlg::slotApply() { save(); }

#include "preferencesdlg.moc"
