using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Net;
using System;
using System.Text;
using System.Net.Sockets;

namespace Mes.AutoUpdate
{
    public delegate void Action<T1, T2>(T1 _t1, T2 _t2);

    public static class DownManager
    {
        private static string main_progress = "";
        private static string sub_progress = "";
        private static int total_updated = 0;
        private static int total_files = 0;

        private static Action<string, string> _sProgress = null;

        public static void DownLoad(ArrayList files, string HTTP_Address, string FTP_Address, Action<int, int> m_Progress, Action<string, string> s_Progress, int retry, out ArrayList Finished)
        {
            string fileName = "";
            string errMsg = "";
            _sProgress = s_Progress;
            total_updated = 0;
            Finished = new ArrayList();
            total_files = files.Count;
            try
            {
                fileName = Process.GetCurrentProcess().MainModule.FileName;

                foreach (object file in files)
                {
                    if (m_Progress != null)
                        m_Progress(total_updated, files.Count);

                    string startupPath = Application.StartupPath;
                    string fileName2 = Path.GetFileName(file.ToString());
                    string text = startupPath + "\\" + fileName2;
                    if (Path.GetFullPath(text).ToUpper() == Path.GetFullPath(fileName).ToUpper())
                    {
                        total_updated++;
                    }
                    else
                    {
                        bool flag = false;
                        main_progress = fileName2;
                        for (int i = 0; i < retry; i++)
                        {
                            if (i > 0)
                            {
                                main_progress = string.Format("{0} 更新出错，尝试重新下载[{1}/2]", fileName2, i);
                                sub_progress = "";
                                inner_Progress(0, 1);
                                Thread.Sleep(1500);
                            }

                            if (HTTP_Helper.DownFile(Path.Combine(HTTP_Address, file.ToString()), text, out errMsg, inner_Progress))
                            {
                                flag = true;
                                Finished.Add(fileName2);
                                total_updated++;
                                break;
                            }
                        }
                        if (!flag)
                        {
                            for (int i = 0; i < retry; i++)
                            {
                                main_progress = string.Format("{0} 更新出错，按FTP方式重新下载[{1}/2]", fileName2, i + 1);
                                sub_progress = "";
                                inner_Progress(0, 1);
                                Thread.Sleep(100);

                                if (FTP_Helper.FtpDownload(Path.Combine(FTP_Address, file.ToString()), text, false, out errMsg, inner_Progress))
                                {
                                    flag = true;
                                    Finished.Add(fileName2);
                                    total_updated++;
                                    break;
                                }
                            }
                        }
                        if (!flag)
                        {
                            throw new Exception(errMsg);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }


        private static void inner_Progress(int a, int b)
        {
            sub_progress = string.Format("{0,4}/{1,-4} {2,3}% ", total_updated + 1, total_files, a * 100 / b);
            if (_sProgress != null)
            {
                _sProgress(sub_progress, main_progress);
            }
        }
    }

    public static class FTP_Helper
    {
        public static string FtpUserID = string.Empty;

        public static string FtpPassword = string.Empty;

        public static bool FtpDownload(string remoteFileName, string localFileName, bool ifCredential, out string errMsg, Action<int, int> updateProgress)
        {
            errMsg = "";
            Stream stream = null;
            FtpWebResponse ftpResponse = null;
            FileStream fileStream = null;
            try
            { 
                fileStream = new FileStream(localFileName, FileMode.Create);
                Uri requestUri = new Uri(remoteFileName);
                FtpWebRequest ftpWebRequest = (FtpWebRequest.Create(requestUri)) as FtpWebRequest;
                ftpWebRequest.UseBinary = true;
                FtpWebRequest ftpWebRequest2 = (FtpWebRequest.Create(requestUri)) as FtpWebRequest;
                ftpWebRequest2.UseBinary = true;
                ftpWebRequest2.KeepAlive = false; 
                if (ifCredential)
                {
                    ftpWebRequest.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                    ftpWebRequest2.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                }
                ftpWebRequest.Method = "SIZE";
                FtpWebResponse ftpWebResponse2 = (FtpWebResponse)ftpWebRequest.GetResponse(); 
                long contentLength = ftpWebResponse2.ContentLength;
                ftpWebResponse2.Close();
                ftpWebRequest2.Method = "RETR";
                ftpResponse = (FtpWebResponse)ftpWebRequest2.GetResponse();
                stream = ftpResponse.GetResponseStream();


                if (updateProgress != null)
                    updateProgress.Invoke(0, (int)contentLength);
                long num = 0L;
                int num2 = 2048;
                byte[] buffer = new byte[num2];
                for (int num3 = stream.Read(buffer, 0, num2); num3 > 0; num3 = stream.Read(buffer, 0, num2))
                {
                    num = num3 + num;
                    fileStream.Write(buffer, 0, num3);

                    if (updateProgress != null)
                        updateProgress.Invoke((int)num, (int)contentLength);
                }
                return true;
            }
            catch (Exception ex)
            { 
                errMsg = ex.Message;
            }
            finally
            {
                if (stream != null) stream.Close();
                if (fileStream != null) fileStream.Close();
                if (ftpResponse != null) ftpResponse.Close();
            }
            return false;
        }

        public static bool FtpBrokenDownload(string remoteFileName, string localFileName, bool ifCredential, long size, Action<int, int> updateProgress)
        {
            Stream stream = null;
            FtpWebResponse ftpWebResponse = null;
            FileStream fileStream = null;
            try
            {
                fileStream = new FileStream(localFileName, FileMode.Append);
                Uri requestUri = new Uri(remoteFileName);
                FtpWebRequest ftpWebRequest = (FtpWebRequest.Create(requestUri)) as FtpWebRequest;
                ftpWebRequest.UseBinary = true;
                ftpWebRequest.ContentOffset = size;
                FtpWebRequest ftpWebRequest2 = (FtpWebRequest.Create(requestUri)) as FtpWebRequest;
                ftpWebRequest2.UseBinary = true;
                ftpWebRequest2.KeepAlive = false;
                ftpWebRequest2.ContentOffset = size;
                if (ifCredential)
                {
                    ftpWebRequest.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                    ftpWebRequest2.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                }
                ftpWebRequest.Method = "SIZE";
                FtpWebResponse ftpWebResponse2 = (FtpWebResponse)ftpWebRequest.GetResponse();
                long contentLength = ftpWebResponse2.ContentLength;
                ftpWebResponse2.Close();
                ftpWebRequest2.Method = "RETR";
                ftpWebResponse = (FtpWebResponse)ftpWebRequest2.GetResponse();
                stream = ftpWebResponse.GetResponseStream();


                if (updateProgress != null)
                    updateProgress.Invoke(0, (int)contentLength);
                long num = 0L;
                int num2 = 2048;
                byte[] buffer = new byte[num2];
                for (int num3 = stream.Read(buffer, 0, num2); num3 > 0; num3 = stream.Read(buffer, 0, num2))
                {
                    num = num3 + num;
                    fileStream.Write(buffer, 0, num3);


                    if (updateProgress != null)
                        updateProgress.Invoke((int)num, (int)contentLength);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
            finally
            {
                if (stream != null) stream.Close();
                if (fileStream != null) fileStream.Close();
                if (ftpWebResponse != null) ftpWebResponse.Close();
            }
        }

        public static bool FtpDownload(string remoteFileName, string localFileName, bool ifCredential, bool brokenOpen, Action<int, int> updateProgress)
        {
            string errMsg = "";
            if (brokenOpen)
            {
                try
                {
                    long size = 0L;
                    if (File.Exists(localFileName))
                    {
                        using (FileStream fileStream = new FileStream(localFileName, FileMode.Open))
                        {
                            size = fileStream.Length;
                        }
                    }
                    return FtpBrokenDownload(remoteFileName, localFileName, ifCredential, size, updateProgress);
                }
                catch
                {
                    throw;
                }
            }
            return FtpDownload(remoteFileName, localFileName, ifCredential, out errMsg, updateProgress);
        }

        public static bool FtpUploadFile(string localFullPathName, string remotePath, Action<int, int> updateProgress)
        {
            Stream stream = null;
            FtpWebResponse ftpWebResponse = null;
            FileStream fileStream = null;
            try
            {
                FileInfo fileInfo = new FileInfo(localFullPathName);
                Uri requestUri = new Uri(remotePath);
                FtpWebRequest ftpWebRequest = (FtpWebRequest.Create(requestUri)) as FtpWebRequest;
                ftpWebRequest.KeepAlive = false;
                ftpWebRequest.UseBinary = true;
                ftpWebRequest.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                ftpWebRequest.Method = "STOR";
                ftpWebRequest.ContentLength = fileInfo.Length;
                ftpWebResponse = (ftpWebRequest.GetResponse() as FtpWebResponse);
                ftpWebRequest.ContentLength = fileInfo.Length;
                int num = 1024;
                byte[] buffer = new byte[num];
                fileStream = fileInfo.OpenRead();
                stream = ftpWebRequest.GetRequestStream();
                int num2 = fileStream.Read(buffer, 0, num);
                int t = (int)fileInfo.Length;

                if (updateProgress != null)
                    updateProgress.Invoke(0, t);
                int num3 = 0;
                while (num2 != 0)
                {
                    num3 = num2 + num3;
                    stream.Write(buffer, 0, num2);

                    if (updateProgress != null)
                        updateProgress.Invoke(num3, t);
                    num2 = fileStream.Read(buffer, 0, num);
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
            finally
            {
                if (stream != null) stream.Close();
                if (fileStream != null) fileStream.Close();
                if (ftpWebResponse != null) ftpWebResponse.Close();
            }
        }

        public static bool FtpUploadBroken(string localFullPath, string remoteFilepath, Action<int, int> updateProgress)
        {
            if (remoteFilepath == null)
            {
                remoteFilepath = "";
            }
            string empty = string.Empty;
            bool result = true;
            FileInfo fileInfo = new FileInfo(localFullPath);
            long length = fileInfo.Length;
            if (fileInfo.Name.IndexOf("#") == -1)
            {
                empty = RemoveSpaces(fileInfo.Name);
            }
            else
            {
                empty = fileInfo.Name.Replace("#", "＃");
                empty = RemoveSpaces(empty);
            }
            long fileSize = GetFileSize(empty, remoteFilepath);
            if (fileSize >= length)
            {
                return false;
            }
            long num = fileSize;

            if (updateProgress != null)
                updateProgress.Invoke((int)fileSize, (int)length);
            string uriString = (remoteFilepath.Length != 0) ? (remoteFilepath + "/" + remoteFilepath + "/" + empty) : (remoteFilepath + "/" + empty);
            FtpWebRequest ftpWebRequest = (FtpWebRequest.Create(new Uri(uriString))) as FtpWebRequest;
            ftpWebRequest.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
            ftpWebRequest.KeepAlive = false;
            ftpWebRequest.Method = "APPE";
            ftpWebRequest.UseBinary = true;
            ftpWebRequest.ContentLength = fileInfo.Length;
            int num2 = 2048;
            byte[] buffer = new byte[num2];
            FileStream fileStream = fileInfo.OpenRead();
            Stream stream = null;
            try
            {
                stream = ftpWebRequest.GetRequestStream();
                fileStream.Seek(fileSize, SeekOrigin.Begin);
                int num3 = fileStream.Read(buffer, 0, num2);
                while (num3 != 0)
                {
                    stream.Write(buffer, 0, num3);
                    num3 = fileStream.Read(buffer, 0, num2);
                    num += num3;
                    if (updateProgress != null)
                        updateProgress.Invoke((int)num, (int)length);
                }
            }
            catch
            {
                result = false;
                throw;
            }
            finally
            {
                if (stream != null) stream.Close();
                if (fileStream != null) fileStream.Close();
            }
            return result;
        }

        private static string RemoveSpaces(string str)
        {
            string text = "";
            CharEnumerator enumerator = str.GetEnumerator();
            while (enumerator.MoveNext())
            {
                byte[] array = new byte[1];
                array = Encoding.ASCII.GetBytes(enumerator.Current.ToString());
                int num = array[0];
                if (num != 32)
                {
                    text += enumerator.Current.ToString();
                }
            }
            string text2 = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + DateTime.Now.Millisecond.ToString();
            return text.Split('.')[text.Split('.').Length - 2] + "." + text.Split('.')[text.Split('.').Length - 1];
        }

        public static long GetFileSize(string filename, string remoteFilepath)
        {
            try
            {
                if (remoteFilepath.Length == 0)
                {
                    return 0L;
                }
                FtpWebRequest ftpWebRequest = (FtpWebRequest.Create(remoteFilepath)) as FtpWebRequest;
                ftpWebRequest.KeepAlive = false;
                ftpWebRequest.UseBinary = true;
                ftpWebRequest.Credentials = new NetworkCredential(FtpUserID, FtpPassword);
                ftpWebRequest.Method = "SIZE";
                FtpWebResponse ftpWebResponse = (FtpWebResponse)ftpWebRequest.GetResponse();
                return ftpWebResponse.ContentLength;
            }
            catch
            {
                return 0L;
            }
        }
    }

    public static class HTTP_Helper
    {
        public static bool DownFile(string URLAddress, string LocalAddress, out string errMsg, Action<int, int> updateProgress)
        {
            errMsg = "";
            FileStream fileStream = null;
            Stream stream = null;
            bool result = false;
            try
            {
                string startupPath = Application.StartupPath;
                string fileName = Path.GetFileName(URLAddress);
                string path = startupPath + "\\" + fileName;
                string fileName2 = Process.GetCurrentProcess().MainModule.FileName;
                if (Path.GetFullPath(path).ToUpper() == Path.GetFullPath(fileName2).ToUpper())
                {
                    return true;
                }
                fileStream = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None);
                WebClient webClient = new WebClient();
                stream = webClient.OpenRead(URLAddress);
                int t = Convert.ToInt32(webClient.ResponseHeaders["Content-Length"]);
                byte[] array = new byte[10240];
                int count = array.Length;
                int num = 0;
                int num2 = 0;
                do
                {
                    num = stream.Read(array, 0, count);
                    num2 += num;
                    if (num != 0)
                    {
                        fileStream.Write(array, 0, num);
                    }
                    if (updateProgress != null)
                        updateProgress.Invoke(num2, t);
                }
                while (num != 0);
                fileStream.Flush();
                result = true;
                return result;
            }
            catch (Exception ex)
            {
                errMsg = ex.Message;
            }
            finally
            {
                if (fileStream != null) fileStream.Close();
                if (stream != null) stream.Dispose();
            }
            return result;
        }
    }


}