using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace MES.Utility.Core
{
    public static class ZipHelper
    {
        /// <summary>
        /// 压缩
        /// </summary> 
        /// <param name="filename"> 压缩后的文件名(包含物理路径)</param>
        /// <param name="directory">待压缩的文件夹(包含物理路径)</param>
        //public static void PackFiles(string filename, string directory)
        //{
        //    try
        //    {
        //        FastZip fz = new FastZip();
        //        fz.CreateEmptyDirectories = true;
        //        fz.CreateZip(filename, directory, true, "");
        //        fz = null;
        //    }
        //    catch (Exception)
        //    {
        //        throw;
        //    }
        //}




        /// <summary>
        /// 判断是文件夹还是文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private static bool IsDir(string filePath)
        {
            FileInfo fi = new FileInfo(filePath);
            if ((fi.Attributes & FileAttributes.Directory) != 0)
                return true;
            return false;
        }

        /// <summary>
        /// 压缩
        /// </summary>
        /// <param name="fileName">压缩后的文件名(包含物理路径)</param>
        /// <param name="fileOrDirectoryPath">动长参数，待压缩的文件或者文件夹</param>
        /// <returns></returns>
        public static bool PackFiles(string fileName, params string[] fileOrDirectoryPath)
        {
            try
            {
                ZipStrings.UseUnicode = true;
                using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(fileName)))
                {
                    zipStream.SetComment("版本1.0");
                    zipStream.SetLevel(6);//设值CompressionLevel,压缩比
                    foreach (string filePath in fileOrDirectoryPath)
                    {
                        ZipMultiFiles(filePath, zipStream);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }

        }

        /// <summary>
        /// 加密压缩
        /// </summary>
        /// <param name="fileName">压缩后的文件名(包含物理路径)</param>
        /// <param name="password">密码</param>
        /// <param name="fileOrDirectoryPath">动长参数，待压缩的文件或者文件夹</param>
        /// <returns></returns>
        public static bool PackFilesWithPassword(string fileName, string password, params string[] fileOrDirectoryPath)
        {
            try
            {
                ZipStrings.UseUnicode = true;
                using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(fileName)))
                {
                    zipStream.SetComment("版本1.0");
                    zipStream.SetLevel(6);//设值CompressionLevel,压缩比
                    if (!password.IsNullOrEmpty())
                    {
                        zipStream.Password = password;
                    }
                    foreach (string filePath in fileOrDirectoryPath)
                    {
                        ZipMultiFiles(filePath, zipStream);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }

        }

        private static void ZipMultiFiles(string file, ZipOutputStream zipStream, string lastName = "")
        {
            file = file.Replace("\\", "/");
            if (!IsDir(file))
            {
                if (!File.Exists(file))
                {
                    throw new Exception($"文件{file}不存在");
                }
                using (FileStream streamReader = File.OpenRead(file))
                {
                    string path = Path.GetFileName(file);
                    if (lastName != "")
                    {
                        path = lastName + "/" + path;
                    }
                    ZipEntry zipEntry = new ZipEntry(path);
                    zipEntry.DateTime = DateTime.Now;
                    zipEntry.Size = streamReader.Length;
                    zipStream.PutNextEntry(zipEntry);//压入文件
                    int sourceCount = 0;
                    byte[] buffer = new byte[4096 * 1024];
                    while ((sourceCount = streamReader.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        zipStream.Write(buffer, 0, sourceCount);
                    }
                }
            }
            else
            {
                if (!Directory.Exists(file))
                {
                    throw new Exception($"文件夹{file}不存在");
                }
                string[] fileArray = Directory.GetFileSystemEntries(file);
                string folderName = new DirectoryInfo(file).Name; //Regex.Match(file, @"[^\/:*\?\”“\<>|,\\]*$").ToString();
                if (lastName != "")
                {
                    folderName = lastName + "/" + folderName;
                }
                if (fileArray.Length == 0)
                {
                    ZipEntry zipEntry = new ZipEntry(folderName + "/");
                    zipStream.PutNextEntry(zipEntry);
                }
                foreach (string f in fileArray)
                {
                    ZipMultiFiles(f, zipStream, folderName);
                }
            }
        }

        /// <summary>
        /// 解压缩
        /// </summary>
        /// <param name="file">待解压文件名(包含物理路径)</param>
        /// <param name="dir"> 解压到哪个目录中(包含物理路径)</param>
        public static bool UnpackFiles(string file, string dir)
        {
            try
            {
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                ZipInputStream s = new ZipInputStream(File.OpenRead(file));
                ZipEntry theEntry;
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    string directoryName = Path.GetDirectoryName(theEntry.Name);
                    string fileName = Path.GetFileName(theEntry.Name);
                    if (directoryName != String.Empty)
                    {
                        Directory.CreateDirectory(dir + directoryName);
                    }
                    if (fileName != String.Empty)
                    {
                        FileStream streamWriter = File.Create(dir + theEntry.Name);
                        int size = 2048;
                        byte[] data = new byte[2048];
                        while (true)
                        {
                            size = s.Read(data, 0, data.Length);
                            if (size > 0)
                            {
                                streamWriter.Write(data, 0, size);
                            }
                            else
                            {
                                break;
                            }
                        }
                        streamWriter.Close();
                    }
                }
                s.Close();
                return true;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
