using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Collections;
using System.Xml.Linq;
using System.Reflection;
namespace AIMSAutoUpdate
{
    /// 
    /// ftp下载类
    /// 
    public class FTPTransmission
    {
        /// 
        /// 记录所有要下载的文件路径及下载到本地的路径
        /// 
        public static List ListFileDirectory = new List();
        /// 
        /// 记录当前文件路径及下载到本地的路径
        /// 
        public static List nowListFileDirectory = new List();
        /// 
        /// 记录要下载的文件路径及下载到本地的路径
        /// 
        public struct ftpFileDirectory
        {
            /// 
            /// 要下载的文件路径
            /// 
            public string ftpPath;
            /// 
            /// 下载到本地的路径
            /// 
            public string localPath;
            /// 
            /// 文件名
            /// 
            public string filename;
            /// 
            /// 文件大小
            /// 
            public long filelength;
            /// 
            /// MD5码
            /// 
            public string MD5Hash;
        }
        /// 
        /// 设置ftp服务器的命令,并获取文件和文件夹,以及文件夹内的子文件
        /// 
        /// FTP地址路径
        /// 要发送到FTP服务器的命令
        /// 用户名
        /// 密码
        /// 
        public static string[] ftp(string ftpads, string type, string username, string password, string encoding)
        {
            WebResponse webresp = null;
            StreamReader ftpFileListReader = null;
            FtpWebRequest ftpRequest = null;
            try
            {
                ftpRequest = (FtpWebRequest)WebRequest.Create(new Uri(ftpads));
                ftpRequest.Method = type;
                 ftpRequest.UsePassive = false;//只需要添加这一句话
                ftpRequest.Credentials = new NetworkCredential(username,
                                                          password);
                webresp = ftpRequest.GetResponse();
                if (encoding == "Default")
                {
                    ftpFileListReader = new StreamReader(webresp.GetResponseStream(), Encoding.Default);
                }
                else
                {
                    ftpFileListReader = new StreamReader(webresp.GetResponseStream(), Encoding.UTF8);
                }
                StringBuilder str = new StringBuilder();
                string line = ftpFileListReader.ReadLine();
                while (line != null)
                {
                    str.Append(line);
                    str.Append("\n");
                    line = ftpFileListReader.ReadLine();
                }
                string[] fen = str.ToString().Split('\n');
                return fen;
            }
            catch (Exception  )
            {
                MessageBox.Show("更新失败! 请检查网络或者FTP用户名与口令!");
                Environment.Exit(0);
                return null;
            }
        }
        /// 
        /// 递归实现获取ftp目录下所有文件及文件夹以及文件夹内的子文件
        /// 
        /// FTP路径
        /// 保存的本地路径
        /// 用户名
        /// 密码
        public static void downftp(string ftpads, string downloadDir, string username, string password, Hashtable htUpdateFile, string encoding)
        {
            try
            {
                downloadDir = downloadDir.Replace("\\\\", "\\");
                string ftpdir = ftpads;
                string[] fullname = ftp(ftpads, WebRequestMethods.Ftp.ListDirectoryDetails, username, password, encoding);
                if (fullname == null) return;
                string[] onlyname = ftp(ftpads, WebRequestMethods.Ftp.ListDirectory, username, password, encoding);
                if (onlyname == null) return;
                if (!Directory.Exists(downloadDir))
                {
                    Directory.CreateDirectory(downloadDir);
                }
                foreach (string names in fullname)
                {
                    //判断是否具有文件夹标识
                    if (names.Contains(""))
                    {
                        string olname = names.Split(new string[] { "" },
                        StringSplitOptions.None)[1].Trim();
                        downftp(ftpads + "/" + olname, downloadDir + "\\" + olname, username, password, htUpdateFile, encoding);
                    }
                    else
                    {
                        foreach (string onlynames in onlyname)
                        {
                            if (string.IsNullOrEmpty(onlynames.Trim()) || string.IsNullOrEmpty(names.Trim())) break;
                            if (names.Contains(" " + onlynames))
                            {
                                //download(downloadDir + "\\" + onlynames, ftpads + "/" + onlynames, username, password);
                                var fd = new ftpFileDirectory();
                                fd.ftpPath = ftpads + "/" + onlynames.ToString();
                                fd.localPath = downloadDir + "\\" + onlynames.ToString();
                                fd.localPath = fd.localPath.Replace("\\\\", "\\");
                                fd.filename = onlynames.ToString();
                                fd.filelength = GetFileSize(fd.ftpPath, username, password);
                                for (int i = 0; i < htUpdateFile.Count; i++)
                                {
                                    string[] fileArray = (string[])htUpdateFile[i];
                                    if (fd.filename == fileArray[0])
                                    {
                                        fd.MD5Hash = fileArray[1];
                                        break;
                                    }
                                }
                                ListFileDirectory.Add(fd);
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("获取目录失败+downftp" + ex.ToString());
                Environment.Exit(0);
            }
        }
        /// 
        /// 递归实现获取ftp目录下所有文件及文件夹以及文件夹内的子文件
        /// 
        /// FTP路径
        /// 保存的本地路径
        /// 用户名
        /// 密码
        public static void downNow(string ftpads)
        {
            try
            {
                DirectoryInfo theFolder = new DirectoryInfo(ftpads);
                printAllFile(theFolder);
            }
            catch (Exception ex)
            {
                MessageBox.Show("获取目录失败+downftp" + ex.ToString());
                Environment.Exit(0);
            }
        }
        public static void printAllFile(DirectoryInfo di)
        {
            FileInfo[] fiArray = di.GetFiles();
            DirectoryInfo[] diArray = di.GetDirectories();
            foreach (FileInfo NextFile in fiArray)
            {
                if (NextFile.Name.Contains("AIMSAutoUpdate") || NextFile.Name.Contains("AIMS")) continue;
                var fd = new ftpFileDirectory();
                fd.ftpPath = NextFile.DirectoryName + "\\" + NextFile.Name.ToString();
                fd.filename = NextFile.Name.ToString();
                fd.filelength = NextFile.Length;
                fd.MD5Hash = GetMD5HashFromFile(fd.ftpPath);
                nowListFileDirectory.Add(fd);
            }
            foreach (DirectoryInfo inst in diArray)
            {
                printAllFile(inst);
            }
        }
        /// 
        /// 单个文件下载
        /// 
        /// 保存文件的本地路径
        /// 下载文件的FTP路径
        /// 用户名
        /// 密码
        public static void download(string adss, string ftpadss, string username, string password)
        {
            //FileMode常数确定如何打开或创建文件,指定操作系统应创建新文件。
            //FileMode.Create如果文件已存在,它将被改写
            FileStream outputStream = new FileStream(adss, FileMode.Create);
            FtpWebRequest downRequest = (FtpWebRequest)WebRequest.Create(new Uri(ftpadss));
            downRequest.Credentials = new NetworkCredential(username, password);
            downRequest.UsePassive = false;//只需要添加这一句话
            //设置要发送到 FTP 服务器的命令
            downRequest.Method = WebRequestMethods.Ftp.DownloadFile;
            FtpWebResponse response = (FtpWebResponse)downRequest.GetResponse();
            Stream ftpStream = response.GetResponseStream();
            long cl = response.ContentLength;
            int bufferSize = 2048;
            int readCount;
            byte[] buffer = new byte[bufferSize];
            readCount = ftpStream.Read(buffer, 0, bufferSize);
            while (readCount > 0)
            {
                outputStream.Write(buffer, 0, readCount);
                readCount = ftpStream.Read(buffer, 0, bufferSize);
            }
            ftpStream.Close();
            outputStream.Close();
            response.Close();
        }
        /// 
        /// 获得文件大小
        /// 
        /// 
        /// 
        public static long GetFileSize(string ftpadss, string username, string password)
        {
            long fileSize = 0;
            try
            {
                FtpWebRequest downRequest = (FtpWebRequest)WebRequest.Create(new Uri(ftpadss));
                downRequest.Credentials = new NetworkCredential(username, password);
                downRequest.Method = WebRequestMethods.Ftp.GetFileSize;
                 downRequest.UsePassive = false;//只需要添加这一句话
                FtpWebResponse response = (FtpWebResponse)downRequest.GetResponse();
                fileSize = response.ContentLength;
                response.Close();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
            return fileSize;
        }
        ///   
        /// FTP获取文件的MD5码  
        ///   
        /// 传入的文件名(含路径及后缀名)  
        ///   
        public static string FTPGetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, System.IO.FileMode.Open);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception)
            {
                return "";
                //throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
        ///   
        /// 获取文件的MD5码  
        ///   
        /// 传入的文件名(含路径及后缀名)  
        ///   
        public static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, System.IO.FileMode.Open);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception)
            {
                return "";
                //throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
        public static void UpdateListXML()
        {
            try
            {
                string localXmlFile = AppDomain.CurrentDomain.BaseDirectory + "\\UpdateList.xml";
                if (!File.Exists(localXmlFile))
                    return;
                XElement xe = XElement.Load(localXmlFile);
                //获取本地EXE版本号
                Assembly currentAssembly = Assembly.LoadFile(Application.ExecutablePath.Trim());
                AssemblyName CurrentAssemblyName = currentAssembly.GetName();
                string Version = CurrentAssemblyName.Version.ToString();
                Version vs = new Version(Version);
                Version newvs = new Version(xe.Element("Version").Value);
                if (vs.CompareTo(newvs) > 0)
                {
                    xe.Element("Version").Value = Version;
                    FTPTransmission.downNow(AppDomain.CurrentDomain.BaseDirectory);
                    IEnumerable element = from ex in xe.Elements("Files")
                                                    select ex;
                    ///删除指定的元素,并保存
                    if (element.Count() > 0)
                    {
                        element.Remove();
                    }
                    XElement record = new XElement("Files");
                    foreach (var item in FTPTransmission.nowListFileDirectory)
                    {
                        if (item.filename.Contains("AIMSAutoUpdate")) continue;
                        FTPTransmission.ftpFileDirectory f = item;
                        XElement file = new XElement(
                        new XElement("File",
                            //new XAttribute("Ver", Version),
                        new XAttribute("Name", item.filename),
                        new XAttribute("MD5Hash", item.MD5Hash)));
                        record.Add(file);
                    }
                    xe.Add(record);
                    xe.Save(localXmlFile);
                }
            }
            catch (Exception)
            {
                return;
            }
        }
        public static Encoding GetEncoding(string filePath)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException("filePath");
            }
            Encoding encoding1 = Encoding.Default;
            if (File.Exists(filePath))
            {
                try
                {
                    using (FileStream stream1 = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        if (stream1.Length > 0)
                        {
                            using (StreamReader reader1 = new StreamReader(stream1, true))
                            {
                                char[] chArray1 = new char[1];
                                reader1.Read(chArray1, 0, 1);
                                encoding1 = reader1.CurrentEncoding;
                                reader1.BaseStream.Position = 0;
                                if (encoding1 == Encoding.UTF8)
                                {
                                    byte[] buffer1 = encoding1.GetPreamble();
                                    if (stream1.Length >= buffer1.Length)
                                    {
                                        byte[] buffer2 = new byte[buffer1.Length];
                                        stream1.Read(buffer2, 0, buffer2.Length);
                                        for (int num1 = 0; num1 < buffer2.Length; num1++)
                                        {
                                            if (buffer2[num1] != buffer1[num1])
                                            {
                                                encoding1 = Encoding.Default;
                                                break;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        encoding1 = Encoding.Default;
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    throw;
                }
                if (encoding1 == null)
                {
                    encoding1 = Encoding.UTF8;
                }
            }
            return encoding1;
        }
    }
}