// Created with MonoDevelop
//
//    Copyright (C) 2010 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Reflection;
using System.Collections.Generic;

namespace Hiperscan.Unix
{
	public class Process
	{
		[DllImport ("libc")] // Linux
		private static extern int prctl(int option, byte [] arg2, IntPtr arg3,
		                                IntPtr arg4, IntPtr arg5);
		
		[DllImport ("libc")] // BSD
		private static extern void setproctitle(byte [] fmt, byte [] str_arg);
		
        public static void SetName(string name)
		{
			try
			{
				try 
				{
					if (prctl(15 /* PR_SET_NAME */, Encoding.ASCII.GetBytes(name + "\0"),
					          IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0) 
					{
						throw new ApplicationException("Error setting process name: " +
						                               Mono.Unix.Native.Stdlib.GetLastError());
					}
				}
				catch (EntryPointNotFoundException)
				{
					setproctitle(Encoding.ASCII.GetBytes("%s\0"),
					             Encoding.ASCII.GetBytes(name + "\0"));
				}
			}
			catch {}
		}

        public static void SetCtrlCDelegate()
        {
            Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) => {
                System.Diagnostics.Process.Start("/bin/stty", "sane");
                System.Diagnostics.Process.GetCurrentProcess().Kill();
            };
        }

        private static readonly Dictionary<Guid,ConsoleCancelEventHandler> cancel_actions = new Dictionary<Guid,ConsoleCancelEventHandler>();

        public static Guid SetCtrlCDelegate(Action on_cancel)
        {
            Guid guid = Guid.NewGuid();
            void action(object sender, ConsoleCancelEventArgs e) => on_cancel.Invoke();
            Process.cancel_actions.Add(guid, action);
            Console.CancelKeyPress += action;

            return guid;
        }

        public static void UnsetCtrlCDelegate(Guid guid)
        {
            Console.CancelKeyPress -= Process.cancel_actions[guid];
            Process.cancel_actions.Remove(guid);
        }
    }
}