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

namespace SunnyTest
{
    /// <summary>
    /// Sunny公共方法
    /// </summary>
    public class SunnyPublic
    {
        static System.Func<int, int, int, string, string, string, int, bool> httpFunc = null;
        static System.Func<int, int, int, string, string, int, int, bool> wsFunc = null;
        static System.Func<string, string, int, int, IntPtr, int, int, int, bool> tcpFunc = null;
        static NetHttpCallback FuncCALL;

       /// <summary>
       /// 关闭IE代理 取消IE代理  如果要设置IE代理，要先启动后再调用此命令
       /// </summary>
       /// <param name="关闭IE代理"> 真=取消IE代理 假=设置IE代理 默认=真 如果为假 </param>
       public static void 关闭IE代理(bool 关闭IE代理 = true)
        {
            Sunny.SetIeProxy(关闭IE代理);
        }
        /// <summary>
        /// 不调用此方法或者证书管理器中无内容=使用自带的证书
        /// </summary>
        /// <param name="证书管理器"></param>
        public static void 导入自定义证书(CertificateManager 证书管理器)
        {
            Sunny.SetCa(证书管理器.获取证书Context());
        }



        /// <summary>
        /// 强制全部走TCP 真=强制走TCP 假=取消强制走TCP
        /// </summary>
        /// <param name="t"> 真强制走TCP 假=取消强制走TCP</param>
        public static void 强制全部走TCP(bool t)
        {
            Sunny.MustTcp(t);
        }


        /// <summary>
        /// 停止代理 停止的同时将会自动关闭IE代理
        /// </summary>
        public static void 停止代理()
        {
            Sunny.Stop();
            Sunny.SetIeProxy(true);
        }



        /// <summary>
        /// ws_取Body长度 ws、wss 取 接收/发送 的消息长度
        /// </summary>
        public static int ws_取Body长度(int MessageId)
        {
            return Sunny.GetWebsocketBodyLen(MessageId);
        }


        /// <summary>
        /// ws_取Body ws、wss 取 接收/发送 的消息
        /// </summary>
        public static byte[] ws_取Body(int MessageId)
        {
            IntPtr p = Sunny.GetWebsocketBody(MessageId);
            if (p.ToInt64() < 1)
            {
                return new byte[0];
            }
            return Tool.PtrToBytes(p, ws_取Body长度(MessageId));
        }


        /// <summary>
        /// ws_修改Body ws、wss 修改 接收/发送 的消息
        /// </summary>
        public static bool ws_修改Body(int MessageId, byte[] data)
        {
            IntPtr a = Tool.BytesToIntptr(data);
            bool p = Sunny.SetWebsocketBody(MessageId, a, data.Length);
            Tool.PtrFree(a);
            return p;
        }



        /// <summary>
        /// ws_发送Body ws、wss自动发送消息
        /// </summary>
        /// <param name="MessageId"></param>
        /// <param name="type">ws/wss 发送或接收的消息类型 请使用[ Const.WSClient_ ]</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool ws_发送Body(int MessageId, int type, byte[] data)
        {
            IntPtr a = Tool.BytesToIntptr(data);
            bool p = Sunny.SendWebsocketBody(MessageId, type, a, data.Length);
            Tool.PtrFree(a);
            return p;
        }




        /// <summary>
        /// Tcp_修改消息
        /// </summary>
        /// <param name="MessageId"></param>
        /// <param name="type">1=发送  2=接受 回调函数传递的 </param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static bool Tcp_修改消息(int MessageId, int type, byte[] data)
        {
            IntPtr a = Tool.BytesToIntptr(data);
            bool p = Sunny.SetTcpBody(MessageId, type, a, data.Length);
            Tool.PtrFree(a);
            return p;
        }




        /// <summary>
        /// Tcp_设置代理 给TCP请求设置S5代理。仅在TCP 即将连接时有效
        /// </summary>
        /// <param name="MessageId"></param>
        /// <param name="ip"></param>
        /// <param name="user"></param>
        /// <param name="pass"></param>
        /// <returns></returns>
        public static bool Tcp_设置代理(int MessageId, string ip, string user = "", string pass = "")
        {
            IntPtr a = Tool.StringToIntptr(ip);
            IntPtr b = Tool.StringToIntptr(user);
            IntPtr c = Tool.StringToIntptr(pass);
            bool p = Sunny.SetTcpAgent(MessageId, a, b, c);
            Tool.PtrFree(a);
            Tool.PtrFree(b);
            Tool.PtrFree(c);
            return p;
        }


        /// <summary>
        /// Tcp_断开指定连接 断开指定连接
        /// </summary>
        /// <param name="唯一ID"></param>
        /// <returns></returns>
        public static bool Tcp_断开指定连接(int 唯一ID)
        {
            bool p = Sunny.TcpCloseClient(唯一ID);
            return p;
        }




        /// <summary>
        /// Tcp_取数据 
        /// </summary>
        /// <param name="数据指针">回调中的 参数</param>
        /// <param name="数据长度">回调中的 参数</param>
        /// <returns></returns>
        public static byte[] Tcp_取数据(IntPtr 数据指针, int 数据长度)
        {
            return Tool.PtrToBytes(数据指针, 数据长度);
        }





        /// <summary>
        /// Tcp_连接重定向 
        /// </summary>
        /// <param name="MessageId">回调中的 参数</param>
        /// <param name="新IP"></param>
        /// <returns></returns>
        public static bool Tcp_连接重定向(int MessageId, string 新IP)
        {
            IntPtr a = Tool.StringToIntptr(新IP);
            bool b = Sunny.SetTcpConnectionIP(MessageId, a);
            Tool.PtrFree(a);
            return b;
        }




        /// <summary>
        /// Tcp_向服务器发送消息 返回发送成功的字节数
        /// </summary>
        /// <param name="MessageId">回调中的 参数</param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static int Tcp_向服务器发送消息(int MessageId, byte[] msg)
        {
            IntPtr a = Tool.BytesToIntptr(msg);
            int b = Sunny.TcpSendMsg(MessageId, a, msg.Length);
            Tool.PtrFree(a);
            return b;
        }



        /// <summary>
        /// Tcp_向客户端发送消息 返回发送成功的字节数
        /// </summary>
        /// <param name="MessageId">回调中的 参数</param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static int Tcp_向客户端发送消息(int MessageId, byte[] msg)
        {
            IntPtr a = Tool.BytesToIntptr(msg);
            int b = Sunny.TcpSendMsgClient(MessageId, a, msg.Length);
            Tool.PtrFree(a);
            return b;
        }



        /// <summary>
        /// 启动进程代理   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static bool 启动进程代理()
        {
            if (Sunny.StartProcess())
            {
                Sunny.ProcessStart();
                return true;
            }
            return false;
        }



        /// <summary>
        /// 进程代理_添加PID   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static bool 进程代理_添加PID(int pid)
        {
            return Sunny.ProcessAddPID(pid);
        }




        /// <summary>
        /// 进程代理_删除PID   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static bool 进程代理_删除PID(int pid)
        {
            return Sunny.ProcessDelPID(pid);
        }


        /// <summary>
        /// 进程代理_删除全部PID   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static bool 进程代理_删除全部PID()
        {
            return Sunny.ProcessCancelAll();
        }







        /// <summary>
        /// Br解压缩   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static byte[] Br解压缩(byte[] data)
        {
            IntPtr a = Tool.BytesToIntptr(data);
            IntPtr p = Sunny.BrUnCompress(a, data.Length);
            if (p.ToInt64() < 1)
            {
                Tool.PtrFree(a);
                return new byte[0];
            }
            IntPtr b = Tool.BytesToIntptr(Tool.PtrToBytes(p, 8, 0));
            int i = Sunny.BytesToInt(b, 8);
            byte[] s = Tool.PtrToBytes(p, i, 8);
            Tool.PtrFree(b);
            Tool.PtrFree(a);
            Sunny.Cfree(p);
            return s;
        }



        /// <summary>
        /// Gzip解压缩   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static byte[] Gzip解压缩(byte[] data)
        {
            IntPtr a = Tool.BytesToIntptr(data);
            IntPtr p = Sunny.GzipUnCompress(a, data.Length);
            if (p.ToInt64() < 1)
            {
                Tool.PtrFree(a);
                return new byte[0];
            }
            IntPtr b = Tool.BytesToIntptr(Tool.PtrToBytes(p, 8, 0));
            int i = Sunny.BytesToInt(b, 8);
            byte[] s = Tool.PtrToBytes(p, i, 8);
            Tool.PtrFree(b);
            Tool.PtrFree(a);
            Sunny.Cfree(p);
            return s;
        }




        /// <summary>
        /// Deflate解压缩   在 中间件 启动之后执行 [仅Windows有效]
        /// </summary>
        /// <returns></returns>
        public static byte[] Deflate解压缩(byte[] data)
        {
            IntPtr a = Tool.BytesToIntptr(data);
            IntPtr p = Sunny.DeflateUnCompress(a, data.Length);
            if (p.ToInt64() < 1)
            {
                Tool.PtrFree(a);
                return new byte[0];
            }
            IntPtr b = Tool.BytesToIntptr(Tool.PtrToBytes(p, 8, 0));
            int i = Sunny.BytesToInt(b, 8);
            byte[] s = Tool.PtrToBytes(p, i, 8);
            Tool.PtrFree(b);
            Tool.PtrFree(a);
            Sunny.Cfree(p);
            return s;
        }





        /// <summary>
        /// 载入P12证书
        /// </summary>
        /// <param name="域名">只能是顶级域名*.baidu.com</param>
        /// <param name="p12证书路径"></param>
        /// <param name="证书密码"></param>
        /// <param name="规则">0=仅解析使用 1=仅发送使用 其他值为解析及发送都使用</param>
        /// <returns></returns>
        public static bool 载入P12证书(string 域名, string p12证书路径, string 证书密码, int 规则)
        {
            IntPtr a = Tool.StringToIntptr(域名);
            IntPtr b = Tool.StringToIntptr(p12证书路径);
            IntPtr c = Tool.StringToIntptr(证书密码);
            bool p = Sunny.AddP12Certificate(a, b, c, 规则);
            Tool.PtrFree(a);
            Tool.PtrFree(b);
            Tool.PtrFree(c);
            return p;
        }



        /// <summary>
        /// 执行脚本方法 自定义JS脚本
        /// </summary>
        /// <param name="类型"></param>
        /// <param name="参数"></param>
        /// <returns></returns>
        public static string 执行脚本方法(int 类型, string 参数)
        {
            IntPtr a = Tool.StringToIntptr(参数);
            IntPtr p = Sunny.ScriptCall(类型, a);
            if (p.ToInt64() < 1)
            {
                Tool.PtrFree(a);
                return "";
            }
            string s = Tool.PtrToString(p);
            Sunny.Cfree(p);
            Tool.PtrFree(a);
            return s;
        }



        /// <summary>
        /// 设置脚本代码 
        /// </summary>
        /// <param name="代码"></param>
        /// <returns></returns>
        public static void 设置脚本代码(string 代码)
        {
            IntPtr a = Tool.StringToIntptr(代码);
            Sunny.SetScript(a);
            Tool.PtrFree(a);
        }
         

        /// <summary>
        /// 设置自定义JS脚本日志回调函数 
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static void 设置自定义JS脚本日志回调函数(IntPtr address)
        {
            Sunny.SetScriptLogCallAddress(address);
        }
         


        /// <summary>
        /// 删除P12证书
        /// </summary>
        /// <param name="域名">只能是顶级域名*.baidu.com</param> 
        /// <returns></returns>
        public static void 删除P12证书(string 域名)
        {
            IntPtr a = Tool.StringToIntptr(域名);
            Sunny.DelP12Certificate(a);
            Tool.PtrFree(a);
        }

        /// <summary>
        /// Webp转Png 
        /// </summary>
        /// <param name="webp文件路径">例如：c:\123.webp</param>
        /// <param name="保存png文件路径">例如：c:\123.png</param>
        /// <returns></returns>
        public static bool Webp转Png(string webp文件路径, string 保存png文件路径)
        {
            IntPtr a = Tool.StringToIntptr(webp文件路径);
            IntPtr b = Tool.StringToIntptr(保存png文件路径);
            bool p = Sunny.WebpToPng(a, b);
            Tool.PtrFree(a);
            Tool.PtrFree(b);
            return p;
        }




        /// <summary>
        /// Webp转Jpg 
        /// </summary>
        /// <param name="webp文件路径">例如：c:\123.webp</param>
        /// <param name="保存png文件路径">例如：c:\123.jpg</param>
        /// <param name="质量">1-100 默认75</param>
        /// <returns></returns>
        public static bool Webp转Jpg(string webp文件路径, string 保存png文件路径, int 质量 = 75)
        {
            IntPtr a = Tool.StringToIntptr(webp文件路径);
            IntPtr b = Tool.StringToIntptr(保存png文件路径);
            bool p = Sunny.WebpToJpeg(a, b, 质量);
            Tool.PtrFree(a);
            Tool.PtrFree(b);
            return p;
        }





        /// <summary>
        /// Webp转Jpg_2 
        /// </summary>
        /// <param name="webp图片">文件内容</param>
        /// <param name="质量">1-100 默认75</param>
        /// <returns></returns>
        public static byte[] Webp转Jpg_2(byte[] webp图片, int 质量 = 75)
        {
            IntPtr a = Tool.BytesToIntptr(webp图片);
            IntPtr p = Sunny.WebpToJpegBytes(a, webp图片.Length, 质量);
            if (p.ToInt64() < 1)
            {
                Tool.PtrFree(a);
                return new byte[0];
            }
            IntPtr b = Tool.BytesToIntptr(Tool.PtrToBytes(p, 8, 0));
            int i = Sunny.BytesToInt(b, 8);
            byte[] s = Tool.PtrToBytes(p, i, 8);
            Tool.PtrFree(b);
            Tool.PtrFree(a);
            return s;
        }





        /// <summary>
        /// Webp转Png_2 
        /// </summary>
        /// <param name="webp图片">文件内容</param>
        /// <returns></returns>
        public static byte[] Webp转Png_2(byte[] webp图片)
        {
            IntPtr a = Tool.BytesToIntptr(webp图片);
            IntPtr p = Sunny.WebpToPngBytes(a, webp图片.Length);
            if (p.ToInt64() < 1)
            {
                Tool.PtrFree(a);
                return new byte[0];
            }
            IntPtr b = Tool.BytesToIntptr(Tool.PtrToBytes(p, 8, 0));
            int i = Sunny.BytesToInt(b, 8);
            byte[] s = Tool.PtrToBytes(p, i, 8);
            Tool.PtrFree(b);
            Tool.PtrFree(a);
            return s;
        }


        /// <summary>
        /// 设置上游代理 不懂?,请先了解上游代理的含义 
        /// </summary>
        /// <param name="代理地址">例如：127.0.0.1:8888 为空=取消</param>
        /// <param name="代理账号">没有的话允许空</param>
        /// <param name="代理密码">没有的话允许空</param>
        /// <param name="代理超时">单位：秒  默认60</param>
        /// <param name="上游代理类型">0=http  1=socks5  其他值没任何代码执行</param>
        public static void 设置上游代理(string 代理地址 = "", string 代理账号 = "", string 代理密码 = "", int 代理超时 = 60, int 上游代理类型 = 0)
        {
            IntPtr A = Tool.StringToIntptr(代理地址);
            IntPtr B = Tool.StringToIntptr(代理地址 + ":" + 代理密码);
            if (上游代理类型 == 0)
            {
                Sunny.SetIpProxy(A);
                if (代理账号 != "")
                {
                    Sunny.SetIpAuth(B);
                }
                Tool.PtrFree(A);
                Tool.PtrFree(B);
                Sunny.SetProxyTimeout(代理超时);
                return;
            }
            else if (上游代理类型 == 1)
            {
                IntPtr C = Tool.StringToIntptr("s5|" + 代理地址);
                Sunny.SetIpProxy(C);
                if (代理账号 != "")
                {
                    Sunny.SetIpAuth(B);
                }
                Tool.PtrFree(A);
                Tool.PtrFree(B);
                Tool.PtrFree(C);
                Sunny.SetProxyTimeout(代理超时);
            }
        }

        public static string 取错误信息()
        {
            IntPtr a = Sunny.Geterr();
            if (a.ToInt64() < 1)
            {
                return "";
            }
            string s = Tool.PtrToString(a);
            Tool.PtrFree(a);
            return s;
        }
        /// <summary>
        /// 启动 成功返回真 失败返回假 失败可调用取错误信息 获取错误内容
        /// </summary>
        /// <param name="代理端口"></param>
        /// <param name="回调函数_HTTP请求"></param>
        /// <param name="回调函数_WebSocket请求"></param>
        /// <param name="回调函数_TCP请求"></param>
        /// <param name="自动设置IE代理"></param>
        /// <returns></returns>
        public static bool 启动(int 代理端口, System.Func<int, int, int, string, string, string, int, bool> 回调函数_HTTP请求 = null, System.Func<int, int, int, string, string, int, int, bool> 回调函数_WebSocket请求 = null, System.Func<string, string, int, int, IntPtr, int, int, int, bool> 回调函数_TCP请求 = null, bool 自动设置IE代理 = false)
        {
            if (回调函数_TCP请求 != null)
            {
                tcpFunc = 回调函数_TCP请求;
                Sunny.OpenTcp(Marshal.GetFunctionPointerForDelegate(new NetTcpCallback(DefaultNetTcpCallback)));
            }
            else
            { 
                Sunny.OpenTcp((IntPtr)(0));
            }
            httpFunc = 回调函数_HTTP请求;
            wsFunc = 回调函数_WebSocket请求;
            FuncCALL = new NetHttpCallback(DefaultNetHttpCallback);
            return Sunny.PInit(代理端口, Marshal.GetFunctionPointerForDelegate(FuncCALL), true, 自动设置IE代理);
        }

        private delegate void NetTcpCallback(IntPtr _来源地址, IntPtr _远程地址, int _消息类型, int _MessageId, IntPtr _数据指针, int _数据长度, int _唯一ID, int pid);
        private static void DefaultNetTcpCallback(IntPtr _来源地址, IntPtr _远程地址, int _消息类型, int _MessageId, IntPtr _数据指针, int _数据长度, int _唯一ID, int pid)
        {
            if (tcpFunc != null)
            {
                tcpFunc(Tool.PtrToString(_来源地址), Tool.PtrToString(_远程地址), _消息类型, _MessageId, _数据指针, _数据长度, _唯一ID, pid);
            }

        } 
        private delegate void NetHttpCallback(int _MessageId, int _Type, IntPtr _ptr_mod, IntPtr _ptr_Url, int _唯一ID, int 已弃用_允许过滤_已弃用, IntPtr _err, int pid, int WsMsgType);
        private static void DefaultNetHttpCallback(int _MessageId, int _Type, IntPtr _ptr_mod, IntPtr _ptr_Url, int _唯一ID, int 已弃用_允许过滤_已弃用, IntPtr _err, int pid, int WsMsgType)
        {
            if (_Type == Const.Net_Http_Request || _Type == Const.Net_Http_Response)
            {
                if (httpFunc != null)
                {
                    if (已弃用_允许过滤_已弃用 == 1)
                    {
                        return;
                    }
                    httpFunc(_唯一ID, _MessageId, _Type, Tool.PtrToString(_ptr_mod), Tool.PtrToString(_ptr_Url), "", pid);
                }
            }
            else if (_Type == Const.Net_Http_Request_Fail)
            {
                if (httpFunc != null)
                {
                    httpFunc(_唯一ID, _MessageId, _Type, Tool.PtrToString(_ptr_mod), Tool.PtrToString(_ptr_Url), Tool.PtrToString(_err), pid);
                }
            }
            else if (wsFunc != null)
            {
                wsFunc(_唯一ID, _MessageId, _Type, Tool.PtrToString(_ptr_mod), Tool.PtrToString(_ptr_Url), pid, WsMsgType);
            }
        }

    }
}
