using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
using TimberWinR.Outputs;
using TimberWinR.ServiceHost;
using TimberWinR.Inputs;

using Topshelf;
using Topshelf.HostConfigurators;
using Topshelf.Logging;
using Topshelf.ServiceConfigurators;

namespace TimberWinR.ServiceHost
{
    internal class Program
    {
        const string KeyPath = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\TimberWinR";
        const string KeyName = "ImagePath";
        
        private static void Main(string[] args)
        {
            Arguments arguments = new Arguments();
           
            HostFactory.Run(hostConfigurator =>
            {
                string cmdLine = Environment.CommandLine;

                hostConfigurator.Service<TimberWinRService>(serviceConfigurator =>
                {
                    serviceConfigurator.ConstructUsing(() => new TimberWinRService(arguments));
                    serviceConfigurator.WhenStarted(myService => myService.Start());
                    serviceConfigurator.WhenStopped(myService => myService.Stop());
                });
               
                hostConfigurator.AddCommandLineDefinition("configFile", c => arguments.ConfigFile = c);
                hostConfigurator.AddCommandLineDefinition("logLevel", c => arguments.LogLevel = c);
                hostConfigurator.AddCommandLineDefinition("logDir", c => arguments.LogfileDir = c);
                hostConfigurator.AddCommandLineDefinition("diagnosticPort", c => arguments.DiagnosticPort = int.Parse(c));    

                hostConfigurator.ApplyCommandLine();
                hostConfigurator.RunAsLocalSystem();
                hostConfigurator.StartAutomatically();
                hostConfigurator.EnableShutdown();
                hostConfigurator.SetDisplayName("TimberWinR");
                hostConfigurator.SetDescription("TimberWinR using Topshelf");
                hostConfigurator.SetServiceName("TimberWinR");

                hostConfigurator.AfterInstall(() =>
                { 
                    var currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();
                    if (!string.IsNullOrEmpty(currentValue))
                    {
                        AddServiceParameter("-configFile", arguments.ConfigFile);
                        AddServiceParameter("-logLevel", arguments.LogLevel);
                        AddServiceParameter("-logDir", arguments.LogfileDir);
                        if (arguments.DiagnosticPort > 0)
                            AddServiceParameter("-diagnosticPort", arguments.DiagnosticPort);
                    }
                });
            });
        }

        private static void AddServiceParameter(string paramName, string value)
        {
         
            string currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();

            if (!string.IsNullOrEmpty(paramName) && !currentValue.Contains(string.Format("{0} ", paramName)))           
            {
                currentValue += string.Format(" {0} \"{1}\"", paramName, value.Replace("\\\\", "\\"));               
                Registry.SetValue(KeyPath, KeyName, currentValue);               
            }
        }

        private static void AddServiceParameter(string paramName, int value)
        {
    
            string currentValue = Registry.GetValue(KeyPath, KeyName, "").ToString();

            if (!string.IsNullOrEmpty(paramName) && !currentValue.Contains(string.Format("{0}:", paramName)))
            {
                currentValue += string.Format(" {0}:{1}", paramName, value);
                Registry.SetValue(KeyPath, KeyName, currentValue);
            }
        }

    }

    internal class Arguments
    {
        public string ConfigFile { get; set; }
        public string LogLevel { get; set; }
        public string LogfileDir { get; set; }
        public int DiagnosticPort { get; set; }

        public Arguments()
        {
            DiagnosticPort = 5141;
            ConfigFile = "default.json";
            LogLevel = "Info";
            LogfileDir = @"C:\logs";
        }
    }


    internal class TimberWinRService
    {
        readonly CancellationTokenSource _cancellationTokenSource;
        readonly CancellationToken _cancellationToken;
        readonly Task _serviceTask;
        private readonly Arguments _args;
        private TimberWinR.Diagnostics.Diagnostics _diags;
        private TimberWinR.Manager _manager;

        public TimberWinRService(Arguments args)
        {
            _args = args;
            _cancellationTokenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationTokenSource.Token;
            _serviceTask = new Task(RunService, _cancellationToken);           
        }

        public void Start()
        {
            _serviceTask.Start();
        }

        public void Stop()
        {
            _cancellationTokenSource.Cancel();
            if (_diags != null)
             _diags.Shutdown();

            if (_manager != null)
                _manager.Shutdown();
        }

        /// <summary>
        /// The Main body of the Service Worker Thread
        /// </summary>
        private void RunService()
        {
            _manager = new TimberWinR.Manager(_args.ConfigFile, _args.LogLevel, _args.LogfileDir, _cancellationToken);
            if (_args.DiagnosticPort > 0)
                _diags = new Diagnostics.Diagnostics(_manager, _cancellationToken, _args.DiagnosticPort);
        }
    }
}


