/***************************************************************************
    begin                : Mon Feb  4 23:40:41 EST 2002
    copyright            : (C) 2002 - 2004 by Scott Wheeler
    email                : wheeler@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 <config.h>

#include <tdecmdlineargs.h>
#include <kstatusbar.h>
#include <kdebug.h>
#include <tdemessagebox.h>
#include <tdestandarddirs.h>


#include "juk.h"
#include "slideraction.h"
#include "statuslabel.h"
#include "splashscreen.h"
#include "systemtray.h"
#include "keydialog.h"
#include "tagguesserconfigdlg.h"
#include "filerenamerconfigdlg.h"
#include "actioncollection.h"
#include "cache.h"
#include "playlistsplitter.h"
#include "collectionlist.h"
#include "covermanager.h"
#include "tagtransactionmanager.h"

using namespace ActionCollection;

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

JuK::JuK(TQWidget *parent, const char *name) :
    TDEMainWindow(parent, name, WDestructiveClose),
    m_player(PlayerManager::instance()),
    m_shuttingDown(false)
{
    // Expect segfaults if you change this order.

    readSettings();

    if(m_showSplash && !m_startDocked && Cache::cacheFileExists()) {
	SplashScreen::instance()->show();
	tdeApp->processEvents();
    }

    setupActions();
    setupLayout();
	 
    if(TQApplication::reverseLayout())
	setupGUI(ToolBar | Save | Create, "jukui-rtl.rc");
    else
	setupGUI(ToolBar | Save | Create);

    readConfig();
    setupSystemTray();
    setupGlobalAccels();
    createDirs();

    SplashScreen::finishedLoading();
    TQTimer::singleShot(0, CollectionList::instance(), TQ_SLOT(slotCheckCache()));
    TQTimer::singleShot(0, this, TQ_SLOT(slotProcessArgs()));

    m_sliderAction->slotUpdateOrientation();
}

JuK::~JuK()
{
    kdDebug(65432) << k_funcinfo << endl;
}

TDEActionCollection *JuK::actionCollection() const
{
    return ActionCollection::actions();
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void JuK::setupLayout()
{
    new TagTransactionManager(this);

    m_splitter = new PlaylistSplitter(this, "playlistSplitter");
    setCentralWidget(m_splitter);

    m_statusLabel = new StatusLabel(m_splitter->playlist(), statusBar());
    connect(CollectionList::instance(), TQ_SIGNAL(signalCollectionChanged()),
            m_statusLabel, TQ_SLOT(updateData()));
    statusBar()->addWidget(m_statusLabel, 1);
    PlayerManager::instance()->setStatusLabel(m_statusLabel);

    m_splitter->setFocus();
    resize(750, 500);
}

void JuK::setupActions()
{
    ActionCollection::actions()->setWidget(this);

    KStdAction::quit(this, TQ_SLOT(slotQuit()), ActionCollection::actions());
    KStdAction::undo(this, TQ_SLOT(slotUndo()), ActionCollection::actions());
    KStdAction::cut(tdeApp,   TQ_SLOT(cut()),   ActionCollection::actions());
    KStdAction::copy(tdeApp,  TQ_SLOT(copy()),  ActionCollection::actions());
    KStdAction::paste(tdeApp, TQ_SLOT(paste()), ActionCollection::actions());
    KStdAction::clear(tdeApp, TQ_SLOT(clear()), ActionCollection::actions());
    KStdAction::selectAll(tdeApp, TQ_SLOT(selectAll()), ActionCollection::actions());

    new TDEAction(i18n("Remove From Playlist"), "edit_remove", 0, tdeApp, TQ_SLOT(clear()), ActionCollection::actions(), "removeFromPlaylist");

    TDEActionMenu *actionMenu = new TDEActionMenu(i18n("&Random Play"), "roll", ActionCollection::actions(), "actionMenu");
    actionMenu->setDelayed(false);

    TDERadioAction *ka = new TDERadioAction(i18n("&Disable Random Play"), "player_playlist", 0, ActionCollection::actions(), "disableRandomPlay");
    ka->setExclusiveGroup("randomPlayGroup");
    actionMenu->insert(ka);

    m_randomPlayAction = new TDERadioAction(i18n("Use &Random Play"), "roll", 0, ActionCollection::actions(), "randomPlay");
    m_randomPlayAction->setExclusiveGroup("randomPlayGroup");
    actionMenu->insert(m_randomPlayAction);

    ka = new TDERadioAction(i18n("Use &Album Random Play"), "roll", 0, ActionCollection::actions(), "albumRandomPlay");
    ka->setExclusiveGroup("randomPlayGroup");
    connect(ka, TQ_SIGNAL(toggled(bool)), TQ_SLOT(slotCheckAlbumNextAction(bool)));
    actionMenu->insert(ka);

    new TDEAction(i18n("&Play"),  "media-playback-start",  0, m_player, TQ_SLOT(play()),  ActionCollection::actions(), "play");
    new TDEAction(i18n("P&ause"), "media-playback-pause", 0, m_player, TQ_SLOT(pause()), ActionCollection::actions(), "pause");
    new TDEAction(i18n("&Stop"),  "media-playback-stop",  0, m_player, TQ_SLOT(stop()),  ActionCollection::actions(), "stop");

    new TDEToolBarPopupAction(i18n("previous track", "Previous"), "media-skip-backward", TDEShortcut(), m_player, TQ_SLOT(back()), ActionCollection::actions(), "back");
    new TDEAction(i18n("next track", "&Next"), "media-skip-forward", TDEShortcut(), m_player, TQ_SLOT(forward()), ActionCollection::actions(), "forward");
    new TDEToggleAction(i18n("&Loop Playlist"), 0, TDEShortcut(), ActionCollection::actions(), "loopPlaylist");
    TDEToggleAction *resizeColumnAction =
        new TDEToggleAction(i18n("&Resize Playlist Columns Manually"),
	                  TDEShortcut(), ActionCollection::actions(), "resizeColumnsManually");
    resizeColumnAction->setCheckedState(i18n("&Resize Column Headers Automatically"));

    // the following are not visible by default

    new TDEAction(i18n("Mute"),         "mute",        0, m_player, TQ_SLOT(mute()),        ActionCollection::actions(), "mute");
    new TDEAction(i18n("Volume Up"),    "volumeUp",    0, m_player, TQ_SLOT(volumeUp()),    ActionCollection::actions(), "volumeUp");
    new TDEAction(i18n("Volume Down"),  "volumeDown",  0, m_player, TQ_SLOT(volumeDown()),  ActionCollection::actions(), "volumeDown");
    new TDEAction(i18n("Play / Pause"), "playPause",   0, m_player, TQ_SLOT(playPause()),   ActionCollection::actions(), "playPause");
    new TDEAction(i18n("Seek Forward"), "seekForward", 0, m_player, TQ_SLOT(seekForward()), ActionCollection::actions(), "seekForward");
    new TDEAction(i18n("Seek Back"),    "seekBack",    0, m_player, TQ_SLOT(seekBack()),    ActionCollection::actions(), "seekBack");

    //////////////////////////////////////////////////
    // settings menu
    //////////////////////////////////////////////////

    m_toggleSplashAction =
	new TDEToggleAction(i18n("Show Splash Screen on Startup"),
			  TDEShortcut(), ActionCollection::actions(), "showSplashScreen");
    m_toggleSplashAction->setCheckedState(i18n("Hide Splash Screen on Startup"));
    m_toggleSystemTrayAction =
	new TDEToggleAction(i18n("&Dock in System Tray"),
			  TDEShortcut(), ActionCollection::actions(), "toggleSystemTray");
    m_toggleDockOnCloseAction =
	new TDEToggleAction(i18n("&Stay in System Tray on Close"),
			  TDEShortcut(), ActionCollection::actions(), "dockOnClose");
    m_togglePopupsAction =
	new TDEToggleAction(i18n("Popup &Track Announcement"),
			  TDEShortcut(), this, 0, ActionCollection::actions(), "togglePopups");
    new TDEToggleAction(i18n("Save &Play Queue on Exit"),
                      TDEShortcut(), this, 0, ActionCollection::actions(), "saveUpcomingTracks");

    connect(m_toggleSystemTrayAction, TQ_SIGNAL(toggled(bool)),
	    this, TQ_SLOT(slotToggleSystemTray(bool)));


    m_outputSelectAction = PlayerManager::playerSelectAction(ActionCollection::actions());

    if(m_outputSelectAction)
        m_outputSelectAction->setCurrentItem(0);

    new TDEAction(i18n("&Tag Guesser..."), 0, 0, this, TQ_SLOT(slotConfigureTagGuesser()),
		ActionCollection::actions(), "tagGuesserConfig");

    new TDEAction(i18n("&File Renamer..."), 0, 0, this, TQ_SLOT(slotConfigureFileRenamer()),
		ActionCollection::actions(), "fileRenamerConfig");

    KStdAction::keyBindings(this, TQ_SLOT(slotEditKeys()), ActionCollection::actions());

    //////////////////////////////////////////////////
    // just in the toolbar
    //////////////////////////////////////////////////

    m_sliderAction = new SliderAction(i18n("Track Position"), ActionCollection::actions(),
				      "trackPositionAction");
}

void JuK::setupSystemTray()
{
    if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) {
	m_systemTray = new SystemTray(this, "systemTray");
	m_systemTray->show();

	m_toggleDockOnCloseAction->setEnabled(true);
	m_togglePopupsAction->setEnabled(true);

	connect(m_systemTray, TQ_SIGNAL(quitSelected()), this, TQ_SLOT(slotAboutToQuit()));
    }
    else {
	m_systemTray = 0;
	m_toggleDockOnCloseAction->setEnabled(false);
	m_togglePopupsAction->setEnabled(false);
    }
}

void JuK::setupGlobalAccels()
{
    m_accel = new TDEGlobalAccel(this);

    KeyDialog::insert(m_accel, "Play",        i18n("Play"),         action("play"),        TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "PlayPause",   i18n("Play / Pause"), action("playPause"),   TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "Stop",        i18n("Stop Playing"), action("stop"),        TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "Back",        i18n("Back"),         action("back"),        TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "Forward",     i18n("Forward"),      action("forward"),     TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "SeekBack",    i18n("Seek Back"),    action("seekBack"),    TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "SeekForward", i18n("Seek Forward"), action("seekForward"), TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "VolumeUp",    i18n("Volume Up"),    action("volumeUp"),    TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "VolumeDown",  i18n("Volume Down"),  action("volumeDown"),  TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "Mute",        i18n("Mute"),         action("mute"),        TQ_SLOT(activate()));
    KeyDialog::insert(m_accel, "ShowHide",    i18n("Show / Hide"),  this,    TQ_SLOT(slotShowHide()));
    KeyDialog::insert(m_accel, "ForwardAlbum", i18n("Play Next Album"), action("forwardAlbum"), TQ_SLOT(activate()));

    m_accel->setConfigGroup("Shortcuts");
    m_accel->readSettings();
    m_accel->updateConnections();
}

void JuK::slotProcessArgs()
{
    TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
    TQStringList files;

    for(int i = 0; i < args->count(); i++)
        files.append(args->arg(i));

    CollectionList::instance()->addFiles(files);
}

void JuK::createDirs()
{
    TQDir dir(TDEGlobal::dirs()->saveLocation("data", tdeApp->instanceName() + '/'));
    if (!dir.exists("covers", false))
        dir.mkdir("covers", false);
    dir.cd("covers");
    if (!dir.exists("large", false))
        dir.mkdir("large", false);
}

void JuK::keyPressEvent(TQKeyEvent *e)
{
    if (e->key() >= TQt::Key_Back && e->key() <= TQt::Key_MediaLast)
        e->accept();
    TDEMainWindow::keyPressEvent(e);
}

/**
 * These are settings that need to be know before setting up the GUI.
 */

void JuK::readSettings()
{
    TDEConfigGroup config(TDEGlobal::config(), "Settings");
    m_showSplash = config.readBoolEntry("ShowSplashScreen", true);
    m_startDocked = config.readBoolEntry("StartDocked", false);
}

void JuK::readConfig()
{
    // player settings

    TDEConfigGroup playerConfig(TDEGlobal::config(), "Player");

    if(m_sliderAction->volumeSlider()) {
	int maxVolume = m_sliderAction->volumeSlider()->maxValue();
	int volume = playerConfig.readNumEntry("Volume", maxVolume);
	m_sliderAction->volumeSlider()->setVolume(volume);
    }

    // Default to no random play

    ActionCollection::action<TDEToggleAction>("disableRandomPlay")->setChecked(true);

    TQString randomPlayMode = playerConfig.readEntry("RandomPlay", "Disabled");
    if(randomPlayMode == "true" || randomPlayMode == "Normal")
	m_randomPlayAction->setChecked(true);
    else if(randomPlayMode == "AlbumRandomPlay")
	ActionCollection::action<TDEToggleAction>("albumRandomPlay")->setChecked(true);

    bool loopPlaylist = playerConfig.readBoolEntry("LoopPlaylist", false);
    ActionCollection::action<TDEToggleAction>("loopPlaylist")->setChecked(loopPlaylist);

    // general settings
    
    TDEConfigGroup settingsConfig(TDEGlobal::config(), "Settings");

    bool dockInSystemTray = settingsConfig.readBoolEntry("DockInSystemTray", true);
    m_toggleSystemTrayAction->setChecked(dockInSystemTray);

    bool dockOnClose = settingsConfig.readBoolEntry("DockOnClose", true);
    m_toggleDockOnCloseAction->setChecked(dockOnClose);

    bool showPopups = settingsConfig.readBoolEntry("TrackPopup", false);
    m_togglePopupsAction->setChecked(showPopups);

    if(m_outputSelectAction)
	m_outputSelectAction->setCurrentItem(settingsConfig.readNumEntry("MediaSystem", 0));

    m_toggleSplashAction->setChecked(m_showSplash);
}

void JuK::saveConfig()
{
    // player settings
    
    TDEConfigGroup playerConfig(TDEGlobal::config(), "Player");

    if (m_sliderAction->volumeSlider())
    {
        playerConfig.writeEntry("Volume", m_sliderAction->volumeSlider()->volume());
    }

    playerConfig.writeEntry("RandomPlay", m_randomPlayAction->isChecked());

    TDEToggleAction *a = ActionCollection::action<TDEToggleAction>("loopPlaylist");
    playerConfig.writeEntry("LoopPlaylist", a->isChecked());

    a = ActionCollection::action<TDEToggleAction>("albumRandomPlay");
    if(a->isChecked())
	playerConfig.writeEntry("RandomPlay", "AlbumRandomPlay");
    else if(m_randomPlayAction->isChecked())
	playerConfig.writeEntry("RandomPlay", "Normal");
    else
	playerConfig.writeEntry("RandomPlay", "Disabled");

    // general settings

    TDEConfigGroup settingsConfig(TDEGlobal::config(), "Settings");
    settingsConfig.writeEntry("ShowSplashScreen", m_toggleSplashAction->isChecked());
    settingsConfig.writeEntry("StartDocked", m_startDocked);
    settingsConfig.writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked());
    settingsConfig.writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked());
    settingsConfig.writeEntry("TrackPopup", m_togglePopupsAction->isChecked());
    if(m_outputSelectAction)
	settingsConfig.writeEntry("MediaSystem", m_outputSelectAction->currentItem());

    TDEGlobal::config()->sync();
}

bool JuK::queryExit()
{
    m_startDocked = !isVisible();

    kdDebug(65432) << k_funcinfo << endl;

    hide();

    action("stop")->activate();
    delete m_systemTray;
    m_systemTray = 0;

    CoverManager::shutdown();
    Cache::instance()->save();
    saveConfig();

    delete m_splitter;
    m_splitter = 0;
    return true;
}

bool JuK::queryClose()
{
    kdDebug(65432) << k_funcinfo << endl;

    if(!m_shuttingDown &&
       !tdeApp->sessionSaving() &&
       m_systemTray &&
       m_toggleDockOnCloseAction->isChecked())
    {
	KMessageBox::information(this,
	    i18n("<qt>Closing the main window will keep JuK running in the system tray. "
		 "Use Quit from the File menu to quit the application.</qt>"),
	    i18n("Docking in System Tray"), "hideOnCloseInfo");
	hide();
	return false;
    }
    else
	return true;
}

////////////////////////////////////////////////////////////////////////////////
// private slot definitions
////////////////////////////////////////////////////////////////////////////////

void JuK::slotShowHide()
{
    setShown(!isShown());
}

void JuK::slotAboutToQuit()
{
    m_shuttingDown = true;
}

void JuK::slotQuit()
{
    kdDebug(65432) << k_funcinfo << endl;
    m_shuttingDown = true;

    tdeApp->quit();
}

////////////////////////////////////////////////////////////////////////////////
// settings menu
////////////////////////////////////////////////////////////////////////////////

void JuK::slotToggleSystemTray(bool enabled)
{
    if(enabled && !m_systemTray)
	setupSystemTray();
    else if(!enabled && m_systemTray) {
	delete m_systemTray;
	m_systemTray = 0;
	m_toggleDockOnCloseAction->setEnabled(false);
	m_togglePopupsAction->setEnabled(false);
    }
}

void JuK::slotEditKeys()
{
    KeyDialog::configure(m_accel, ActionCollection::actions(), this);
}

void JuK::slotConfigureTagGuesser()
{
    TagGuesserConfigDlg(this).exec();
}

void JuK::slotConfigureFileRenamer()
{
    FileRenamerConfigDlg(this).exec();
}

void JuK::slotUndo()
{
    TagTransactionManager::instance()->undo();
}

void JuK::slotCheckAlbumNextAction(bool albumRandomEnabled)
{
    // If album random play is enabled, then enable the Play Next Album action
    // unless we're not playing right now.

    if(albumRandomEnabled && !m_player->playing())
	albumRandomEnabled = false;

    action("forwardAlbum")->setEnabled(albumRandomEnabled);
}

#include "juk.moc"
