/*
 *  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
 */

#include <iostream>
#include <iomanip>
#include <cstdio>
using namespace std;

#include <qapplication.h>
#include <qcstring.h>
#include <qdir.h>
#include <qdialog.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qpixmap.h>
#include <qstring.h>

#include "AudioConfig.h"
#include "AudioDrivers.h"
#include "AudioDriver.h"
#include "AudioDriverNull.h"
#ifdef XSID_HAVE_ARTSC
#include "AudioDriverARTSC.h"
#endif
#ifdef XSID_HAVE_ESD
#include "AudioDriverESD.h"
#endif

#include "ConfigFile.h"
#include "ConfigFileOld.h"
#include "ConfigC.h"
#include "MainDialog.h"
#include "Player.h"
#include "PlaylistItem.h"
#include "wrapper/EmuWrapper.h"

#include "filenames.h"

#include "images/mainicon.xpm"

// Globals.
QPixmap* mainIcon;
QBitmap* mainIconMask;

ConfigFile* config;
Player* player;

AudioConfig bakAudioConfig;

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

int main(int argc, char** argv)
{
    QApplication a(argc,argv);

    // -------------------------------------------------------------- Globals

    AudioDrivers::addDriver( new AudioDriverNull, true );
    AudioDrivers::addDriver( new AudioDriver );
#ifdef XSID_HAVE_ESD
    AudioDrivers::addDriver( new AudioDriverESD );
#endif
#ifdef XSID_HAVE_ARTSC
    AudioDrivers::addDriver( new AudioDriverARTSC );
#endif
        
    player = new Player;
    
    // The SIDPLAY taskbar/panel icon.
    mainIcon = new QPixmap( (const char**)mainicon_xpm );
    mainIconMask = new QBitmap( mainIcon->size() );
    mainIconMask->fill();
    mainIcon->setMask(*mainIconMask);

    // ------------------------------------------------------- Config file(s)
    
    // Try to access $HOME/.sidplay/ and create it if necessary.
    QString homePath = QDir::homeDirPath();  // or getenv("HOME");
    if ( homePath.isEmpty() )
    {
        cerr << "Please set $HOME to your home directory!" << endl;
    }
    QString configPath = homePath + CONFIG_DIR_NAME;
#ifdef XSID_WB_DEBUG
    cout << configPath << endl;
#endif
    QDir configDir(configPath);
    if ( !configDir.exists() && !configDir.mkdir(configPath) )
    {
        cerr << "Cannot create " << configPath << " directory!" << endl;
    }
    
    // Try to move the old history file, if possible.
    QString oldHistoryFileName = homePath + '/' + OLD_HISTORY_FILE_NAME;  // obsolete
    if ( QFile::exists(oldHistoryFileName) )
    {
        QString historyFileName = configPath + '/' + HISTORY_FILE_NAME;
        rename(oldHistoryFileName,historyFileName);
    }

    // Construct config file name(s).
    QString configFileName = configPath + '/' + CONFIG_FILE_NAME;
    config = new ConfigFile(configFileName);
    // The default for those who have no custom emu config yet.
    config->setEmuConfig( player->getEmuEngine()->getConfigDefault() );

    // Upgrade from old config file (if any).
    QString oldConfigFileName = homePath + '/' + OLD_CONFIG_FILE_NAME;  // obsolete
    bool haveOldConfigFile = QFile::exists(oldConfigFileName);
    if ( haveOldConfigFile )
    {
        ConfigFileOld* myOldConfigFile = new ConfigFileOld(oldConfigFileName);
        // Somewhat difficult way to retrieve default config from emuEngine
        // to provide defaults when no config file is present.
        myOldConfigFile->setEmuConfig( player->getEmuEngine()->getConfigDefault() );
        myOldConfigFile->load();
        // The following converts the old config to new config style.
        // Parameters not set by the old config get set to defaults.
        myOldConfigFile->convertToIni(config);
        // At this point we can get rid of the old config file.
        if ( !QFile::remove(oldConfigFileName) )
        {
            cerr << "Could not remove old-style config file!" << endl;
        }
    }
    else
    {
        // Load a global config file.
        config->load( "/etc/xsidplay.ini" );
        config->load();
    }

    // Copy config to allow additional command line settings.
    AudioConfig myAudioConfig = config->getAudioConfig();
    // Check some input parameters.
    if (myAudioConfig.bufSize!=0 && (myAudioConfig.bufSize<256))
        myAudioConfig.bufSize = 256;

    // Although we assume the command line user knows what he is doing,
    // we want to provide defaults for "expert" mode. If available, we copy
    // the argument line settings to a separate config.
    AudioConfig argLineAC = myAudioConfig;

    // --------------------------------------------------- Parse command line

    bool expertMode = false;

    unsigned int inFile = 0;
    int commandLineStartSong = 0;
        
    for (int myArg = 1; myArg < argc; myArg++)  
    {
        // Check for options prefix "-".
        if (argv[myArg][0] == '-')  
        {
            // Single "-" means reading from stdin.
            if (strlen(argv[myArg]) == 1)
            {
                if ( inFile == 0 )
                {
                    inFile = myArg;
                    break;
                }
                else
                {
                    cerr << "Command line syntax error." << endl;
                }
            }
            else
            {
                if (qstrnicmp(&argv[myArg][1],"-expert",7) == 0)
                    expertMode = true;
                if (qstrnicmp(&argv[myArg][1],"-nosnd",6) == 0)
                {
                    config->setGroup( ConfigC::groups[ConfigC::Audio] );
                    config->setEntry( ConfigC::keys[ConfigC::Driver], "No Sound" );
                }
                else if (qstrnicmp(&argv[myArg][1],"bufsize",7) == 0)
                    argLineAC.bufSize = atoi(&argv[myArg][1+7]);
                else if (qstrnicmp(&argv[myArg][1],"maxfrags",8) == 0)
                    argLineAC.maxFrags = atoi(&argv[myArg][1+8]);
                else if (qstrnicmp(&argv[myArg][1],"fragsize",8) == 0)
                    argLineAC.fragSize = atoi(&argv[myArg][1+8]);
                else if (qstrnicmp(&argv[myArg][1],"o",1) == 0)
                    commandLineStartSong = atoi(&argv[myArg][1+1]);
            }
        }
        else
        {
            // No prefix. Thus is considered a filename argument.
            if ( inFile == 0 )
            {
                inFile = myArg;
            }
            else 
            {
                cerr << "Command line syntax error." << endl;
                break;
            }
        }
    }

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

    expertMode = false;  // !!! (ms) 1.6.0 - disabled
    
    config->setGroup( ConfigC::groups[ConfigC::Misc] );
    config->setEntry( ConfigC::keys[ConfigC::ExpertMode], expertMode );
        
    if (!expertMode)
    {
        // If the user has provided any command line arguments, these have
        // made it into the argLineAC. Override config file settings here.
        myAudioConfig.bufSize = argLineAC.bufSize;
        myAudioConfig.maxFrags = argLineAC.maxFrags;
        myAudioConfig.fragSize = argLineAC.fragSize;
        // Backup config will be saved upon exit instead of run-time settings.
        // This makes sure, zeroes (0 => default) make it into the config
        // file again instead of temporary command-line settings.
        bakAudioConfig = myAudioConfig;
    }
    else  // expert mode
    {
        // See whether to take command line settings or
        // provide moderate defaults.
        if (argLineAC.bufSize != myAudioConfig.bufSize)
            myAudioConfig.bufSize = argLineAC.bufSize;
        else
            myAudioConfig.bufSize = 2048;
        if (argLineAC.maxFrags != myAudioConfig.maxFrags)
            myAudioConfig.maxFrags = argLineAC.maxFrags;
        else
            myAudioConfig.maxFrags = 2;
        if (argLineAC.fragSize != myAudioConfig.fragSize)
            myAudioConfig.fragSize = argLineAC.fragSize;
        else
            myAudioConfig.fragSize = 2048;
            
        if (myAudioConfig.bufSize < 4*280)  // waveView w=280!
            myAudioConfig.bufSize = 4*280;
    }
    
    // ----------------------------------------------------------------------
    
    config->setAudioConfig(myAudioConfig);

    player->init(myAudioConfig);
    player->readConfig(config);
    
    MainDialog* mainDlg = new MainDialog;  // main _window_
    mainDlg->setup(config,configPath,player);

    if ( inFile!=0 )
    {
        PlaylistItem pi;  // just a dummy
        mainDlg->playFileMain( argv[inFile], commandLineStartSong, pi, true, false );
    }

    a.setMainWidget(mainDlg);
    mainDlg->show();
    // Give control to Qt.
    int qRet = a.exec();

    // ------------------------------------------------------------- Clean up
    
    player->writeConfig(config);
    player->shutdown();
    
    delete mainDlg;
    
    delete mainIcon;
    delete config;
    delete player;
    
    return qRet;
}

