using Microsoft.CSharp.RuntimeBinder;

using System.Collections.ObjectModel;
using System.Drawing.Imaging;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;

namespace DH.Commons.Helper
{
    public static class StaticHelper
    {
        /// <summary>
        /// 数值转换为byte数组 高位在前,低位在后
        /// </summary>
        /// <param name="number"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public static byte[] IntToBytes(this int number, int size = 2)
        {
            byte[] result = new byte[size];

            int temp = size;
            while (temp > 0)
            {
                result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff);

                temp--;
            }

            return result;
        }

        /// <summary>
        /// 字节数组转换为整数
        /// </summary>
        /// <param name="data">字节数组</param>
        /// <param name="HtL">true:数组序号低的在高位 false:数组序号低的在低位</param>
        /// <returns></returns>
        public static int BytesToInt(this byte[] data, bool HtL = true)
        {
            int res = 0;

            for (int i = 0; i < data.Length; i++)
            {
                int index = i;

                if (HtL)
                {
                    index = data.Length - 1 - i;
                }

                res += data[index] << (8 * i);
            }

            return res;
        }

        /// <summary>
        /// 获取一个类指定的属性值
        /// </summary>
        /// <param name="info">object对象</param>
        /// <param name="field">属性名称</param>
        /// <returns></returns>
        public static object GetPropertyValue(object info, string field)
        {
            if (info == null) return null;
            Type t = info.GetType();
            IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
            return property.First().GetValue(info, null);
        }

        /// <summary>
        /// 将32位整形拆分为无符号16位整形
        /// </summary>
        /// <param name="num">需要拆分的32位整形</param>
        /// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
        /// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
        /// <returns></returns>
        public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false)
        {
            if (bitNum == 2)
            {
                ushort high = (ushort)(num >> 16);
                ushort low = (ushort)num;

                if (HtL)
                {
                    return new List<ushort>() { high, low };
                }
                else
                {
                    return new List<ushort>() { low, high };
                }
            }
            else
            {
                if (num < 0)
                {
                    num = ushort.MaxValue + 1 + num;
                }

                return new List<ushort>() { (ushort)num };
            }
        }

        /// <summary>
        /// 将32位整形数组拆分为无符号16位整形数组
        /// </summary>
        /// <param name="list">需要拆分的32位整形</param>
        /// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
        /// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
        /// <returns></returns>
        public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false)
        {
            return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList();
        }

        /// <summary>
        /// 将ushort的集合转换为16位带符号整形
        /// </summary>
        /// <param name="numList"></param>
        /// <param name="bitNum">合并的位数 1或者2</param>
        /// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
        /// <returns></returns>
        public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false)
        {
            if (bitNum == 1)
            {
                return numList.ConvertAll(n =>
                {
                    int num = n;
                    if (num > short.MaxValue)
                    {
                        num = num - ushort.MaxValue - 1;
                    }

                    return num;
                });
            }
            else
            {
                List<int> list = new List<int>();
                for (int i = 0; i < numList.Count; i += 2)
                {
                    int high = HtL ? numList[i] : numList[i + 1];
                    int low = HtL ? numList[i + 1] : numList[i];
                    list.Add((high << 16) | low);
                }

                return list;
            }
        }

        //public static T DeepSerializeClone<T>(this T t)
        //{
        //    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
        //}

        public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class
        {
            if (sourceT == null)
            {
                destT = null;
                return;
            }

            PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray();
            PropertyInfo[] propSource = sourceT.GetType().GetProperties();

            Array.ForEach(propDest, prop =>
            {
                if (exceptionProps == null || !exceptionProps.Contains(prop.Name))
                {
                    if (prop.CanWrite)
                    {
                        PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name);
                        if (propS != null && propS.CanRead)
                        {
                            prop.SetValue(destT, propS.GetValue(sourceT));
                        }
                    }
                }
            });
        }

       
        //RtlMoveMemory
        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
        public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
        [HandleProcessCorruptedStateExceptions]
        //public static Bitmap CopyBitmap(this Bitmap source)
        //{
        //    Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
        //    try
        //    {
        //        int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
        //        if (PixelSize == 1)
        //        {
        //            ColorPalette cp = clone.Palette;
        //            for (int i = 0; i < 256; i++)
        //            {
        //                cp.Entries[i] = Color.FromArgb(255, i, i, i);
        //            }
        //            clone.Palette = cp;
        //        }

        //        Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
        //        BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
        //        BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
        //        if (source.Width % 4 == 0)
        //        {
        //            unsafe
        //            {
        //                CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height));
        //            }
        //        }
        //        else
        //        {
        //            Parallel.For(0, source.Height, h =>
        //            {
        //                unsafe
        //                {
        //                    CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width);
        //                }
        //            });
        //        }

        //        clone.UnlockBits(cloneData);
        //        source.UnlockBits(sourceData);

        //    }
        //    catch (Exception ex)
        //    {
        //        return clone;
        //    }

        //    return clone;
        //}
        public static Bitmap CopyBitmap(this Bitmap source)
        {
            Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);

            try
            {
                int pixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
                if (pixelSize == 1)
                {
                    ColorPalette cp = clone.Palette;
                    for (int i = 0; i < 256; i++)
                    {
                        cp.Entries[i] = Color.FromArgb(255, i, i, i);
                    }
                    clone.Palette = cp;
                }

                Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
                BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
                BitmapData cloneData = clone.LockBits(rect, ImageLockMode.WriteOnly, source.PixelFormat);

                int stride = sourceData.Stride;
                int height = sourceData.Height;

                if (stride % 4 == 0)
                {
                    unsafe
                    {
                        CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(stride * height));
                    }
                }
                else
                {
                    Parallel.For(0, height, h =>
                    {
                    unsafe
                    {
                        CopyMemory(cloneData.Scan0 + h * stride, sourceData.Scan0 + h * stride, (uint)stride);
                        }
                    });
                }
                source.UnlockBits(sourceData); clone.UnlockBits(cloneData);
            }
            catch (Exception ex)
            { // Handle or log exception if needed
            } return clone; } 


                public static Bitmap BitmapDeepClone(Bitmap source)
        {
            Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);

            try
            {
                int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
                if (PixelSize == 1)
                {
                    ColorPalette cp = clone.Palette;
                    for (int i = 0; i < 256; i++)
                    {
                        cp.Entries[i] = Color.FromArgb(255, i, i, i);
                    }
                    clone.Palette = cp;
                }
                Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
                BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
                BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat);

                int depth_width = source_bitmap.Width * PixelSize;

                unsafe
                {
                    byte* source_ptr = (byte*)source_bitmap.Scan0;
                    byte* destination_ptr = (byte*)destination_bitmap.Scan0;

                    int offset = source_bitmap.Stride - depth_width;

                    for (int i = 0; i < source_bitmap.Height; i++)
                    {
                        for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++)
                        {
                            *destination_ptr = *source_ptr;
                        }

                        source_ptr += offset;
                        destination_ptr += offset;
                    }
                }

                source.UnlockBits(source_bitmap);
                clone.UnlockBits(destination_bitmap);
            }
            catch (Exception ex)
            {

            }
            return clone;
        }



        public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2)
        {
            Bitmap connectImage = null;
            if (map1 == null || map2 == null)
                return null;
            //横向拼接
            int width = map1.Width + map2.Width;
            //高度不变
            int height = Math.Max(map1.Height, map2.Height);
            connectImage = new Bitmap(width, height);
            using (Graphics graph = Graphics.FromImage(connectImage))
            {
                graph.DrawImage(connectImage, width, height);
                graph.Clear(System.Drawing.Color.White);
                graph.DrawImage(map1, 0, 0);
                graph.DrawImage(map2, map1.Width, 0);
            }
            return connectImage;
        }

        public static IntPtr FloatToIntptr(float[] bytes)
        {
            GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
            return hObject.AddrOfPinnedObject();
        }

        // 将Btimap类转换为byte[]类函数
        public static byte[] GetBGRValues(Bitmap bmp, out int stride)
        {
            var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
            stride = bmpData.Stride;
            var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
            var imgBytes = bmp.Height * rowBytes;
            byte[] rgbValues = new byte[imgBytes];
            IntPtr ptr = bmpData.Scan0;
            for (var i = 0; i < bmp.Height; i++)
            {
                Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
                ptr += bmpData.Stride;
            }
            bmp.UnlockBits(bmpData);
            return rgbValues;
        }
        /// <summary>
        /// 缺陷灰度图转彩色图像函数
        /// </summary>
        /// <param name="src">灰度图</param>
        /// <returns>返回构造的伪彩色图像</returns>
        public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null)
        {
            try
            {
                //Stopwatch sw = new Stopwatch();
                //sw.Start();

                Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);

                int destHeight = dest.Height;
                int destWidth = dest.Width;

                Rectangle rect = new Rectangle(0, 0, destWidth, destHeight);
                BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
                int strideDest = bmpDataDest.Stride;

                int strideSrc = bmpDataSrc.Stride;
                unsafe
                {
                    byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer();
                    byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer();

                    Parallel.For(0, destHeight, y =>
                    {
                        Parallel.For(0, destWidth, x =>
                        {
                            int pixel = pSrc[y * strideSrc + x];
                            int startIndex = y * strideDest + x * 4;
                            if (pixel >= 0 && pixel <= 63)
                            {
                                Color color = Color.Red;
                                if (indexColorDict != null && indexColorDict.ContainsKey(pixel))
                                {
                                    color = indexColorDict[pixel];
                                }

                                byte R = color.R;
                                byte G = color.G;
                                byte B = color.B;

                                pDest[startIndex] = B;
                                pDest[startIndex + 1] = G;
                                pDest[startIndex + 2] = R;
                                pDest[startIndex + 3] = 100;
                            }
                            else
                            {
                                pDest[startIndex] = 255;
                                pDest[startIndex + 1] = 255;
                                pDest[startIndex + 2] = 255;
                                pDest[startIndex + 3] = 0;
                            }
                        });
                    });
                }
                dest.UnlockBits(bmpDataDest);
                src.UnlockBits(bmpDataSrc);

                //sw.Stop();
                //Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}");

                return dest;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T>
        {
            List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序 
            for (int i = 0; i < sortedList.Count(); i++)
            {
                collection.Move(collection.IndexOf(sortedList[i]), i);
            }
        }

        /// <summary>
        /// 获得字符串中开始和结束字符串中间的值
        /// </summary>
        /// <param name="sourse"></param>
        /// <param name="startstr"></param>
        /// <param name="endstr"></param>
        /// <returns></returns>
        public static string GetMidString(string sourse, string startstr, string endstr)
        {
            string result = string.Empty;
            int startindex, endindex;
            try
            {
                startindex = sourse.IndexOf(startstr);
                if (startindex == -1)
                    return result;
                string tmpstr = sourse.Substring(startindex + startstr.Length);
                endindex = tmpstr.IndexOf(endstr);
                if (endindex == -1)
                    return result;
                result = tmpstr.Remove(endindex);
            }
            catch (Exception ex)
            {
                return "";
            }
            return result;
        }

        /// <summary>
        /// 获得字符串中开始和结束字符串中间的值
        /// </summary>
        /// <param name="t">字符串</param>
        /// <param name="k">开始</param>
        /// <param name="j">结束</param>
        /// <returns></returns> 
        private static string GetMidString2(string sourse, string startstr, string endstr) //截取指定文本,和易语言的取文本中间差不多
        {
            try //异常捕捉
            {
                var kn = sourse.IndexOf(startstr, StringComparison.Ordinal) + startstr.Length;
                var jn = sourse.IndexOf(endstr, kn, StringComparison.Ordinal);
                return sourse.Substring(kn, jn - kn);
            }
            catch //如果发现未知的错误,比如上面的代码出错了,就执行下面这句代码
            {
                return ""; //返回空
            }

        }

        // 布尔类型转换为整型
        public static int ToInt(this object obj)
        {
            if (Convert.ToBoolean(obj) == true)
                return 1;
            else
                return 0;
        }

        // 整型转换为布尔类型
        public static bool ToBool(this object obj)
        {
            if (Convert.ToInt32(obj) == 1)
                return true;
            else
                return false;
        }

        public static object GetProperty(this object o, string member)
        {
            if (o == null) throw new ArgumentNullException("o");
            if (member == null) throw new ArgumentNullException("member");
            Type scope = o.GetType();
            IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
            if (provider != null)
            {
                ParameterExpression param = Expression.Parameter(typeof(object));
                DynamicMetaObject mobj = provider.GetMetaObject(param);
                GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
                DynamicMetaObject ret = mobj.BindGetMember(binder);
                BlockExpression final = Expression.Block(
                    Expression.Label(CallSiteBinder.UpdateLabel),
                    ret.Expression
                );
                LambdaExpression lambda = Expression.Lambda(final, param);
                Delegate del = lambda.Compile();
                return del.DynamicInvoke(o);
            }
            else
            {
                return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
            }
        }

        #region 检测文件状态及操作方式选择
        [DllImport("kernel32.dll")]
        private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
        [DllImport("kernel32.dll")]
        private static extern bool CloseHandle(IntPtr hObject);
        private const int OF_READWRITE = 2;
        private const int OF_SHARE_DENY_NONE = 0x40;
        private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
        /// <summary>
        /// 检测文件是否只读或被使用
        /// </summary>
        /// <param name="FileNames">要检测的文件</param>
        /// <returns>true可用,false在用或只读</returns>
        public static bool CheckFilesCanUse(string fileName)
        {
            if (!File.Exists(fileName))
                return true;//文件不存在
            if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                return false;       //文件只读
            IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE);
            if (vHandle == HFILE_ERROR)
            {
                CloseHandle(vHandle);
                return false;       //文件被占用
            }

            CloseHandle(vHandle);   //文件没被占用
            return true;
        }
        #endregion

        /// <summary>
        /// 获取指定文件夹下所有的文件名称
        /// </summary>
        /// <param name="folderName">指定文件夹名称,绝对路径</param>
        /// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param>
        /// <param name="isContainSubFolder">是否包含子文件夹</param>
        /// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
        public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false)
        {
            List<FileInfo> resList = new List<FileInfo>();
            try
            {
                DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录
                FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件
                foreach (FileInfo file in currFiles)
                {
                    if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0)
                    {
                        resList.Add(file);
                    }
                }
                if (isContainSubFolder)
                {
                    string[] subFolders = Directory.GetDirectories(folderName);
                    foreach (string subFolder in subFolders)
                    {
                        resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归   
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return resList;
        }

        /// <summary>
        /// 获取指定文件夹下所有的文件名称,不过滤文件类型
        /// </summary>
        /// <param name="folderName">指定文件夹名称,绝对路径</param>
        /// <param name="isContainSubFolder">是否包含子文件夹</param>
        /// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
        public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder)
        {
            return GetAllFilesByFolder(folderName, "*", isContainSubFolder);
        }
    }

    public class Compare<T, C> : IEqualityComparer<T>
    {
        private Func<T, C> _getField;
        public Compare(Func<T, C> getfield)
        {
            _getField = getfield;
        }
        public bool Equals(T x, T y)
        {
            return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));
        }
        public int GetHashCode(T obj)
        {
            return EqualityComparer<C>.Default.GetHashCode(_getField(obj));
        }
    }

    public static class ObjectExtensions
    {
        public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
        {
            return source.Distinct(new Compare<T, C>(getfield));
        }

        public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield)
        {
            return source.Distinct(new Compare<T, C>(getfield));
        }
    }
}