/*
  Copyright (c) 2000 Caldera Systems

  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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <config.h>

#include <iostream>

#include <qfile.h>

#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <klocale.h>
#include <kapp.h>
#include <kmessagebox.h>
#include <kstddirs.h>
#include <kdebug.h>

#include "toplevel.h"
#include "kxdata.h"
#include "kxfreeconfig.h"
#include "xserver.h"
#include "batchmode.h"
#include "xfree4probe.h"

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>

#include <X11/Xlib.h>

static const char *description =
        I18N_NOOP("KDE utility for X-server configuration.");


static const KCmdLineOptions options[] =
{
    { "batchmode", I18N_NOOP("Enable batch mode."), 0 },
    { "pointer <pointermodel>", I18N_NOOP("Batch-mode only: Specify the pointer model to use.\n"
                                "The format is:\n"
                                "<Protocol>,<Wheels>,<Device>\n"
                                " Protocol is the mouse protocol to be used (as\n"
                                " written to XF86Config)\n"
                                " Wheels is the number of mouse wheels\n"
                                " Device is the mouse device"), 0 },
    { "keyboard <keyboard>", I18N_NOOP("Batch-mode only: Specify the keyboard model and\n"
                             "layout to use. The format is:\n"
                             "<Model>,<Layout>\n"
                             " Model is the keyboard model\n"
                             " Layout is the keyboard layout, both as specified\n"
                             " in XF86Config"), 0 },
    { "serverflags <flags>",  I18N_NOOP("Batch-mode only: Specify X server flags.\n"
                              "The format is:\n"
                              "<AllowZap>\n"
                              " AllowZap specifies whether the Ctrl+Alt+BackSpace\n"
                              "shortcut is enabled (1) or not (0)"), 0 },
    { "screen <screenconfig>", I18N_NOOP("Batch-mode only: Specify the basic screen\n"
                               "layout. The format is:\n"
                               "<DefaultDepth>,<DisplayInfo1>,<DisplayInfo2>,...\n"
                               " DefaultDepth specifies the default color depth\n"
                               " DisplayInfo is in the following format:\n"
                               "  Depth,XResolution,YResolution,VertRefresh"), 0 },
    { "monitor <monitorconfig>", I18N_NOOP("Batch-mode only: Specify monitor details\n"
                                 "The format is:\n"
                                 "HSyncMin,HSyncMax,VSyncMin,VSyncMax"), 0 },
    { "videocard <videocardconfig>", I18N_NOOP("Batch-mode only: Specify video card details\n"
                                     "The format is:\n"
                                     "<Driver>,<VendorName>,<Model>\n"
                                     " Driver is the xfree video card driver to use\n"
                                     " VendorName is the vendor name to specify in the\n"
                                     " config file\n"
                                     " Model is the model of the videocard, as specified\n"
                                     " in the BoardName option in the config file"), 0 },
    { "xf86config <file>", I18N_NOOP("Use the specified file to read and write the configuration\n"
                           "settings from/to\n"), 0 },
    { "probe", I18N_NOOP("Force probing of hardware."), 0 },
    { "dontprobe", I18N_NOOP("Prevent probing of hardware."), 0 },
    { 0, 0, 0 }
};


int main( int argc, char *argv[] )
{
    KAboutData aboutData( "kxconfig", I18N_NOOP("KDE X-Configurator"),
                          VERSION, description, KAboutData::License_GPL,
                          "(c) 2000-2001, Caldera (Deutschland) GmbH");
    aboutData.addAuthor( "Matthias Hoelzer-Kluepfel", 0, "mhk@caldera.de" );
    aboutData.addAuthor( "Matthias Elter", 0, "me@caldera.de" );
    aboutData.addAuthor( "Simon Hausmann", 0, "sh@caldera.de" );
    aboutData.addAuthor( "Cornelius Schumacher", 0, "cs@caldera.de" );
    aboutData.addAuthor( "Marcus Meissner", 0, "mm@caldera.de" );
    KCmdLineArgs::init( argc, argv, &aboutData );

    KCmdLineArgs::addCmdLineOptions( options );

    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

    bool batchMode = args->isSet( "batchmode" );

    // Test if a X-Server has to be started.
    bool ownX = false;
    Display *dpy = XOpenDisplay(0);
    if (dpy) {
        XCloseDisplay(dpy);
    } else {
        ownX = true;
    }

    // KXConfig has to run as root.
    if ( getuid() != 0 ) {
        if ( ownX ) {
	    std::cerr << "The KDE X Configurator must be run as root!" << std::endl;
            exit(0);
        } else {
            KApplication app;
            KMessageBox::sorry( 0, i18n( "The KDE X Configurator must be run as root!" ) );
            exit( 0 );
        }
    }

    (void)new KInstance( &aboutData );

    // Initialise global data object
    if ( !KXData::initStatic() )
        return 1;

    // User supplied config file name
    QString customXF86Config;
    if ( args->isSet( "xf86config" ) )
        customXF86Config = args->getOption( "xf86config" );
    // Default config file
    KStandardDirs dirs;
    QString defaultConfigFile = dirs.findResource( "data", "kxconfig/XF86Config-4.default" );

    // Initialise config file object
    KXFreeConfig cfg( customXF86Config );


    // Determine, if hardware should be probed

    bool probe = false;
    bool probeForKxconfig = false;

#ifdef __ia64__
    // We need to probe. The default config file uses "vesa" , which is
    // not supported on IA64. But we must not override loading of the old
    // config file!
    probeForKxconfig = true;
kdDebug() << "IA64\n";
#endif

    if ( args->isSet( "probe" ) ) {
        kdDebug() << "Probe forced." << endl;
        probe = true;
    }

    bool xfree3Config = false;

    // Check, if we need to probe, because we don't have a valid config file
    if ( ownX && !probe ) {
        xfree3Config = !cfg.loadConfig();
        bool configExists = QFile::exists( cfg.configFile() );
        if ( xfree3Config ) kdDebug() << "XFree3 config file found." << endl;
        if ( configExists ) kdDebug() << "Config '" << cfg.configFile() << "' exists." << endl;
        else kdDebug() << "Config '" << cfg.configFile() << "' doesn't exist." << endl;

        if ( xfree3Config || !configExists ) {
            probe = true;
        }
    }

    if ( args->isSet( "dontprobe" ) ) {
        kdDebug() << "Don't probe." << endl;
        probe = false;
    }


    // Probe hardware and choose config file for kxconfig
    QString probedConfigFile;
    QString serverConfigFile = defaultConfigFile;
    if ( probe || probeForKxconfig ) {
        probedConfigFile = dirs.saveLocation( "data", "kxconfig" ) + "/XF86config-4";
        LXFree40Probe p;
        p.probe( probedConfigFile );
	serverConfigFile = probedConfigFile;

    }


    // Determine config file which should be loaded
    QString loadConfigFile;
    if ( probe ) {
        loadConfigFile = probedConfigFile;
    } else {
        if ( cfg.configFile().isEmpty() ) {
            // if no file exists at all, we use a standard template
            loadConfigFile = defaultConfigFile;
        }
    }

    // Start X-Server
    if ( ownX ) {
        kdDebug() << "Starting own X-Server with config file '" << serverConfigFile << "'" << endl;
        LXServer::runServer( serverConfigFile );
    }


    KApplication *app = 0;

    if ( !batchMode )
    {
        app = new KApplication;
    }


    // Load configuration

    if ( xfree3Config || !cfg.loadConfig( loadConfigFile ) )
    {
        if ( batchMode )
        {
            if ( !ownX )
            {
                qDebug( "ERROR: XFree 3.x configuration found with running display." );
                return 1;
            }
            if ( probe ) {
                cfg.loadConfig( probedConfigFile );
            } else {
                cfg.loadConfig( defaultConfigFile );
            }
        }
        else
        {
            if ( !ownX )
            {
                KMessageBox::error( 0, i18n( "XFree 3.x configuration file found.\n"
                                             "It appears that you are already running X Window. In order to\n"
                                             "create a new XFree 4.x configuration you need to start kxconfig\n"
                                             "from the system console. Aborting." ) );
                return 1;
            }
            if ( KMessageBox::questionYesNo( 0, i18n( "XFree 3.x configuration file found.\n"
                                                      "Do you want to use KXConfig to create a new XFree 4.x\n"
                                                      "configuration?" ) ) == KMessageBox::No )
            {
                if ( ownX )
                    LXServer::stopServer();
                return 0;
            }
            if ( probe ) {
                cfg.loadConfig( probedConfigFile );
            } else {
                cfg.loadConfig( defaultConfigFile );
            }
        }
    }

    kdDebug() << "Default config file: " << defaultConfigFile << endl;
    kdDebug() << "Probed config file : " << probedConfigFile << endl;
    kdDebug() << "Loaded config file : " << loadConfigFile << endl;
    kdDebug() << "Save config file   : " << cfg.configFile() << endl;

    if ( batchMode ) {
        processBatchMode( args );
        cfg.saveConfig();
    } else {
        TopLevel *toplevel = new TopLevel( &cfg, ownX );
        toplevel->updateItems();

        if (ownX)
            toplevel->showFullScreen();
        else
            toplevel->resize(720, 540);

        app->setMainWidget(toplevel);
        toplevel->show();

        app->exec();
    }

    // terminate X-Server in case we started our own
    if (ownX) {
        LXServer::stopServer();
    }

    delete app;

    return 0;
}
