using BPASmartClient.Message;
using IWshRuntimeLibrary;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace BPASmartClient.Helper
{
    /// <summary>
    /// 系统操作类
    /// </summary>
    public class SystemHelper
    {
        private volatile static SystemHelper _Instance;
        public static SystemHelper GetInstance => _Instance ?? (_Instance = new SystemHelper());
        private SystemHelper() { }

        /// <summary>
        /// 获取当前应用程序名称，包括后缀名
        /// </summary>
        public string GetApplicationName => $"{AppDomain.CurrentDomain.FriendlyName}.exe";

        /// <summary>
        /// 获取当前应用程序完整路径
        /// </summary>
        public string GetApplicationPath => $"{AppDomain.CurrentDomain.BaseDirectory}{GetApplicationName}";

        /// <summary>
        /// 创建桌面快捷方式
        /// </summary>
        /// <returns>成功或失败</returns>
        public bool CreateDesktopShortcut()
        {
            //1、在COM对象中找到 Windows Script Host Object Model 
            //2、添加引用 using IWshRuntimeLibrary;
            string deskTop = string.Empty;
            try
            {
                deskTop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\";
                if (System.IO.File.Exists(deskTop + GetApplicationName + ".lnk"))  //
                {
                    return true;
                    //System.IO.File.Delete(deskTop + FileName + ".lnk");//删除原来的桌面快捷键方式
                }
                WshShell shell = new WshShell();
                //快捷键方式创建的位置、名称
                IWshShortcut shortcut = shell.CreateShortcut(deskTop + GetApplicationName + ".lnk") as IWshShortcut;
                shortcut.TargetPath = GetApplicationPath; //目标文件
                                                          //该属性指定应用程序的工作目录，当用户没有指定一个具体的目录时，快捷方式的目标应用程序将使用该属性所指定的目录来装载或保存文件。
                shortcut.WorkingDirectory = System.Environment.CurrentDirectory;
                shortcut.WindowStyle = 1; //目标应用程序的窗口状态分为普通、最大化、最小化【1,3,7】
                shortcut.Description = GetApplicationName; //描述
                //shortcut.IconLocation = exePath + "\\logo.ico";  //快捷方式图标
                shortcut.Arguments = "";
                //shortcut.Hotkey = "CTRL+ALT+F11"; // 快捷键
                shortcut.Save(); //必须调用保存快捷才成创建成功
                return true;
            }
            catch (Exception ex)
            {
                MessageLog.GetInstance.ShowEx(ex.ToString());
                return false;
            }
        }

        /// <summary>  
        /// 设置开机自启动  
        /// </summary>  
        /// <param name="isAuto">true:开机启动,false:不开机自启</param> 
        public void AutoStart(bool isAuto = true)
        {
            if (isAuto == true)
            {
                RegistryKey R_local = Registry.CurrentUser;
                RegistryKey R_run = R_local.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
                R_run.SetValue(GetApplicationName, GetApplicationPath);
                R_run.Close();
                R_local.Close();
            }
            else
            {
                RegistryKey R_local = Registry.CurrentUser;
                RegistryKey R_run = R_local.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
                R_run.DeleteValue(GetApplicationName, false);
                R_run.Close();
                R_local.Close();
            }
        }

        /// <summary>
        /// 判断是否是自动启动
        /// </summary>
        /// <returns></returns>
        public bool IsAutoStart()
        {
            RegistryKey R_local = Registry.CurrentUser;
            RegistryKey R_run = R_local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
            bool res = R_run.GetValueNames().Contains(GetApplicationName);
            R_run.Close();
            R_local.Close();
            return res;
        }

        #region U盘，串口插拔信息
        private const int WM_DEVICECHANGE = 0x219; //设备改变
        private const int DBT_DEVICEARRIVAL = 0x8000; //检测到新设备
        private const int DBT_DEVICEREMOVECOMPLETE = 0x8004; //移除设备
        public const int DBT_DEVTYP_PORT = 0x00000003;
        public const int DBT_DEVTYP_VOLUME = 0x00000002;

        public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_DEVICECHANGE)
            {
                //插入
                if (wParam.ToInt32() == DBT_DEVICEARRIVAL)
                {
                    var volume = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_HDR));

                    switch (volume.dbch_devicetype)
                    {
                        case DBT_DEVTYP_PORT://串口设备
                            string portName = Marshal.PtrToStringUni(lParam + Marshal.SizeOf(typeof(DEV_BROADCAST_PORT)));
                            MessageLog.GetInstance.Show($"插入串口：[{portName}]");
                            break;
                        case DBT_DEVTYP_VOLUME:
                            var drive = GetDrive(lParam);
                            MessageLog.GetInstance.Show($"usb插入：[{drive}]");
                            break;
                        default:
                            break;
                    }
                }

                //拔出
                if (wParam.ToInt32() == DBT_DEVICEREMOVECOMPLETE)
                {
                    var volume = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_HDR));
                    switch (volume.dbch_devicetype)
                    {
                        case DBT_DEVTYP_PORT://串口设备
                            string portName = Marshal.PtrToStringUni(lParam + Marshal.SizeOf(typeof(DEV_BROADCAST_PORT)));
                            MessageLog.GetInstance.Show($"拔出串口：[{portName}]");
                            break;
                        case DBT_DEVTYP_VOLUME:
                            var drive = GetDrive(lParam);
                            MessageLog.GetInstance.Show($"usb拔出：[{drive}]");
                            break;
                        default:
                            break;
                    }
                }
            }
            return IntPtr.Zero;
        }

        private static string GetDrive(IntPtr lParam)
        {
            var volume = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_VOLUME));
            var letter = GetLetter(volume.dbcv_unitmask);
            return string.Format("{0}:\\", letter);
        }

        /// <summary>
        /// 获得盘符
        /// </summary>
        /// <param name="dbcvUnitmask">
        /// 1 = A
        /// 2 = B
        /// 4 = C...
        /// </param>
        /// <returns>结果是A~Z的任意一个字符或者为'?'</returns>
        private static char GetLetter(uint dbcvUnitmask)
        {
            const char nona = '?';
            const string drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            if (dbcvUnitmask == 0) return nona;
            var i = 0;
            var pom = dbcvUnitmask >> 1;
            while (pom != 0)
            {
                pom = pom >> 1;
                i++;
            }
            if (i < drives.Length)
                return drives[i];
            return nona;
        }


        #endregion
    }

    [StructLayout(LayoutKind.Sequential)]
    struct DEV_BROADCAST_HDR
    {
        public UInt32 dbch_size;
        public UInt32 dbch_devicetype;
        public UInt32 dbch_reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct DEV_BROADCAST_PORT
    {
        public uint dbcp_size;
        public uint dbcp_devicetype;
        public uint dbcp_reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct DEV_BROADCAST_PORT_A
    {
        public uint dbcp_size;
        public uint dbcp_devicetype;
        public uint dbcp_reserved;
        //public string dbcp_name;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct DEV_BROADCAST_VOLUME
    {
        /// DWORD->unsigned int
        public uint dbcv_size;
        /// DWORD->unsigned int
        public uint dbcv_devicetype;
        /// DWORD->unsigned int
        public uint dbcv_reserved;
        /// DWORD->unsigned int
        public uint dbcv_unitmask;
        /// WORD->unsigned short
        public ushort dbcv_flags;
    }
}
