using System.IO;
using System.Text;
using System.Windows;
using Syncfusion.Windows.Controls.RichTextBoxAdv;

namespace InABox.DynamicGrid
{
    /// <summary>
    ///     Represents the extension class for SfRichTextBoxAdv.
    /// </summary>
    public class ExtendedRichTextEditor : SfRichTextBoxAdv
    {
        #region Static Dependency Properties

        /// <summary>
        ///     Using as a backing store for Text dependency property to enable styling, animation etc.
        /// </summary>
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(ExtendedRichTextEditor),
            new PropertyMetadata("", OnTextChanged));

        #endregion

        #region Fields

        private bool skipUpdating;

        #endregion

        #region Constructor

        /// <summary>
        ///     Initializes the instance of SfRichTextBoxAdvExtension class.
        /// </summary>
        public ExtendedRichTextEditor()
        {
            // Wires the ContentChanged event.
            ContentChanged += RTE_ContentChanged;
        }

        #endregion

        #region Properties

        /// <summary>
        ///     Gets or Sets the text.
        /// </summary>
        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }

        #endregion

        #region Static Events

        /// <summary>
        ///     Called when text changed.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="e"></param>
        private static void OnTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var richTextBox = (ExtendedRichTextEditor)obj;
            //Update the document with the text.
            richTextBox.UpdateDocument((string)e.NewValue);
        }

        #endregion

        #region Events

        /// <summary>
        ///     Called when content changes in SfRichTextBoxAdv.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="args"></param>
        private void RTE_ContentChanged(object obj, ContentChangedEventArgs args)
        {
            if (Document != null)
            {
                // To skip internal updation of document on setting Text property.
                skipUpdating = true;
                Stream stream = new MemoryStream();
                // Saves the document as text Stream.
                Save(stream, FormatType.Html);
                stream.Position = 0;
                // Reads the stream and assigned the string to Text property
                using (var reader = new StreamReader(stream))
                {
                    Text = reader.ReadToEnd();
                }

                skipUpdating = false;
            }
        }

        #endregion

        #region Implementation

        /// <summary>
        ///     Updates the document.
        /// </summary>
        /// <param name="text">The text.</param>
        private void UpdateDocument(string text)
        {
            // If text property is set internally means, skip updating the document.
            if (!skipUpdating && !string.IsNullOrEmpty(text))
            {
                Stream stream = new MemoryStream();
                // Convert the text string to byte array.
                var bytes = Encoding.UTF8.GetBytes(text);
                // Writes the byte array to stream.
                stream.Write(bytes, 0, bytes.Length);
                stream.Position = 0;
                //Load the Text stream.
                Load(stream, FormatType.Html);
            }
        }

        /// <summary>
        ///     Disposes the instance.
        /// </summary>
        public void Dispose()
        {
            ContentChanged -= RTE_ContentChanged;
            ClearValue(TextProperty);
            base.Dispose();
        }

        #endregion
    }
}