using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Xml.Serialization;
using log4net.Appender;
using log4net.Config;
using Orbiter.Multiplayer;

namespace Orbiter
{
    class ServerConsole
    {
        static void Main(string[] args)
        {
            var consoleConfiguration=new ServerConsoleConfiguration();
            
            //Check and filter commandline arguments
            if (args.Length > 1)
            {
                DumpHelp();
                return;
            }
            foreach (var arg in args)
            {
                switch(arg.ToLower())
                {
                    case "-h":
                    case "--help":
                        DumpHelp();
                        return;
                    default:
                        if (!File.Exists(arg))
                        {
                            Console.Error.WriteLine("Can't access server console configuration file '" + arg + "' !");
                            return;
                        }
                        var path = Path.IsPathRooted(arg)?arg:Path.Combine(AppDomain.CurrentDomain.BaseDirectory, arg);
                        try
                        {
                            var configurationSerializer = new XmlSerializer(typeof(ServerConsoleConfiguration));
                            consoleConfiguration = configurationSerializer.Deserialize(File.OpenRead(path)) as ServerConsoleConfiguration;
                        }
                        catch (Exception ex)
                        {
                            Console.Error.WriteLine("Can't decode server console configuration file!\n\rException occured: " + ex);
                            return;
                        }
                        if (consoleConfiguration == null) consoleConfiguration = new ServerConsoleConfiguration();
                        break;
                }
            }
            if (consoleConfiguration.ServerConfigurationEditor==null)
                consoleConfiguration.ServerConfigurationEditor=new ServerConsoleConfigurationServerConfigurationEditor();
            if (consoleConfiguration.LoggerConfigurationEditor==null)
                consoleConfiguration.LoggerConfigurationEditor=new ServerConsoleConfigurationLoggerConfigurationEditor();
            if (consoleConfiguration.TelnetClient==null)
                consoleConfiguration.TelnetClient=new ServerConsoleConfigurationTelnetClient();
            if (!File.Exists(consoleConfiguration.OMPServerConfiguration))
            {
                Console.Error.WriteLine("Can't access server configuration file '" + consoleConfiguration.OMPServerConfiguration + "' !");
                return;
            }
            FileInfo loggerConfiguration = null;
            if (!File.Exists(consoleConfiguration.OMPLoggerConfiguration))
                Console.Out.WriteLine("Can't access logger configuration file '" + consoleConfiguration.OMPLoggerConfiguration + "' !");
            else loggerConfiguration = new FileInfo(consoleConfiguration.OMPLoggerConfiguration);
            
            //Configure logger
            using(new AnsiColorForwardingAppender()){/*Do nothing, just load custom appender to allow log4net detecting it*/}
            if (loggerConfiguration != null) XmlConfigurator.ConfigureAndWatch(loggerConfiguration);
            else log4net.LogManager.ResetConfiguration();

            //Start server
            var server = new Server(new []{consoleConfiguration.OMPServerConfiguration});
            server.Start();
            
            //Input loop
            var key=ConsoleKey.NoName;
            while (key != ConsoleKey.Q)
            {
                try{key = Console.ReadKey(true).Key;}
                catch (InvalidOperationException){key = 0;}
                switch (key)
                {
                    case ConsoleKey.C:
                        try
                        {
                            Process.Start(consoleConfiguration.ServerConfigurationEditor.Path,
                                          String.Format(consoleConfiguration.ServerConfigurationEditor.Arguments,
                                            Path.GetFullPath(consoleConfiguration.OMPServerConfiguration)));
                        }
                        catch (Exception ex)
                        {
                            Console.Error.WriteLine("Can't start server configuration editor!\n\rException occured: " + ex);
                        }
                        break;
                    case ConsoleKey.G:
                        GC.Collect();
                        Console.WriteLine("Collector triggered.\n");
                        break;
                    case ConsoleKey.S:
                        try
                        {
                            Process.Start(consoleConfiguration.TelnetClient.Path,
                                          String.Format(consoleConfiguration.TelnetClient.Arguments,
                                            server.Configuration.Network.TCP.ToString(),
                                            server.Configuration.Network.IP,
                                            server.Configuration.Name));
                        }
                        catch (Exception ex)
                        {
                            Console.Error.WriteLine("Can't start telnet client!\n\rException occured: " + ex);
                        }
                        break;
                    case ConsoleKey.L:
                        try
                        {
                            Process.Start(consoleConfiguration.LoggerConfigurationEditor.Path,
                                          String.Format(consoleConfiguration.LoggerConfigurationEditor.Arguments,
                                            Path.GetFullPath(consoleConfiguration.OMPLoggerConfiguration)));
                        }
                        catch (Exception ex)
                        {
                            Console.Error.WriteLine("Can't start logger configuration editor!\n\rException occured: " + ex);
                        }
                        break;
                    case ConsoleKey.Q:
                        log4net.LogManager.ResetConfiguration();
                        Console.Write("Enter admin password: ");
                        var passwd = Console.ReadLine();
                        if (passwd!=server.Configuration.Password.Admin) key=ConsoleKey.NoName;
                        if (loggerConfiguration!=null) XmlConfigurator.ConfigureAndWatch(loggerConfiguration);
                        break;
                    case ConsoleKey.K:
                        server.Locked = !server.Locked;
                        Console.WriteLine("Server "+(server.Locked?"locked":"open")+".\n");
                        break;                    
                    case 0:
                        Thread.Sleep(Timeout.Infinite);
                        break;
                    default:
                        Console.WriteLine("Key '"+key+"' not supported! Supported keys:\n" +
                                          " c  .. edit configuration file\n" +
                                          " g  .. trigger garbage collector\n" +
                                          " k  .. lock/unlock server\n" +
                                          " l  .. edit log configuration\n" +
                                          " s  .. start shell\n" +
                                          " q  .. quit server\n");
                        break;
                }
            }
            server.Stop();
        }

        private static void DumpHelp()
        {
            Console.Out.WriteLine("\n\rOrbiter Multiplayer Project Server Console - "+new Multiplayer.Version());
            Console.Out.WriteLine("Copyright (C) 2007-2008  Friedrich Kastner-Masilko");
            Console.Out.WriteLine("\n\rUsage:      ServerConsole <path_to_configuration>\n\r\n\rOptions:\n\r -h --help  Displays this help and exits.");
            Console.Out.WriteLine("\n\rNotes:\n\r------\n\rIf no configuration path is specified, the system looks for:\n\r* 'server.xml' in the application directory as server configuration and\n\r* 'server.log4net' in the application directory as logger configuration.\n\rIn addition, puttytel (most reside in the application directory) is used\n\ras telnet client and notepad as configuration editor.");
        }
    }
}
