using System;
using System.Windows.Forms;
using System.Diagnostics;

//System.IO.Ports.SerialData
//System.Management.ManagementEventWatcher
//System.IO.FileSystemWatcher


namespace Trigger
{
	/// <summary>
	/// <para>The main <see cref="Form"/></para>
	/// </summary>
	/// <remarks>This <see cref="Form"/> is invisible</remarks>
	public partial class Main : Form
	{
		#region Properties
		/// <summary>The logging <see cref="Form"/></summary>
		public Log Log;
		/// <summary>The global EventManager</summary>
		public Events.Manager EventMgr;
		/// <summary>The global TaskManager</summary>
		public Tasks.Manager TaskMgr;
		private StatusView StatusView = null;

		/// <summary>
		/// <para>Checks whether this process has administrator privileges</para>
		/// </summary>
		/// <exception cref="System.Security.SecurityException"></exception>
		public bool IsAdmin
		{
			get
			{
				bool isAdmin = false;
				System.Security.Principal.WindowsIdentity winId = System.Security.Principal.WindowsIdentity.GetCurrent();
				if (winId != null)
					isAdmin = new System.Security.Principal.WindowsPrincipal(winId).IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
				return isAdmin;
			}
		}
		#endregion

		#region Events
		/// <summary>
		/// <para>Is triggered when the application is already running and then gets called with command line arguments</para>
		/// </summary>
		private event Events.EventPlugin.EventValue<int> OnCommandLineTrigger;
		/// <summary>
		/// <para>Is triggered when the application is already running and then gets called with command line arguments</para>
		/// </summary>
		public event Events.EventPlugin.EventValue<int> CommandLineTrigger
		{
			add
			{
				OnCommandLineTrigger += value;
			}
			remove
			{
				OnCommandLineTrigger -= value;
			}
		}
		#endregion

		#region Constructor
		/// <summary></summary>
		public Main()
		{
			this.Visible = false;
			InitializeComponent();

			this.Log = new Log(this);
			this.Log.Show();
			if (this.IsAdmin)
				this.Log.LogLine("Running with admin privileges", Log.Type.Other);
			this.EventMgr = new Events.Manager(this);
			this.TaskMgr = new Tasks.Manager(this);
			this.Log.LogLine(new String('-', 32), Log.Type.Other);

			this.RegisterEventForMessage(Classes.System.WindowsMessages.WM_USER);
			MessageReceived += new Events.EventPlugin.EventValue<Message>(HandleNewInstance);
		}
		public Main(Options options) : this()
		{
		}
		#endregion

		#region Methods
		/// <summary>
		/// <para>Creates a new or refreshes the existing <see cref="StatusView"/></para>
		/// </summary>
		public void RefreshStatus()
		{
			if (this.StatusView == null || this.StatusView.IsDisposed)
				this.StatusView = new StatusView(this);
			else
				this.StatusView.Refresh();
			this.StatusView.Show();
		}

		/// <summary>
		/// <para>Check if the app was started as administrator or restart it with those permissions</para>
		/// <para>This method has to be called during the task initialization process because otherwise the app will be restarted when trying to perform an action that requires administrator priviliges</para>
		/// </summary>
		/// <returns>
		/// <para>Whether administrator privileges are possible and requested</para>
		/// <para>When the user cancels UAC or some other error occurs this will return false.</para>
		/// </returns>
		/// <exception cref="System.ComponentModel.Win32Exception"></exception>
		public bool RequireAdministrator()
		{
			if (this.IsAdmin)
				return true;

			ProcessStartInfo procStart = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName, "-a");
			procStart.UseShellExecute = true;
			procStart.Verb = "runas";	// run as Admin

			this.Log.LogLineDate("Requiring admin privileges...", Trigger.Log.Type.Other);

			try
			{
				Process.Start(procStart);
			}
			catch (System.ComponentModel.Win32Exception e)
			{
				if (e.NativeErrorCode != 1223)		// 1223 = user aborted UAC
					throw;
			}
			return false;
		}

		/// <summary>
		/// <para>Close the application</para>
		/// </summary>
		new public void Close()
		{
			this.Close(true);
		}
		/// <summary>
		/// <para>Ask the user and close the application</para>
		/// </summary>
		/// <param name="ask">Whether the user shall be asked first</param>
		public void Close(bool ask)
		{
			if (ask)
				if (DialogResult.Yes != MessageBox.Show("Do you really want to exit Trigger4Win?", "Quit Trigger4Win", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
					return;
			base.Close();
		}
		#endregion

		#region Event handler
		/// <summary>
		/// <para>Do not show this <see cref="Form"/></para>
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Main_Shown(object sender, EventArgs e)
		{
			this.Visible = false;
		}

		/// <summary>
		/// <para>Exit application</para>
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void tsmNotifyIcon_Exit_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		/// <summary>
		/// <para>Show the Log</para>
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void tmsNotifyIcon_Log_Click(object sender, EventArgs e)
		{
			this.Log.Show();
			this.Log.BringToFront();
			((ToolStripMenuItem)sender).Visible = false;
		}

		/// <summary>
		/// <para>Show the log</para>
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			this.Log.Show();
		}

		/// <summary>
		/// <para>Show <see cref="StatusView"/>: <see cref="RefreshStatus"/></para>
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void tsmNotifyIcon_Status_Click(object sender, EventArgs e)
		{
			this.RefreshStatus();
		}

		private void HandleNewInstance(object sender, Events.EventArgsValue<Message> e)
		{
			if (e.Value.Msg != (int)Classes.System.WindowsMessages.WM_USER)
				return;
			switch (e.Value.LParam.ToInt32())
			{
				case -1:
					this.TaskMgr.Abort();
					Application.Exit();
					return;
				case -2:
					this.Show();
					return;
			}
			switch (e.Value.WParam.ToInt32())
			{
				case 0:
					return;
				default:
					if (OnCommandLineTrigger != null)
						OnCommandLineTrigger(this, new Events.EventArgsValue<int>(e.Value.WParam.ToInt32()));
					return;
			}
		}
		#endregion
	}
}
