using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using EasyDevCore.Common.Security;

namespace EasyDevCore.Common
{
    /// <summary>
    /// 
    /// </summary>
    public enum CompressMethod
    {
        /// <summary>
        /// The deflate
        /// </summary>
        Deflate,
        /// <summary>
        /// The G zip
        /// </summary>
        GZip
    }

    /// <summary>
    /// 
    /// </summary>
    public class CompressHelper
    {
        /// <summary>
        /// Compresses the data.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static byte[] CompressData(byte[] data, CompressMethod method = CompressMethod.Deflate)
        {
            using (var inputStream = new MemoryStream(data))
            using (var compressStream = new MemoryStream())
            {
                using (var compressor = (method == CompressMethod.Deflate ? (Stream)(new DeflateStream(compressStream, CompressionMode.Compress)) : (Stream)(new GZipStream(compressStream, CompressionMode.Compress))))
                {
                    inputStream.CopyTo(compressor);
                }
                return compressStream.ToArray();
            }
        }

        /// <summary>
        /// Compresses the data.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="password">The password to encrypt data.</param>
        /// <param name="algorithm">The algorithm.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static byte[] CompressData(byte[] data, string password, SymmetricAlgorithmMethod algorithm = SymmetricAlgorithmMethod.DESCryptoServiceProvider, CompressMethod method = CompressMethod.Deflate)
        {
            return EncryptionHelper.EncryptData(password, algorithm, CompressData(data, method));
        }

        /// <summary>
        /// Decompress data
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static byte[] DecompressData(byte[] data, CompressMethod method = CompressMethod.Deflate)
        {
            using (var inputStream = new MemoryStream(data))
            using (var decompressStream = new MemoryStream())
            {
                using (var decompressor = (method == CompressMethod.Deflate ? (Stream)(new DeflateStream(inputStream, CompressionMode.Decompress)) : (Stream)(new GZipStream(inputStream, CompressionMode.Decompress))))
                {
                    decompressor.CopyTo(decompressStream);
                }
                return decompressStream.ToArray();
            }
        }

        /// <summary>
        /// Des the compress data.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="password">The password to decrypt data.</param>
        /// <param name="algorithm">The algorithm.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static byte[] DecompressData(byte[] data, string password, SymmetricAlgorithmMethod algorithm = SymmetricAlgorithmMethod.DESCryptoServiceProvider, CompressMethod method = CompressMethod.Deflate)
        {
            return DecompressData(EncryptionHelper.DecryptData(password, algorithm, data), method);
        }

        /// <summary>
        /// Compresses the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="method">The method.</param>
        /// <param name="encoding">The encoding.</param>
        /// <returns></returns>
        public static string CompressString(string value, Encoding encoding, CompressMethod method = CompressMethod.Deflate)
        {
            return Encoding.GetEncoding(850).GetString(CompressData(encoding.GetBytes(value), method));
        }

        /// <summary>
        /// Compresses the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="password">The password to encrypt data.</param>
        /// <param name="encoding">The encoding.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static string CompressString(string value, string password, Encoding encoding, CompressMethod method = CompressMethod.Deflate)
        {
            return  Encoding.GetEncoding(850).GetString(CompressData(encoding.GetBytes(value), password: password, method: method));
        }

        /// <summary>
        /// Compresses the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static string CompressString(string value, CompressMethod method = CompressMethod.Deflate)
        {
            return Encoding.GetEncoding(850).GetString(CompressData(ConvertHelper.ToByteArray(value), method));
        }

        /// <summary>
        /// Compresses the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="password">The password to encrypt.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static string CompressString(string value, string password, CompressMethod method = CompressMethod.Deflate)
        {
            return Encoding.GetEncoding(850).GetString(CompressData(ConvertHelper.ToByteArray(value), password: password, method: method));
        }

        /// <summary>
        /// Decompresses the string.
        /// </summary>
        /// <param name="compressValue">The compress value.</param>
        /// <param name="method">The method.</param>
        /// <param name="encoding">The encoding.</param>
        /// <returns></returns>
        public static string DecompressString(string compressValue, Encoding encoding, CompressMethod method = CompressMethod.Deflate)
        {
            return encoding.GetString(DecompressData(Encoding.GetEncoding(850).GetBytes(compressValue), method));
        }

        /// <summary>
        /// Decompresses the string.
        /// </summary>
        /// <param name="compressValue">The compress value.</param>
        /// <param name="password">The password.</param>
        /// <param name="encoding">The encoding.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static string DecompressString(string compressValue, string password, Encoding encoding, CompressMethod method = CompressMethod.Deflate)
        {
            return encoding.GetString(DecompressData(Encoding.GetEncoding(850).GetBytes(compressValue), password: password, method: method));
        }

        /// <summary>
        /// Decompresses the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static string DecompressString(string value, CompressMethod method = CompressMethod.Deflate)
        {
            return ConvertHelper.ToString(DecompressData(Encoding.GetEncoding(850).GetBytes(value), method));
        }

        /// <summary>
        /// Decompresses the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="password">The password.</param>
        /// <param name="method">The method.</param>
        /// <returns></returns>
        public static string DecompressString(string value, string password, CompressMethod method = CompressMethod.Deflate)
        {
            return ConvertHelper.ToString(DecompressData(Encoding.GetEncoding(850).GetBytes(value), password: password, method: method));
        }
    }
}
