using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Quadarax.Foundation.Core.Value.Extensions
{
    public static class StringExt
    {
        /// <summary>
        /// Default string comparer for like operator.
        /// </summary>
        public static IEqualityComparer<string> DefaultLikeComparer { get; set; } = new StringPatternComparer();

        public static string Align(this string value, int size)
        {
            if (string.IsNullOrEmpty(value)) return new string(' ', size);
            if (value.Length < size)
                return value + new string(' ',  size - value.Length);
            return Truncate(value, size);
        }
        public static string Truncate(this string value, int maxLength)
        {
            if (string.IsNullOrEmpty(value)) return value;
            return value.Length <= maxLength ? value : value.Substring(0, maxLength); 
        }
        
        public static int SeparateValueCount(this string value, string separator)
        {
            var nSepLen = separator.Length;
            var nStrLen = value.Length;
            if (nStrLen == 0 || nSepLen == 0)
                return nSepLen == 0 && nStrLen > 0 ? 1 : 0;
            var nCnt = 0;
            var nPos = value.IndexOf(separator, StringComparison.Ordinal);
            while (nPos >= 0)
            {
                nCnt++;
                nPos = value.IndexOf(separator, nPos + nSepLen, StringComparison.Ordinal);
            }
            return nCnt + 1;

        }
        public static string SeparateValue(this string value, string separator, int zeroBasedIndex)
        {
            var nSepLen = separator.Length;
            var nStrLen = value.Length;
            if (nStrLen == 0 || nSepLen == 0 || nSepLen > nStrLen)
                throw new IndexOutOfRangeException("SeparateValue method has index out of range.");
            var nLastPos = 0;
            var nPos = value.IndexOf(separator, StringComparison.Ordinal);
            while (nPos >= 0)
            {
                if (zeroBasedIndex == 0)
                    break;
                nLastPos = nPos + nSepLen;
                nPos = value.IndexOf(separator, nPos + nSepLen, StringComparison.Ordinal);
                zeroBasedIndex--;
            }
            if (zeroBasedIndex > 0)
                throw new IndexOutOfRangeException("SeparateValue method has index out of range.");
            return value.Substring(nLastPos, nPos == -1 ? nStrLen - nLastPos : nPos - nLastPos);
        }
        public static string SeparateValueLast(this string value, string separator)
        {
            var nSepLen = separator.Length;
            var nStrLen = value.Length;
            if (nStrLen == 0 || nSepLen == 0 || nSepLen > nStrLen)
                throw new IndexOutOfRangeException("SeparateValue method has index out of range.");
            return value.SeparateValue(separator, value.SeparateValueCount(separator) - 1);
        }
        public static string RemoveLast(this string value)
        {
            return value.Length == 0 ? string.Empty : value.Substring(0, value.Length - 1);
        }
        public static string RemoveFirst(this string value)
        {
            return value.Length == 0 ? string.Empty : value.Substring(1, value.Length - 1);
        }

        public static int MaxLineChars(this string value)
        {
            var aParts = value.Split("/n");
            return aParts.Length > 0 ? aParts.Max(x => x.Length) : value.Length;
        }

        public static string[] Split(this string value, string separator)
        {
            return value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
        }

        public static Tuple<string, string>[] Extract(this string value, params string[] hashes) //hashtype, tashname
        {

            var oResult = new List<Tuple<string, string>>();
            if (hashes.Length == 0)
                return new Tuple<string, string>[0];
            var nLenIndex = value.Length + 1;
            foreach (var sHash in hashes)
            {
                var bBeginBlock = true;
                var nPos = value.IndexOf(sHash, StringComparison.InvariantCulture);
                var nLenHash = sHash.Length;
                if (nPos < 0)
                    continue;
                while (nPos >= 0)
                {
                    if (nPos + nLenHash > nLenIndex)
                        break;
                    var nEndPos = value.IndexOf(sHash, nPos + nLenHash, StringComparison.InvariantCulture);
                    if (nEndPos < 0)
                        break;
                    if (bBeginBlock)
                    {
                        var oEntry = new Tuple<string, string>(sHash, value.Substring(nPos + nLenHash, nEndPos - nPos - nLenHash));
                        if (!oResult.Contains(oEntry))
                            oResult.Add(oEntry);
                    }
                    nPos = nEndPos;
                    bBeginBlock = !bBeginBlock;
                }
            }
            return oResult.ToArray();
        }

        public static string EnsurePathBackslash(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return value;
            value = value.Trim();
            if (value.EndsWith(Path.DirectorySeparatorChar))
                return value;
            return value + Path.DirectorySeparatorChar;
        }
        public static string EnsurePathNonBackslash(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return value;
            value = value.Trim();
            if (!value.EndsWith(Path.DirectorySeparatorChar))
                return value;
            return value.RemoveLast();
        }

        public static string RemoveWhitespace(this string input)
        {
            return new string(input.ToCharArray()
                .Where(c => !Char.IsWhiteSpace(c))
                .ToArray());
        }

        /// <summary>
        /// Performs like operator on input string. customComparer can be provides to override default comparer.
        /// </summary>
        /// <param name="input">Input string to compare</param>
        /// <param name="searchPattern">Search pattern corresponds with comparer implementation.</param>
        /// <param name="customComparer">Custom comparer. If not set, use default comparer (defined in <see cref="DefaultLikeComparer"/>)</param>
        /// <returns></returns>
        public static bool Like(this string input,string searchPattern, IEqualityComparer<string>? customComparer = null)
        {
            customComparer ??= DefaultLikeComparer;
            return customComparer.Equals(input, searchPattern);
        }
    }
}
