
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FastReport.RichTextParser;
using FastReport.Code;
using FastReport.Utils;

namespace FastReport
{

    partial class RichObject
    {
        IList<string> expression_list = null;
        int expressionIndex;

        private void GenerateExpressionList()
        {
            FindTextArgs args = new FindTextArgs();
            string plain_text = string.Empty;
            using (RTF_DocumentParser parser = new RTF_DocumentParser())
            {
                parser.Load(Text);
                using (RTF_ToTextSaver saver = new RTF_ToTextSaver(parser.Document))
                    args.Text = new FastString(saver.PlainText);
            }

            string[] brackets = Brackets.Split(',');
            args.OpenBracket = brackets[0];
            args.CloseBracket = brackets[1];
            args.StartIndex = ActualTextStart;

            expression_list = new List<string>();

            while (args.StartIndex < args.Text.Length - 2)
            {
                string expression = CodeUtils.GetExpression(args, false);
                if (expression == null)
                    break;
                expression_list.Add(expression);
                args.StartIndex = args.EndIndex;
            }
        }

        /// <summary>
        ///  Called from RichObject.CalcHeight()
        /// </summary>
        /// <returns></returns>
        internal float SecondStageTranslation()
        {
            float height = 0;
            BandBase parentBand = this.Parent as BandBase;
            float bottom = 0;
            float current_top = this.Top;
            float shift = translated_height - this.Height;

            // shift vertical position of objects which below RichObject
            foreach (ReportComponentBase c in parentBand.Objects)
            {
                if (this.Top < c.Top)
                {
                    if((this.Left < c.Left && this.Left + this.Width > c.Left) || (this.Left > c.Left && c.Left + c.Width > this.Left))
                        c.Top += shift;
                }
            }

            // assign translated objects to parent band
            foreach (ReportComponentBase c in TransltedObjects)
            {
                parentBand.AddChild(c);
                c.ShiftMode = this.ShiftMode; // 20220118 replaced from ShiftMode.Never;
                c.Top += current_top;
                bottom = c.Bottom;
            }
            height = bottom - this.Top;
            Visible = false;

            if (bottom != 0)
                shift = bottom - this.Height;

            return height;
        }


        enum States { Wait, Open };

        private bool InsertText(StreamWriter rtf_writer, string formattedValue)
        {
            bool isRich = formattedValue.StartsWith(@"{\rtf");

            if(isRich)
            {
                rtf_writer.Write(formattedValue);
            }
            else
            {
                bool lf = false;
                foreach (char chr in formattedValue)
                {
                    if (chr == '\r')
                    {
                        rtf_writer.Write("\\line ");
                        lf = true;
                    }
                    else
                    {
                        if (chr == '\n')
                        {
                            if (lf != true)
                                rtf_writer.Write("\\line ");
                        }
                        else if ((int)chr <= 127)
                            rtf_writer.Write(chr);
                        else
                            rtf_writer.Write("\\u{0}\\'3f", (uint)chr);
                        lf = false;
                    }
                }
            }
            return isRich;
        }

        private void CalculateExpressions()
        {
            char ch;
            expressionIndex = 0;
            int internal_brackets_count = 0;
            States state = States.Wait;
            bool need_repack = false;

            if (expression_list == null)
                GenerateExpressionList();

            if (Text == null)
                return;

            using (MemoryStream rtf_stream = new MemoryStream())
            {
                using (StreamWriter rtf_writer = new StreamWriter(rtf_stream, Encoding.UTF8))
                {
                    for (int i = 0; i < Text.Length; i++)
                    {
                        ch = Text[i];
                        switch (state)
                        {
                            case States.Wait:
                                if (ch != '[')
                                    rtf_writer.Write(ch);
                                else
                                    state = States.Open;
                                break;

                            case States.Open:
                                if (ch == '[')
                                    internal_brackets_count++;
                                if (ch != ']')
                                    break;
                                if (internal_brackets_count > 0)
                                {
                                    internal_brackets_count--;
                                    break;
                                }
                                string formattedValue = CalcAndFormatExpression(expression_list[expressionIndex], expressionIndex);
                                /////
                                if (expression_list.Count == 1 && formattedValue.StartsWith(@"{\rtf"))
                                {
                                    Text = formattedValue;
                                    return;
                                }
                                /////
                                need_repack |= InsertText(rtf_writer, formattedValue);
                                expressionIndex++;
                                state = States.Wait;
                                break;
                        }
                    }

                    rtf_writer.Flush();
                    rtf_stream.Seek(0, SeekOrigin.Begin);

                    using (StreamReader rtf_reader = new StreamReader(rtf_stream, Encoding.UTF8))
                    {
                        if (need_repack)
                        {
                            using (RTF_DocumentParser parser = new RTF_DocumentParser())
                            {
                                string buffer = rtf_reader.ReadToEnd();
                                parser.Load(buffer);
                                using (RTF_DocumentSaver saver = new RTF_DocumentSaver(parser.Document))
                                {
                                    base.Text = saver.RichText;
                                }
                            }
                        }
                        else
                        {
                            base.Text = rtf_reader.ReadToEnd();
                        }
                    }
                }
            }

        }

        private void MergeRichText()
        {
            CalculateExpressions();
        }
    }
}
