// 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.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;


namespace Hiperscan.Unix
{
    public static 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: " +
                                                       Process._GetLastError());
                    }
                }
                catch (EntryPointNotFoundException)
                {
                    setproctitle(Encoding.ASCII.GetBytes("%s\0"),
                                 Encoding.ASCII.GetBytes(name + "\0"));
                }
            }
#pragma warning disable RECS0022
            catch { }
#pragma warning restore RECS0022
        }

        public static void SetCtrlCDelegate()
        {
            Console.CancelKeyPress += (sender, 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;
        }

        private static int _GetLastError()
        {
            return (int)Reflector.Instance.StdlibGetLastErrorMethod.Invoke(null, null);
        }

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

        public static System.Diagnostics.Process OpenUri(Uri uri)
        {
            if (Environment.OSVersion.Platform != PlatformID.Unix)
                return System.Diagnostics.Process.Start(uri.ToString());

            if (FileIO.ExistsFile("/usr/bin/xdg-open"))
                return System.Diagnostics.Process.Start("/usr/bin/xdg-open", "\"" + uri.ToString() + "\"");

            if (FileIO.ExistsFile("/usr/bin/kfmclient"))
                return System.Diagnostics.Process.Start("/usr/bin/kfmclient", "\"" + uri.ToString() + "\"");

            throw new NotSupportedException("Cannot open URI.");
        }

        public static System.Diagnostics.Process OpenUri(string uri_string)
        {
            return Process.OpenUri(new Uri(uri_string));
        }
    }
}
