using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace 常用工具集.Utility.Network
{

    public class FtpHelper
    {
        private string ip;
        private int port = 21;
        private string ftpUserId;
        private string ftpPassword;
        private Encoding encoding;
        private string FtpUrl
        {
            get
            {
                return $"ftp://{ip}:{port}/";
            }
        }


        public FtpHelper(string ip) : this(ip, 21) { }

        public FtpHelper(string ip, int port) : this(ip, 21, Encoding.GetEncoding("GB2312")) { }
        /// <summary>
        /// 匿名
        /// </summary>
        /// <param name="ip"></param>
        public FtpHelper(string ip, Encoding encoding) : this(ip, 21, encoding) { }

        public FtpHelper(string ip, int port, Encoding encoding) : this(ip, port, "anonymous", "", encoding) { }


        public FtpHelper(string ip, string userName, string password) : this(ip, 21, userName, password) { }

        public FtpHelper(string ip, int port, string userName, string password) : this(ip, port, userName, password, Encoding.UTF8) { }
        /// <summary>
        /// 指定用户名密码
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="userName"></param>
        /// <param name="password"></param>

        public FtpHelper(string ip, string userName, string password, Encoding encoding) : this(ip, 21, userName, password, encoding) { }

        /// <summary>
        /// 指定用户名密码
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="userName"></param>
        /// <param name="password"></param>

        public FtpHelper(string ip, int port, string userName, string password, Encoding encoding)
        {
            this.ip = ip;
            this.port = port;
            this.ftpUserId = userName;
            this.ftpPassword = password;
            this.encoding = encoding;
        }



        /// <summary>
        /// 获得文件的最后更新时间
        /// </summary>
        /// <param name="ftpPath"></param>
        /// <param name="ftpUserId"></param>
        /// <param name="ftpPassword"></param>
        /// <param name="relativeFilePath"></param>
        /// <returns></returns>
        public DateTime GetFileLastModified(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.UseBinary = true;
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                DateTime dt = response.LastModified;
                response.Close();
                response = null;
                request = null;
                return dt;
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.GetFileLastModified 获得文件的最后更新时间 错误");
                throw ex;
            }

        }

        /// <summary>
        /// 列出ftp目录下的所有文件
        /// </summary>
        /// <param name="ftpPath"></param>
        /// <param name="ftpUserId"></param>
        /// <param name="ftpPassword"></param>
        /// <returns></returns>
        public List<FtpFileInfo> GetList(string ftpPath)
        {
            List<string> fileList = GetFileDetail(ftpPath);
            List<FtpFileInfo> list = new List<FtpFileInfo>();
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                string str = encoding.GetString(stream.ToArray());
                foreach (string line in str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (line == "." || line == "..")
                        continue;
                    string detail = fileList.Where(it => it.EndsWith(line)).FirstOrDefault();
                    if (detail == null || detail.Length == 0)
                    {
                        continue;

                    }
                    if (detail.ToUpper().Contains("<DIR>") || detail.ToUpper().Contains("DR"))
                    {
                        list.Add(new FtpFileInfo { IsDirectory = true, Name = line });
                    }
                    else
                    {
                        list.Add(new FtpFileInfo { IsDirectory = false, Name = line });
                    }
                }
                return list.OrderByDescending(it => it.IsDirectory).ToList();
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.GetFile  列出ftp目录下的所有文件 错误");
                throw ex;
            }

        }

        public List<string> GetFileDetail(string ftpPath)
        {
            List<string> list = new List<string>();
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);

                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                string str = encoding.GetString(stream.ToArray());
                foreach (string line in str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    list.Add(line);
                }
                return list;
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.GetFile  列出ftp目录下的所有文件 错误");
                throw ex;
            }
        }

        /// <summary>
        /// 判断是否是文件
        /// </summary>
        /// <param name="ftpPath"></param>
        /// <param name="ftpUserId"></param>
        /// <param name="ftpPassword"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public bool IsFileExist(string ftpPath, string fileName)
        {
            List<FtpFileInfo> list = GetList(ftpPath);
            if (list.Any(it => !it.IsDirectory && it.Name == fileName))
            {
                return true;
            }
            return false;
        }


        #region 文件夹是否存在
        /// <summary>
        /// 文件夹是否存在
        /// </summary>
        /// <param name="ftpPath"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public bool FolderExists(string ftpPath, string folderName)
        {
            List<FtpFileInfo> list = GetList(ftpPath);
            if (list.Any(it => it.IsDirectory && it.Name == folderName))
            {
                return true;
            }
            return false;
        }
        #endregion

        #region 创建文件夹
        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="ftpPath">ftp路径</param> 
        /// <param name="folderName">文件夹名称</param>
        public bool CreateFolder(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "MKD";
                ((FtpWebResponse)request.GetResponse()).Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion

        #region 文件是否存在
        /// <summary>
        /// 文件是否存在
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public bool FileExists(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                string folderName = Path.GetDirectoryName(ftpPath);
                string fileName = Path.GetFileName(ftpPath);
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "LIST";
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                string str = encoding.GetString(stream.ToArray());
                foreach (string line in str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (!line.ToUpper().Contains("DIR") && !line.ToUpper().Contains("DR"))
                    {
                        int pos = line.LastIndexOf(" ");
                        string strFileName = line.Substring(pos).Trim();
                        if (strFileName == fileName)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.FileExists 判断文件是否存在 错误");
                throw ex;
            }

            return false;
        }
        #endregion

        #region 下载文件
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public MemoryStream DownloadFile(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "RETR";
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();


                return stream;
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.DownloadFile 下载文件 错误");
                throw ex;
            }
        }


        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public void DownloadFile(string ftpPath, string localFile)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "RETR";
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                FileStream stream = new FileStream(localFile, FileMode.OpenOrCreate, FileAccess.Write);
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();
                stream.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.DownloadFile 下载文件 错误");
                throw ex;
            }
        }
        #endregion

        #region 异步下载文件
        /// <summary>
        /// 异步下载文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param> 
        public async Task<MemoryStream> DownloadFileAsync(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "RETR";
                FtpWebResponse response = (FtpWebResponse)(await request.GetResponseAsync());
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = await responseStream.ReadAsync(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = await responseStream.ReadAsync(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                return stream;
            }
            catch (Exception ex)
            {
                Console.WriteLine("FtpUtil.DownloadFileAsync 异步下载文件 错误");
                throw ex;
            }
        }
        #endregion

        #region 上传文件
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param> 
        /// <param name="relativeFilePath">文件相对路径</param>
        /// <param name="bArr">文件内容</param>
        public bool UploadFile(string ftpPath, byte[] bArr)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "STOR";
                Stream postStream = request.GetRequestStream();
                int pageSize = 1024 * 1024;
                int index = 0;
                while (index < bArr.Length)
                {
                    if (bArr.Length - index > pageSize)
                    {
                        postStream.Write(bArr, index, pageSize);
                        index += pageSize;
                    }
                    else
                    {
                        postStream.Write(bArr, index, bArr.Length - index);
                        index = index + (bArr.Length - index);
                    }
                }
                postStream.Close();
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader sr = new StreamReader(responseStream, Encoding.UTF8);
                string result = sr.ReadToEnd();
                responseStream.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="localFilePath">本地文件</param>
        /// <param name="ftpPath">远端路径</param>
        /// <returns></returns>
        public bool UploadFile(string localFilePath, string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                byte[] bytes = new byte[1024 * 1024];
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "STOR";

                FileStream stream = new FileStream(localFilePath, FileMode.Open);

                Stream postStream = request.GetRequestStream();
                while (true)
                {
                    int count = stream.Read(bytes, 0, bytes.Length);
                    if (count == 0)
                        break;
                    postStream.Write(bytes, 0, count);
                }
                postStream.Close();
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader sr = new StreamReader(responseStream, Encoding.UTF8);
                string result = sr.ReadToEnd();
                responseStream.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion

        #region 删除文件
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public bool DeleteFile(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = WebRequestMethods.Ftp.DeleteFile;
                ((FtpWebResponse)request.GetResponse()).Close();
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool Rename(string ftpPath, string newName)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = WebRequestMethods.Ftp.Rename;
                request.RenameTo = newName;
                ((FtpWebResponse)request.GetResponse()).Close();
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public bool DeleteDirectory(string ftpPath)
        {
            try
            {
                string url = Uri.EscapeUriString(FtpUrl + ftpPath);
                if (ftpPath.EndsWith("/"))
                    ftpPath = ftpPath.Substring(0, ftpPath.Length - 1);
                FtpWebRequest request = null;
                request = (FtpWebRequest)WebRequest.Create(new Uri(url));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = WebRequestMethods.Ftp.RemoveDirectory;
                ((FtpWebResponse)request.GetResponse()).Close();
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion
    }


    public class FtpFileInfo
    {
        public bool IsDirectory { get; set; }
        public string Name { get; set; }
    }
}
