using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Unicode;
using System.Threading.Tasks;

using SharpCompress;
using SharpCompress.Common;
using SharpCompress.Factories;
using SharpCompress.Writers;
using SharpCompress.Compressors;

using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
using SharpCompress.Archives.Rar;
using SharpCompress.Archives.GZip;
using SharpCompress.Archives.Tar;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Readers;


namespace SharpCompressStudy.Core
{
    public static class CommonUtility
    {
        /// <summary>
        /// 解压文件
        /// (解压到压缩文件所在目录)
        /// </summary>
        /// <param name="fileName">压缩文件包</param>
        /// <param name="isDelete">解压后删除压缩文件</param>
        public static void Decompress(string fileName, bool isDelete)
        {
            if (string.IsNullOrWhiteSpace(fileName))
            { 
                throw new ArgumentNullException($"{fileName}");
            }

            if (!File.Exists(fileName))
            {
                throw new FileNotFoundException($"{fileName} not found");
            }

            try
            {
                //扩展名
                var extName = Path.GetExtension(fileName).Trim().ToLower();

                //文件名
                var rarFileName = Path.GetFileName(fileName);

                //不带扩展名的文件名
                var rarFileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);

                //解压根目录
                string extractPath = Path.GetDirectoryName(fileName) ?? "";

                //解压文件
                using (var archive = GetArchiveByExtName(fileName))
                {
                    //创建解压目录
                    if (!Directory.Exists(extractPath))
                    {
                        Directory.CreateDirectory(extractPath);
                    }

                    //解压所有文件到指定目录
                    foreach (var entry in archive.Entries)
                    {
                        if (!entry.IsDirectory)
                        {
                            entry.WriteToDirectory(extractPath, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
                        }
                    }

                    //如果整体解压到一个同名目录,则把同名目录内容提取到当前目录,并删除同名目录
                    if (archive.Entries.Where(f => f.IsDirectory && f.Key == rarFileNameWithoutExt).Count() == 1)
                    {
                        var dir = new DirectoryInfo(Path.Combine(extractPath, rarFileNameWithoutExt));
                        dir.GetDirectories().ForEach(f =>
                        {
                            var toDir = Path.Combine(extractPath, f.Name);
                            if (Directory.Exists(toDir))
                            {
                                Directory.Delete(toDir, true);
                            }
                            f.MoveTo(toDir);
                        });

                        dir.GetFiles().ForEach(f =>
                        {
                            f.MoveTo(Path.Combine(extractPath, f.Name), true);
                        });

                        dir.Delete();
                    }
                }

                //删除压缩文件
                if (isDelete && File.Exists(fileName)) 
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception ex)
            {
                Console.Write($"解压报错,错误:{ex}");
                throw;
            }
        }

        /// <summary>
        /// 按扩展名获取IArchive对象
        /// </summary>
        /// <param name="compressFileName">压缩文件</param>
        /// <returns>IArchive对象</returns>
        /// <exception cref="ArchiveException">压缩文件类型不支持异常</exception>
        private static IArchive GetArchiveByExtName(string compressFileName)
        {
            IArchive archive;
            var extName = Path.GetExtension(compressFileName).Trim().ToLower();
            switch (extName)
            {
                case ".rar":
                    archive = RarArchive.Open(compressFileName);
                    break;

                case ".zip":
                    archive = ZipArchive.Open(compressFileName);
                    break;

                case ".7z":
                    archive = SevenZipArchive.Open(compressFileName);
                    break;

                case ".gz":
                    archive = GZipArchive.Open(compressFileName);
                    break;
                case ".tar":
                    archive = TarArchive.Open(compressFileName);
                    break;

                default:
                    throw new ArchiveException($"不支持的压缩文件格式[{compressFileName}]");
            }

            return archive;
        }
    }
}