using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Web;
using Com.Bocom.OpenApi.Security.Crypt;

namespace Com.Bocom.OpenApi
{
    namespace Utils
    {
        public class WebUtils
        {
            private static readonly string DefaultUserAgent =
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

            public static string GetHttpResponseStr(string url, Dictionary<string, string> parameters, string charset)
            {
                HttpWebRequest request;
                string urlStr = BuildGetUrl(url, parameters, charset);
                //HTTPSQ请求:既支持http请求也支持https请求      
                request = WebRequest.Create(urlStr) as HttpWebRequest;
                //HttpVersion.Version10:defines a version instance for http 1.0
                //HttpVersion.Version11:defines a version instance for http 1.1，用1.1报网络异常、不通。
                request.ProtocolVersion = HttpVersion.Version10;
                request.Method = "GET";
                request.Timeout = 8000;
                request.ReadWriteTimeout = 30000;
                var response = request.GetResponse() as HttpWebResponse;
                var responseString = string.Empty;
                var httpStatusCode = (int) response.StatusCode;
                if (httpStatusCode == 200)
                {
                    responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
                    return responseString;
                }

                throw new Exception("response status code is not valid. status code: " + httpStatusCode);
            }

            public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary<string, string> parameters,
                string charset)
            {
                HttpWebRequest request;
                //验证服务器加载回调自动验证
                //ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
                TrustAllCertificatePolicy.SetCertificatePolicy();
                ServicePointManager.SecurityProtocol =
                    SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

                ServicePointManager.Expect100Continue = true;

                //HTTPSQ请求:既支持http请求也支持https请求            
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version11;
                request.Method = "POST";
                request.Timeout = 8000;
                request.ReadWriteTimeout = 30000;
                request.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
                request.UserAgent = DefaultUserAgent;


                Encoding encode = Encoding.GetEncoding(charset);
                //如果需要POST数据   
                if (!(parameters == null || parameters.Count == 0))
                {
                    StringBuilder buffer = new StringBuilder();
                    int i = 0;
                    foreach (string key in parameters.Keys)
                    {
                        if (parameters[key] == null || parameters[key].Equals(""))
                        {
                            continue;
                        }

                        if (i > 0)
                        {
                            buffer.AppendFormat("&{0}={1}", key,
                                HttpUtility.UrlEncode(parameters[key], Encoding.GetEncoding(charset)));
                        }
                        else
                        {
                            buffer.AppendFormat("{0}={1}", key,
                                HttpUtility.UrlEncode(parameters[key], Encoding.GetEncoding(charset)));
                        }

                        i++;
                    }

                    //如果用户输入带加号的参数值，需要转义
                    byte[] data = encode.GetBytes(buffer.ToString()); //.Replace("+","%2B"));
                    using (Stream stream = request.GetRequestStream())
                    {
                        stream.Write(data, 0, data.Length);
                    }
                }

                return request.GetResponse() as HttpWebResponse;
            }


            //upload file
            public static HttpWebResponse CreatePostUploadFileHttpResponse(string url,
                IDictionary<string, string> parameters, string charset, FileItem f)
            {
                HttpWebRequest request;
                //验证服务器加载回调自动验证
                //ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
                TrustAllCertificatePolicy.SetCertificatePolicy();
                System.Net.ServicePointManager.SecurityProtocol =
                    SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

                ServicePointManager.Expect100Continue = true;

                //HTTPSQ请求:既支持http请求也支持https请求            
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version11; // http1.1
                request.Method = "POST";
                request.Timeout = 8000;
                request.ReadWriteTimeout = 30000;
                // request.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
                string boundary = "----" + DateTime.Now.Ticks.ToString("x");
                request.ContentType = "multipart/form-data;boundary=" + boundary + ";charset=" + charset;
                request.UserAgent = DefaultUserAgent;


                //    string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
                Stream stream = request.GetRequestStream();
                byte[] entryBoundaryBytes = Encoding.GetEncoding(charset).GetBytes(("\r\n--" + boundary + "\r\n"));
                //如果需要POST数据   
                if (!(parameters == null || parameters.Count == 0))
                {
                    foreach (string key in parameters.Keys)
                    {
                        if (parameters[key] == null || parameters[key].Equals(""))
                        {
                            continue;
                        }

                        byte[] data = GetTextEntry(key, parameters[key], charset);
                        stream.Write(entryBoundaryBytes, 0, entryBoundaryBytes.Length);
                        stream.Write(data, 0, data.Length);
                    }
                }

                using (var fileStream = FileToStream(f))
                {
                    string fileName = f.GetFileName();
                    //  var formdata = string.Format(formdataTemplate, "", System.IO.Path.GetFileName(fileName) /*Path.GetFileName(fileName)*/);
                    //  var formdataBytes = Encoding.UTF8.GetBytes(stream.Length == 0 ? formdata.Substring(2, formdata.Length - 2) : formdata);//第一行不需要换行
                    //   stream.Write(formdataBytes, 0, formdataBytes.Length);
                    byte[] fileBytes = GetFileEntry(BocomConstants.FILE_CONTENT, f.GetFileName(), f.GetMimeType(),
                        charset);


                    //写入文件
                    //byte[] buffer = new byte[1024];
                    //  int bytesRead = 0;
                    //  while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    // {
                    stream.Write(entryBoundaryBytes, 0, entryBoundaryBytes.Length);
                    stream.Write(fileBytes, 0, fileBytes.Length);
                    byte[] fileContent = f.GetContent();
                    stream.Write(fileContent, 0, fileContent.Length);
                    // }
                    byte[] endBoundaryBytes = Encoding.GetEncoding(charset).GetBytes(("\r\n--" + boundary + "--\r\n"));
                    stream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
                    stream.Close();
                }

                return request.GetResponse() as HttpWebResponse;
            }

            private static byte[] GetTextEntry(string fieldName, string fieldValue, string charset)
            {
                StringBuilder entry = new StringBuilder();
                entry.Append("Content-Disposition:form-data;name=\"");
                entry.Append(fieldName);
                entry.Append("\"\r\nContent-Type:text/plain\r\n\r\n");
                entry.Append(fieldValue);
                //return entry.toString().getBytes(charset);
                return Encoding.GetEncoding(charset).GetBytes(entry.ToString());
            }

            private static byte[] GetFileEntry(string fieldName, string fileName, string mimeType, string charset)
            {
                StringBuilder entry = new StringBuilder();
                entry.Append("Content-Disposition:form-data;name=\"");
                entry.Append(fieldName);
                entry.Append("\";filename=\"");
                //    entry.Append(URLEncoder.encode(fileName, charset));
                entry.Append(HttpUtility.UrlEncode(fileName));
                entry.Append("\"\r\nContent-Type:");
                entry.Append(mimeType);
                entry.Append("\r\n\r\n");
                //return entry.toString().getBytes(charset);
                return Encoding.GetEncoding(charset).GetBytes(Convert.ToString(entry));
            }

            public static string GetResponseJson(string url, IDictionary<string, string> parameters, string charset)
            {
                HttpWebResponse response = CreatePostHttpResponse(url, parameters, charset);
                var httpStatusCode = (int) response.StatusCode;
                if (httpStatusCode == 200)
                {
                    Stream stream = response.GetResponseStream();
                    StreamReader streamReader = new StreamReader(stream);
                    string responseStr = streamReader.ReadToEnd();
                    Console.WriteLine(responseStr);
                    return responseStr;
                }

                throw new Exception("response status code is not valid. status code: " + httpStatusCode);
            }

            //upload file 
            public static string GetResponseJson(string url, IDictionary<string, string> parameters, string charset,
                FileItem f)
            {
                HttpWebResponse response = CreatePostUploadFileHttpResponse(url, parameters, charset, f);
                var httpStatusCode = (int) response.StatusCode;
                if (httpStatusCode == 200)
                {
                    Stream stream = response.GetResponseStream();
                    StreamReader streamReader = new StreamReader(stream);
                    string responseStr = streamReader.ReadToEnd();
                    Console.WriteLine(responseStr);
                    return responseStr;
                }

                throw new Exception("response status code is not valid. status code: " + httpStatusCode);
            }

            //download file 加密
            public static string GetResponseJson(string url, IDictionary<string, string> parameters, string charset,
                string downloadPath, string encryptKey, string encryptType)
            {
                HttpWebResponse response = CreatePostHttpResponse(url, parameters, charset);
                var httpStatusCode = (int) response.StatusCode;
                if (httpStatusCode == 200)
                {
                    string responseStr = response.GetResponseHeader(BocomConstants.RESPONSE_BIZ_CONTENT);
                    string disposition = response.GetResponseHeader("Content-Disposition");
                    string fileName = HttpUtility.UrlEncode(disposition.Substring(disposition.IndexOf("filename=") + 9),
                        Encoding.GetEncoding(charset));
                    string filePath = downloadPath + fileName;
                    string tmpFilePath = filePath + ".tmp";
                    Stream stream = response.GetResponseStream();
                    WriteTmpFile(stream, tmpFilePath);
                    FileStream tmpStream = new FileStream(tmpFilePath, FileMode.OpenOrCreate);
                    byte[] text = AESCryptor.DecryptFile(tmpStream, encryptKey);
                    FileStream stream1 = new FileStream(filePath, FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(stream1);

                    bw.Write(text);
                    bw.Close();
                    stream1.Close();
                    File.Delete(tmpFilePath);
                    return responseStr;
                }

                throw new Exception("response status code is not valid. status code: " + httpStatusCode);
            }

            //download file 非加密
            public static string GetResponseJson(string url, IDictionary<string, string> parameters, string charset,
                string downloadPath)
            {
                HttpWebResponse response = CreatePostHttpResponse(url, parameters, charset);
                var httpStatusCode = (int) response.StatusCode;
                if (httpStatusCode == 200)
                {
                    string responseStr = response.GetResponseHeader(BocomConstants.RESPONSE_BIZ_CONTENT);
                    string disposition = response.GetResponseHeader("Content-Disposition");
                    string fileName = HttpUtility.UrlEncode(disposition.Substring(disposition.IndexOf("filename=") + 9),
                        Encoding.GetEncoding(charset));
                    string filePath = downloadPath + fileName;
                    Stream stream = response.GetResponseStream();
                    WriteTmpFile(stream, filePath);

                    return responseStr;
                }

                throw new Exception("response status code is not valid. status code: " + httpStatusCode);
            }

            //将从httpWebResponse中获取的文件流暂存于临时文件
            public static void WriteTmpFile(Stream stream, string tmpFilePath)
            {
                FileStream fs = new FileStream(tmpFilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                byte[] barr = new byte[1024];
                int iTotalSize = 0;
                int size = stream.Read(barr, 0, barr.Length);
                while (size > 0)
                {
                    iTotalSize += size;
                    fs.Write(barr, 0, size);
                    size = stream.Read(barr, 0, barr.Length);
                }

                fs.Close();
                stream.Close();
            }

            public static Stream GetStream(Stream fi)
            {
                Stream memortStream = new MemoryStream();
                byte[] bArr = new byte[1024];
                int size = fi.Read(bArr, 0, bArr.Length);
                while (size > 0)
                {
                    memortStream.Write(bArr, 0, size);
                    size = fi.Read(bArr, 0, bArr.Length);
                    //   Thread.Sleep(1);
                }

                fi.Close();


                return memortStream;
            }

            public static string BuildOrderedSignStr(string path, Dictionary<string, string> param)
            {
                Dictionary<string, string> tmp = new Dictionary<string, string>();
                tmp = param;
                var orderList = tmp.OrderBy(s => s.Key);
                StringBuilder sb = new StringBuilder(path);
                sb.Append("?");
                Boolean hasParam = false;
                foreach (var s in orderList)
                {
                    string name = s.Key;
                    string value = s.Value;
                    if (value == null || name == null || value.Equals(""))
                    {
                        continue;
                    }

                    if (hasParam)
                    {
                        sb.Append("&");
                    }
                    else
                    {
                        hasParam = true;
                    }

                    sb.Append(name).Append("=").Append(value);
                }

                return sb.ToString();
            }

            public static string BuildGetUrl(string strUrl, Dictionary<string, string> param, string charset)
            {
                if (param == null)
                {
                    return strUrl;
                }

                StringBuilder sb = new StringBuilder(strUrl);
                try
                {
                    if (new Uri(strUrl).Query == null || new Uri(strUrl).Query.Equals(""))
                    {
                        if (!strUrl.EndsWith("?"))
                        {
                            sb.Append('?');
                        }
                    }
                }
                catch (UriFormatException e)
                {
                    throw new Exception("url exception. url: " + strUrl, e);
                }

                Dictionary<string, string> tmp = new Dictionary<string, string>();
                tmp = param;
                Boolean hasParam = false;

                Boolean shouldAddAnd = strUrl.Contains("?") ? !strUrl.EndsWith("&") : false;

                foreach (var s in tmp)
                {
                    string name = s.Key;
                    string value = s.Value;
                    // 忽略参数名或参数值为空的参数

                    if (value == null || name == null || value.Equals(""))
                    {
                        continue;
                    }

                    if (hasParam)
                    {
                        sb.Append("&");
                    }
                    else
                    {
                        if (shouldAddAnd)
                        {
                            sb.Append("&");
                        }

                        hasParam = true;
                    }

                    sb.Append(name).Append("=").Append(HttpUtility.UrlEncode(value, Encoding.GetEncoding(charset)));
                }

                return sb.ToString();
            }

            public static string BuildForm(string baseUrl, Dictionary<string, string> parameters)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<form name=\"auto_submit_form\" method=\"post\" action=\"");
                sb.Append(baseUrl);
                sb.Append("\">\n");
                sb.Append(BuildHiddenFields(parameters));

                sb.Append("<input type=\"submit\" value=\"立刻提交\" style=\"display:none\" >\n");
                sb.Append("</form>\n");
                sb.Append("<script>document.forms[0].submit();</script>");
                string form = sb.ToString();
                return form;
            }

            private static string BuildHiddenFields(Dictionary<string, string> parameters)
            {
                if (parameters == null || parameters.Count == 0)
                {
                    return "";
                }

                StringBuilder sb = new StringBuilder();

                foreach (var s in parameters)
                {
                    string key = s.Key;
                    string value = s.Value;
                    // 除去参数中的空值
                    if (key == null || value == null)
                    {
                        continue;
                    }

                    sb.Append(BuildHiddenField(key, value));
                }

                string result = sb.ToString();
                return result;
            }

            private static string BuildHiddenField(string key, string value)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<input type=\"hidden\" name=\"");
                sb.Append(key);

                sb.Append("\" value=\"");
                // 转义双引号
                string a = value.Replace("\"", "&quot;");
                sb.Append(a).Append("\">\n");
                return sb.ToString();
            }

            public bool CheckValidationResult()
            {
                return true;
            }

            public static Stream FileToStream(FileItem f)
            {
                // 把 byte[] 转换成 Stream

                Stream stream = new MemoryStream(f.GetContent());

                return stream;
            }
        }
    }
}