using System;
using System.Text;

namespace SWModules
{
    public delegate void EncodingNotifier(StringBuilder sb);
    
    /// <summary>
    ///     The SafeEncoding Class is a child of the UTF8 Encoding class,
    ///     which implements input checking on the GetChars Methods, that
    ///     avoids exceptions when the input characters exceed decimal
    ///     value 127. Any values larger than 127 are converted to
    ///     carriage returns.
    /// </summary>
    public class SafeEncoding : UTF8Encoding
    {
        private const byte Nonprintreplacement = 13;
        private static SafeEncoding _utf8;
        public static event EncodingNotifier Notify;
    
        private static StringBuilder sbTemp = new StringBuilder(128);
        
        /// <summary>
        ///     Returns a static instance of the SafeEncoding class
        /// </summary>
        public new static SafeEncoding UTF8
        {
            get { return _utf8 ?? (_utf8 = new SafeEncoding()); }
        }

        /// <summary>
        ///     Checks for values above 127 and replaces with selected character
        /// </summary>
        /// <param name="bytes">The byte array containing the sequence of bytes to decode.</param>
        /// <returns>A character array containing the results of decoding the specified sequence of bytes.</returns>
        public new static char[] GetChars(byte[] bytes)
        {
            bool message_corrected = false;
            for (var i = 0; i < bytes.Length; i++)
            {
                if (bytes[i] <= 127)
                    continue;
                bytes[i] = Nonprintreplacement;
                message_corrected = true;
            }
            try
            {
                if (message_corrected && Notify != null) GetStackNotify();
                return UTF8Encoding.UTF8.GetChars(bytes);
            }
            catch {
                return null;
            }
        }

        /// <summary>
        ///     Checks for values above 127 and replaces with selected character
        /// </summary>
        /// <param name="bytes">The byte array containing the sequence of bytes to decode.</param>
        /// <param name="byteIndex">The index of the first byte to decode. </param>
        /// <param name="byteCount">The number of bytes to decode. </param>
        /// <returns>A character array containing the results of decoding the specified sequence of bytes.</returns>
        public new static char[] GetChars(byte[] bytes, int byteIndex, int byteCount)
        {
            bool message_corrected = false;
            for (var i = byteIndex; i < byteIndex + byteCount; i++)
            {
                if (bytes[i] <= 127)
                    continue;
                bytes[i] = Nonprintreplacement;
                message_corrected = true;
            }

            try
            {
                if (message_corrected && Notify != null) GetStackNotify();
                return UTF8Encoding.UTF8.GetChars(bytes, byteIndex, byteCount);
            }
            catch {
                return null;
            }
        }

        /// <summary>
        /// Collects a stack trace and notifies subscribers it had an issue decoding a message
        /// </summary>
        private static void GetStackNotify()
        {
            try
            {
                throw new Exception("Bad Character in byte stream");
            }
            catch (Exception e)
            {
                    sbTemp.Clear();
                    sbTemp.Append("[ERROR] SafeEncoding: ");
                    sbTemp.Append(e.Message);
                    sbTemp.Append(";");
                    sbTemp.Append(e.InnerException);
                    sbTemp.Append(";");
                    sbTemp.Append(e.StackTrace);
            }

            if (Notify != null) Notify(sbTemp);
        }

    }
}