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

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();

            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);

            Thread thWorker = new Thread(new ThreadStart(delegate
            {
                Process process = new Process();
                ProcessStartInfo startInfo = new ProcessStartInfo()
                {
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    WindowStyle = ProcessWindowStyle.Hidden,

                    FileName = Environment.GetEnvironmentVariable("comspec"),
                    Arguments = "/C \\\\wpkg.ch.cam.ac.uk\\wpkg\\wpkg.cmd /synchronize",
                    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("sync done with exit code {0}", process.ExitCode);
                eventLog.WriteEntry(msg, EventLogEntryType.Information);
            }));

            thWorker.Start();
         
        }

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

        }

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

        }

        private void eventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
        {

        }

    }
}