using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using FastReport.Editor;
using FastReport.Editor.Common;
using FastReport.Editor.Syntax;
using FastReport.Utils;
using FastReport.Forms;
using FastReport.Design.ToolWindows;
using FastReport.Data;
using FastReport.Code;
using System.Reflection;
using FastReport.Design.PageDesigners.Page;

namespace FastReport.Design.PageDesigners.Code
{
#if !DEBUG
    [DesignTimeVisible(false)]
#endif
    internal class FRXPageDesigner : PageDesignerBase
    {

        #region Fields
        private SyntaxEdit edit;
        private TextSource source;
        private bool editInitialized;
        private Point positionInText;
        private bool canModify;

        private int defaultHintDelay;
        private int defaultCompletionDelay;
        Font defaultFont;
        #endregion

        #region Properties
        public SyntaxEdit Edit
        {
            get
            {
                if (!editInitialized)
                    CreateEdit();
                return edit;
            }
        }

        public TextSource Source
        {
            get
            {
                if (!editInitialized)
                    CreateEdit();
                return source;
            }
        }

        #endregion

        #region Private Methods
        private void CreateEdit()
        {
            defaultHintDelay = SyntaxConsts.DefaultHintDelay;
            defaultCompletionDelay = SyntaxConsts.DefaultCompletionDelay;

            editInitialized = true;
            source = new TextSource();
            edit = new SyntaxEdit();
            defaultFont = edit.Font;
            edit.Dock = DockStyle.Fill;
            edit.BorderStyle = EditBorderStyle.None;
            edit.Source = source;
            edit.AllowDrop = true;
            edit.TextChanged += Edit_TextChanged;
            Controls.Add(edit);

            // do this after controls.add!
            edit.IndentOptions = IndentOptions.AutoIndent | IndentOptions.SmartIndent;
            edit.NavigateOptions = NavigateOptions.BeyondEol;
            edit.Braces.BracesOptions = BracesOptions.Highlight | BracesOptions.HighlightBounds;
            edit.Braces.BackColor = Color.LightGray;
            edit.Braces.Style = FontStyle.Regular;
            edit.Scroll.ScrollBars = RichTextBoxScrollBars.Both;
            edit.Scroll.Options = ScrollingOptions.AllowSplitHorz | ScrollingOptions.AllowSplitVert | ScrollingOptions.SmoothScroll;
            edit.Outlining.AllowOutlining = true;
            edit.DisplayLines.UseSpaces = true;
            edit.SplitHorz += new EventHandler(Edit_SplitHorz);
            edit.SplitVert += new EventHandler(Edit_SplitVert);
            edit.ImeMode = ImeMode.On;

            UpdateOptions();
            UpdateEditColors();
            LocalizeEditMenu();

            canModify = false;
            SetScriptText();
            canModify = true;
        }

        private void Edit_TextChanged(object sender, EventArgs e)
        {
            if(canModify)
                Designer.SetModified(null, "FRXChange");
        }

        private void UpdateEditColors()
        {
            edit.Gutter.BrushColor = UIStyleUtils.GetControlColor(Designer.UIStyle);
            edit.Gutter.PenColor = edit.Gutter.BrushColor;
        }

        private void Edit_SplitHorz(object sender, EventArgs e)
        {
            Edit.HorzSplitEdit.BorderStyle = Edit.BorderStyle;
        }

        private void Edit_SplitVert(object sender, EventArgs e)
        {
            Edit.VertSplitEdit.BorderStyle = Edit.BorderStyle;
        }

        private void LocalizeEditMenu()
        {
            MyRes res = new MyRes("Designer,Menu,Edit");
            StringConsts.MenuUndoCaption = res.Get("Undo");
            StringConsts.MenuRedoCaption = res.Get("Redo");
            StringConsts.MenuCutCaption = res.Get("Cut");
            StringConsts.MenuCopyCaption = res.Get("Copy");
            StringConsts.MenuPasteCaption = res.Get("Paste");
            StringConsts.MenuDeleteCaption = res.Get("Delete");
            StringConsts.MenuSelectAllCaption = res.Get("SelectAll");
        }

        private void SetScriptText()
        {
            Edit.Source.Text = Designer.Report.SaveToString();
        }
        #endregion

        #region Public Methods

        public void UpdateOptions()
        {
            Edit.DisplayLines.UseSpaces = FRXPageSettings.UseSpaces;
            Edit.DisplayLines.TabStops = new int[] { FRXPageSettings.TabSize };
        }

        public void UpdateFont()
        {
            Font font;
            bool needDisposeFont = false;

            if (Config.Root.FindItem("Designer").FindItem("Fonts").Find("CodePageDesigner") != -1)
            {
                XmlItem editorFont = Config.Root.FindItem("Designer").FindItem("Fonts").FindItem("CodePageDesigner").FindItem("CodePage");
                font = new Font(editorFont.GetProp("font-name"), int.Parse(editorFont.GetProp("font-size")), (editorFont.GetProp("font-italic") == "1" ? FontStyle.Italic : FontStyle.Regular) | (editorFont.GetProp("font-bold") == "1" ? FontStyle.Bold : FontStyle.Regular));
                needDisposeFont = true;
            }
            else
            {
                font = defaultFont;
            }
            Edit.Font = this.LogicalToDevice(font, needDisposeFont);
        }

        public void Copy()
        {
            Edit.Selection.Copy();
        }

        public void Cut()
        {
            Edit.Selection.Cut();
        }

        public void Paste()
        {
            Edit.Selection.Paste();
        }

        public bool CanUndo()
        {
            return Source.CanUndo();
        }

        public bool CanRedo()
        {
            return Source.CanRedo();
        }

        public override void FillObjects(bool resetSelection)
        {
            // do nothing
        }

        public override void PageActivated()
        {
            base.PageActivated();

            canModify = false;
            SetScriptText();
            canModify = true;

            UpdateOptions();
            UpdateLanguage();
            Edit.Position = new Point(0, 0);
            Edit.Position = positionInText;
        }

        public override void PageDeactivated()
        {
            base.PageDeactivated();
            if (editInitialized)
            {
                CommitChanges();
                positionInText = Edit.Position;
            }
        }

        public override void SaveState()
        {
            FRXPageSettings.SaveState();
        }

        public override void RestoreState()
        {
        }

        public override DesignerOptionsPage GetOptionsPage()
        {
            return new FRXPageOptions(this);
        }
        #endregion

        #region IDesignerPlugin

        public override void UpdateUIStyle()
        {
            base.UpdateUIStyle();
            if (editInitialized)
                UpdateEditColors();
        }

        public override void Localize()
        {
            base.Localize();
            if (editInitialized)
                LocalizeEditMenu();
        }

        public override void UpdateDpiDependencies()
        {
            base.UpdateDpiDependencies();
            if (editInitialized)
                UpdateFont();
        }

        public void UpdateLanguage()
        {
            SyntaxParser parser = new XmlParser();
            parser.Options |= SyntaxOptions.SyntaxErrors;
            Edit.Lexer = parser;
            Source.Lexer = parser;
            Source.FormatText();
            Edit.Refresh();
        }

        public void CommitChanges()
        {
            if (Edit.Modified)
            {
                Edit.Modified = false;
                Designer.Report.LoadFromString(Edit.Source.Text);
                (Designer.ActiveReportTab.Plugins.Find("Code") as CodePageDesigner).Script = Designer.Report.ScriptText;
                Designer.SetModified(null, "FRXChange");
            }
        }

        #endregion

        public FRXPageDesigner(Designer designer) : base(designer)
        {
            Name = "FRXPage";
            RightToLeft = Config.RightToLeft ? RightToLeft.Yes : RightToLeft.No;
        }
    }
}
