using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Diagnostics;
using System;
using System.ServiceModel;

namespace WpkgInstaller
{
    public enum ServiceState
    {
        SERVICE_STOPPED = 0x00000001,
        SERVICE_START_PENDING = 0x00000002,
        SERVICE_STOP_PENDING = 0x00000003,
        SERVICE_RUNNING = 0x00000004,
        SERVICE_CONTINUE_PENDING = 0x00000005,
        SERVICE_PAUSE_PENDING = 0x00000006,
        SERVICE_PAUSED = 0x00000007,
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ServiceStatus
    {
        public int dwServiceType;
        public ServiceState dwCurrentState;
        public int dwControlsAccepted;
        public int dwWin32ExitCode;
        public int dwServiceSpecificExitCode;
        public int dwCheckPoint;
        public int dwWaitHint;
    };
    public partial class WpkgInstaller : ServiceBase
    {

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool SetServiceStatus(System.IntPtr handle, ref ServiceStatus serviceStatus);
        public WpkgInstaller()
        {
            InitializeComponent();
            
            OpenMessageChannel();

            eventLog = new EventLog();
            string eventSourceName = "WpkgInstaller Service";
            string logName = "WpkgNotifier";

            if (!EventLog.SourceExists(eventSourceName))
            {
                EventLog.CreateEventSource(eventSourceName, logName);
            }

            eventLog.Source = eventSourceName;
            eventLog.Log = logName;

        }

        protected override void OnStart(string[] args)
        {

            ServiceStatus serviceStatus = new ServiceStatus
            {
                dwCurrentState = ServiceState.SERVICE_START_PENDING,
                dwWaitHint = 100000
            };
            SetServiceStatus(ServiceHandle, ref serviceStatus);
            // RunWpkgSync();
            serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
            SetServiceStatus(ServiceHandle, ref serviceStatus);

            eventLog.WriteEntry("Service started", EventLogEntryType.Information);
        }

        protected override void OnStop()
        {
            ServiceStatus serviceStatus = new ServiceStatus
            {
                dwCurrentState = ServiceState.SERVICE_STOP_PENDING,
                dwWaitHint = 100000
            };
            SetServiceStatus(ServiceHandle, ref serviceStatus);

            serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED;
            SetServiceStatus(ServiceHandle, ref serviceStatus);

            eventLog.WriteEntry("Service stopped", EventLogEntryType.Information);
        }

        private void RunWpkgSync()
        {
            eventLog.WriteEntry("Starting sync", EventLogEntryType.Information);
            RunWpkgCommand("/synchronize");
        }

        private void RunWpkgQuery()
        {
            eventLog.WriteEntry("Starting query", EventLogEntryType.Information);
            RunWpkgCommand("/query:m");
        }
        private void RunWpkgCommand(string arg)
        {
            Process process = new Process();
            ProcessStartInfo startInfo = new ProcessStartInfo()
            {
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                WindowStyle = ProcessWindowStyle.Hidden,

                FileName = Environment.GetEnvironmentVariable("comspec"),
                Arguments = String.Format("/C \\\\wpkg.ch.cam.ac.uk\\wpkg\\wpkg.cmd {0}", arg),
                WorkingDirectory = Environment.GetEnvironmentVariable("temp"),

                UseShellExecute = false,
            };

            process.StartInfo = startInfo;

            process.EnableRaisingEvents = true;
            process.OutputDataReceived += WriteStdoutToLog;
            process.ErrorDataReceived += WriteStderrToLog;

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();
            process.WaitForExit();

            String msg = String.Format("wpkg command finished, with exit code {0}", process.ExitCode);
            eventLog.WriteEntry(msg, EventLogEntryType.Information);

        }

        private void WriteStdoutToLog(object sendingProcess, DataReceivedEventArgs e)
        {
            if (e != null && e.Data != null)
            {
                eventLog.WriteEntry(e.Data, EventLogEntryType.Information);
            }

        }

        private void WriteStderrToLog(object sendingProcess, DataReceivedEventArgs e)
        {
            if (e != null && e.Data != null)
            {
                eventLog.WriteEntry(e.Data, EventLogEntryType.Error);
            }

        }

        private void eventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
        {

        }

        private void OpenMessageChannel()
        {
            Uri BaseAddress = new Uri("net.pipe://localhost/www.ch.cam.ac.uk/WpkgNotifier");
            NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);

            WpkgInstallerMessageService svc = new WpkgInstallerMessageService();
            ServiceHost SvcHost = new ServiceHost(svc, BaseAddress);
            SvcHost.AddServiceEndpoint(typeof(IWpkgMessageRequestHandlerContract), binding, "");
            SvcHost.Open();

            (SvcHost.SingletonInstance as WpkgInstallerMessageService).WpkgEventCallback += new WpkgEventCallbackHandler(ProcessMessage);

        }

        private WpkgMessageRequestType ProcessMessage(object sender, WpkgMessageRequest e)
        {
            eventLog.WriteEntry(string.Format("Got {0}", e.Type));
            switch(e.Type)
            {
                case WpkgMessageRequestType.DO_SYNC:
                    RunWpkgSync();
                    break;
                case WpkgMessageRequestType.RUN_QUERY:
                    RunWpkgQuery();
                    break;

            }
            return WpkgMessageRequestType.DONE;


        }
    }
}