using System;
using System.Text;

namespace Sockeye.Util
{


    internal static class StringUtil
    {

        /// <summary>
        /// Extract string between tokens
        /// </summary>
        /// <param name="s"></param>
        /// <param name="openTag"></param>
        /// <param name="closeTag"></param>
        /// <returns></returns>
        public static string Extract(string s, string openTag, string closeTag)
        {
            int startIndex = s.IndexOf(openTag);
            if (startIndex == -1)
                throw new System.IndexOutOfRangeException("ExtractString->Error: open tag not found");
            startIndex += openTag.Length;

            int endIndex = s.IndexOf(closeTag, startIndex);
            if (endIndex == -1)
                throw new System.IndexOutOfRangeException("ExtractString->Error: closing tag not found");
            return s.Substring(startIndex, endIndex - startIndex);
        }



        /// <summary>
        /// Trim a string if necessary
        /// </summary>
        /// <param name="s"></param>
        /// <param name="maxLength"></param>
        /// <returns></returns>
        public static string MaxLength(string s, int maxLength)
        {
            if (s.Length > maxLength)
                s = s.Substring(0, maxLength);
            return s;
        }


        /// <summary>
        /// mask the exact ip address by substituting the last position of the address with XXX
        /// Works with v6 or v4 addresses as strings
        /// </summary>
        /// <param name="sIP"></param>
        /// <returns></returns>
        public static string MaskIPAddress(string sIP)
        {
            //My test station ip address!?
            //"::ffff:127.0.0.1"
            //weird dual format, new method that covers both v4 and v4 inside v6 format
            if (sIP.Contains("."))
            {
                //new algorithm, replace anything after last period with an xxx
                var ret = sIP.Substring(0, sIP.LastIndexOf(".")) + ".xxx";
                return ret;

            }


            //8 groups IPV6 Address format
            if (sIP.Contains(":"))
            {

                sIP = sIP.Replace("::", ":0:");//rehydrate "compressed" addresses
                var segs = sIP.Split(':');
                if (segs.Length < 7)
                    return "UNRECOGNIZED V6 IP ADDRESS FORMAT";
                else
                    return segs[0] + ":" + segs[1] + ":" + segs[2] + ":" + segs[3] + ":" + segs[4] + ":" + segs[5] + ":" + segs[6] + ":" + segs[7] + ":xxxx";
            }

            // //4 groups IPV4 Address format
            // if (sIP.Contains("."))
            // {
            //     //8 groups IPV6 Address format
            //     var segs = sIP.Split('.');
            //     if (segs.Length < 3)
            //         return "UNRECOGNIZED V4 IP ADDRESS FORMAT";
            //     else
            //         return segs[0] + "." + segs[1] + "." + segs[2] + ".xxx";
            // }

            return "UNRECOGNIZED IP ADDDRESS FORMAT";
        }


        //Used to ensure a unique name generated by appending -nnn is within length requirements by splitting and chopping part of text to keep name
        public static string UniqueNameBuilder(string oldName, long appendValue, int maxLength)
        {
            //deadman switch
            if (appendValue > int.MaxValue)
            {
                throw new System.OverflowException($"UniqueNameBuilder: Unique name could not be generated for item \"{oldName}\" after {int.MaxValue.ToString()} attempts");
            }
            var appendString = "-" + appendValue.ToString();
            string ret = oldName + appendString;
            var diff = maxLength - ret.Length;
            if (diff < 0)
            {
                ret = oldName.Substring(0, Math.Abs(diff)) + appendString;
            }
            return ret;
        }

        //used to trim an enum type down to only it's most relevant (rightmost) portion
        public static string TrimTypeName(string str)
        {
            if (str.Contains('.'))
            {
                return str.Substring(str.LastIndexOf('.') + 1);
            }
            return str;
        }

        public static string ReplaceLastOccurrence(string source, string find, string replace)
        {
            if (source == null) { return source; }
            int place = source.LastIndexOf(find);

            if (place == -1)
                return source;

            string result = source.Remove(place, find.Length).Insert(place, replace);
            return result;
        }

        public static int HexToInt(string h)
        {
            int r = 0;
            int.TryParse(h, System.Globalization.NumberStyles.HexNumber, null, out r);
            return r;
        }


        public static string ToHex(string str)
        {
            var sb = new StringBuilder();

            var bytes = Encoding.ASCII.GetBytes(str);
            foreach (var t in bytes)
            {
                sb.Append(t.ToString("X2"));
            }

            return sb.ToString(); // returns: "48656C6C6F20776F726C64" for "Hello world"
        }



        public static string FromHex(string hexString)
        {
            var bytes = new byte[hexString.Length / 2];
            for (var i = 0; i < bytes.Length; i++)
            {
                bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }

            return Encoding.ASCII.GetString(bytes); // returns: "Hello world" for "48656C6C6F20776F726C64"
        }


        //Generate a random code for email validation and v7 license key fetching
        //doesn't have to be perfect, it's only temporary and 
        //requires knowledge of the customer / trial user
        //email address to use it so it's kind of 2 factor
        public static string GenFetchCode()
        {

            //sufficient for this purpose
            //https://stackoverflow.com/a/1344258/8939

            var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            var stringChars = new char[10];
            var random = new Random();

            for (int i = 0; i < stringChars.Length; i++)
            {
                stringChars[i] = chars[random.Next(chars.Length)];
            }

            var finalString = new String(stringChars);
            return finalString;
        }

    }//eoc

}//eons