using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace GreenTree.Nachtragsmanagement.Core
{
    public static class StaticHelper
    {
        #region Encryption

        /// <summary>
        /// Hashes an input text with MD5
        /// </summary>
        /// <param name="text">The input text.</param>
        public static string GetMD5Hash(string text)
        {
            MD5 md5 = MD5.Create();

            var inputBytes = System.Text.Encoding.ASCII.GetBytes(text);
            var hash = md5.ComputeHash(inputBytes);

            var sb = new StringBuilder();

            for (int i = 0; i < hash.Length; i++)
                sb.Append(hash[i].ToString("X2"));

            return sb.ToString();
        }

        #endregion

        #region String-Compression

        /// <summary>
        /// Compresses a string
        /// </summary>
        /// <param name="text">The text to compress.</param>
        /// <param name="deflate">Determines if the string should be compressed by a DeflateStream.</param>
        /// <param name="encoding">The base encoding of the text.</param>
        /// <returns>The compressed text.</returns>
        public static string CompressString(string text, bool deflate, Encoding encoding)
        {
            var buffer = encoding.GetBytes(text);
            var memoryStream = new MemoryStream();

            if (!deflate)
                using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
                {
                    gZipStream.Write(buffer, 0, buffer.Length);
                }
            else
                using (var deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, true))
                {
                    deflateStream.Write(buffer, 0, buffer.Length);
                }

            memoryStream.Position = 0;

            var compressedData = new byte[memoryStream.Length];
            memoryStream.Read(compressedData, 0, compressedData.Length);

            var gZipBuffer = new byte[compressedData.Length + 4];

            Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
            Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);

            return Convert.ToBase64String(gZipBuffer);
        }

        /// <summary>
        /// Decompresses a string
        /// </summary>
        /// <param name="compressedText">The compressed text.</param>
        /// <param name="deflate">Determines if the string should be decompressed by a DeflateStream.</param>
        /// <param name="encoding">The base encoding of the compressed text.</param>
        /// <returns>The decompressed text.</returns>
        public static string DecompressString(string compressedText, bool deflate, Encoding encoding)
        {
            var gZipBuffer = Convert.FromBase64String(compressedText);
            using (var memoryStream = new MemoryStream())
            {
                var dataLength = BitConverter.ToInt32(gZipBuffer, 0);
                memoryStream.Write(gZipBuffer, 4, gZipBuffer.Length - 4);

                var buffer = new byte[dataLength];

                memoryStream.Position = 0;

                if (!deflate)
                    using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                    {
                        gZipStream.Read(buffer, 0, buffer.Length);
                    }
                else
                    using (var deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
                    {
                        deflateStream.Read(buffer, 0, buffer.Length);
                    }

                return encoding.GetString(buffer);
            }
        }

        /// <summary>
        /// Compresses a string
        /// </summary>
        /// <param name="text">The text to compress.</param>
        /// <returns>Der komprimierte String.</returns>
        public static string CompressString(string text)
        {
            return CompressString(text, true, Encoding.Default);
        }

        /// <summary>
        /// Decompresses a string
        /// </summary>
        /// <param name="text">The text to be decompressed.</param>
        /// <returns>The decompressed text.</returns>
        public static string DecompressString(string text)
        {
            return DecompressString(text, true, Encoding.Default);
        }

        #endregion

        #region File-renaming

        /// <summary>
        /// Adds a suffix to a filepath between name and extension
        /// </summary>
        /// <param name="filename">The original filepath.</param>
        /// <param name="suffix">The suffix.</param>
        /// <param name="isRelativePath">Determines if the original filepath is a relative path.</param>
        public static string AddSuffix(string filename, string suffix, bool isRelativePath)
        {
            var fDir = Path.GetDirectoryName(filename);
            var fName = Path.GetFileNameWithoutExtension(filename);
            var fExt = Path.GetExtension(filename);

            if (isRelativePath)
                return Path.Combine(fDir, String.Concat(fName, suffix, fExt)).Replace("\\", "/");
            else
                return Path.Combine(fDir, String.Concat(fName, suffix, fExt));
        }

        #endregion

        #region Conversion

        /// <summary>
        /// Trys to convert a string to an integer
        /// </summary>
        /// <param name="text">The string to be converted.</param>
        /// <returns>Returns -1, if conversion fails otherwise converted value.</returns>
        public static int TryParseInt(string text)
        {
            int result;

            var success = int.TryParse(text, out result);

            return
                success
                    ? result
                    : -1;
        }

        #endregion
    }
}
