using UnityEngine;
using CommonUI.Cell.Game;
using CommonUI.Display;

using UnityImage = CommonUI_Unity3D.Impl.UnityImage;
using AttributedString = CommonUI.Display.Text.AttributedString;
using BaseRichTextLayer = CommonUI.Display.Text.BaseRichTextLayer;
using TextAttribute = CommonUI.Display.Text.TextAttribute;
using CommonUI.Display.Text;
using UnityEngine.EventSystems;
using System;
using CommonUI.Data;

namespace CommonUnity3D.UGUI
{    //----------------------------------------------------------------------------------------
    /// <summary>
    /// 富文本渲染器
    /// </summary>
    public class UGUIRichTextLayer : BaseRichTextLayer
    {
        /// <summary>
        /// 使用系统字
        /// </summary>
        public bool UseBitmapFont
        {
            get { return mUseBitmapFont; }
            set { mUseBitmapFont = value; }
        }
        public Font DefaultFont
        {
            get { return mFont; }
            set
            {
                this.mFont = value;
                this.mTextGenSetting.font = value;
                this.mTextGenSetting.fontSize = value.fontSize;
            }
        }
        public DisplayNode Binding
        {
            get { return mOwner; }
        }
        public TextAttribute DefaultTextAttribute
        {
            get { return mDefaultTextAttribute; }
            set { mDefaultTextAttribute = value; }
        }
        public string UnityRichText
        {
            set { this.XmlText = UIUtils.UnityRichTextToXmlText(value); }
        }
        public string XmlText
        {
            set
            {
                try
                {
                    var atext = UIFactory.Instance.DecodeAttributedString(value, mDefaultTextAttribute);
                    if (atext != null)
                    {
                        this.SetString(atext);
                    }
                    else
                    {
                        this.Text = value;
                    }
                }
                catch (Exception err)
                {
#if UNITY_5
                    Debug.LogWarningFormat("{0}\n{1}", err.Message, value);
#endif
                    this.Text = value;
                }
            }
        }

        private bool mUseBitmapFont = false;
        private DisplayNode mOwner;
        private UnityEngine.Font mFont;
        private TextAttribute mDefaultTextAttribute;
        private TextGenerator mTextGen;
        private TextGenerationSettings mTextGenSetting = new TextGenerationSettings();
        private Rect mCaretBounds = new Rect(0, 0, 0, 0);

        private CommonUI.Data.TextAnchor mAnchor = CommonUI.Data.TextAnchor.L_T;
        public UGUIRichTextLayer(DisplayNode parent, bool useBitmapFont)
        {
            this.mUseBitmapFont = useBitmapFont;

            this.mOwner = parent;
            this.mFont = UIFactory.Instance.DefaultFont;
            this.mTextGen = UIFactory.Instance.DefaultTextGenerator;

            this.mTextGenSetting.color = UnityEngine.Color.white;
            this.mTextGenSetting.font = mFont;
            this.mTextGenSetting.fontSize = mFont.fontSize;
            this.mTextGenSetting.fontStyle = UnityEngine.FontStyle.Normal;
            this.mTextGenSetting.generateOutOfBounds = true;
            this.mTextGenSetting.generationExtents = Vector2.zero;
            this.mTextGenSetting.horizontalOverflow = HorizontalWrapMode.Overflow;
            this.mTextGenSetting.lineSpacing = 1;
            this.mTextGenSetting.pivot = Vector2.zero;
            this.mTextGenSetting.resizeTextForBestFit = false;
            this.mTextGenSetting.resizeTextMaxSize = 1;
            this.mTextGenSetting.resizeTextMinSize = 1;
            this.mTextGenSetting.richText = false;
            this.mTextGenSetting.scaleFactor = 1;
            this.mTextGenSetting.textAnchor = UnityEngine.TextAnchor.LowerLeft;
            this.mTextGenSetting.updateBounds = true;
            this.mTextGenSetting.verticalOverflow = VerticalWrapMode.Overflow;

            this.mDefaultTextAttribute = new TextAttribute(
                UIUtils.Color_To_UInt32_RGBA(mTextGenSetting.color),
                mTextGenSetting.fontSize,
                mTextGenSetting.font.name);
        }

        public override void Dispose()
        {
            this.mOwner = null;
            this.mFont = null;
            this.mTextGen = null;
            base.Dispose();
        }

        protected override Image AddImage(string file)
        {
            Image img = Driver.Instance.createImage(file);
            return img;
        }

        protected override CommonUI.Cell.CPJResource AddCPJResource(string file)
        {
            CommonUI.Cell.CPJResource res = CommonUI.Cell.CPJResource.CreateResource(file);
            return res;
        }



        protected override void OnBeginResetChars()
        {
            this.mCaretBounds.y = 0;
            this.mCaretBounds.x = 0;
            this.mCaretBounds.size = UIFactory.Instance.DefaultCaretSize;
            base.OnBeginResetChars();
        }
        protected override void OnEndResetLines()
        {
            base.OnEndResetLines();
            if (AllRegions.Count > 0)
            {
                var rg = AllRegions[AllRegions.Count - 1];
                var bounds = rg.Bounds;
                this.mCaretBounds.height = bounds.height;
                this.mCaretBounds.width = UIFactory.Instance.DefaultCaretSize.x;
                if (rg.IsBreak)
                {
                    this.mCaretBounds.y = bounds.y + bounds.height;
                    this.mCaretBounds.x = 0;
                }
                else
                {
                    this.mCaretBounds.y = bounds.y;
                    this.mCaretBounds.x = bounds.x + bounds.width;
                }
            }
        }

        protected override bool TestTextLineBreak(string text, TextAttribute ta, float testW, out float tw, out float th)
        {
            if (UseBitmapFont)
            {
                return Driver.Instance.testTextLineBreak(text, ta.fontSize, ta.fontStyle, this.BorderCount, testW, out tw, out th);
            }
            else
            {
                int fsize = (int)ta.fontSize;
                UnityEngine.FontStyle fstyle = (UnityEngine.FontStyle)ta.fontStyle;
                TextGenerationSettings setting = mTextGenSetting;
                setting.fontSize = fsize;
                setting.fontStyle = fstyle;
                tw = mTextGen.GetPreferredWidth(text, setting);
                th = mTextGen.GetPreferredHeight(text, setting);
                if (testW < tw)
                {
                    return true;
                }
                return false;
            }
        }

        //--------------------------------------------------------------------------------------------
        #region ITextComponent

        public string Text
        {
            get { return base.GetText().ToString(); }
            set { base.SetString(new AttributedString(value, mDefaultTextAttribute)); }
        }
        public int FontSize
        {
            get { return (int)mDefaultTextAttribute.fontSize; }
            set { mDefaultTextAttribute.fontSize = value; }
        }
        public UnityEngine.Color FontColor
        {
            get { return UIUtils.UInt32_RGBA_To_Color(mDefaultTextAttribute.fontColor); }
            set { mDefaultTextAttribute.fontColor = UIUtils.Color_To_UInt32_RGBA(value); }
        }
        public CommonUI.Data.FontStyle Style
        {
            get { bool underline; return UIUtils.ToFontStyle(mDefaultTextAttribute.fontStyle, out underline); }
            set { mDefaultTextAttribute.fontStyle = UIUtils.ToTextLayerFontStyle(value, mDefaultTextAttribute.underline); }
        }
        public bool IsUnderline
        {
            get { return mDefaultTextAttribute.underline; }
            set { mDefaultTextAttribute.underline = value; }
        }
        public Vector2 TextOffset
        {
            get { return Vector2.zero; }
            set { }
        }
        public CommonUI.Data.TextAnchor Anchor
        {
            get { return mAnchor; }
            set
            {
                if (mAnchor != value)
                {
                    mAnchor = value;
                    base.SetAnchor(UIUtils.ToRichTextAnchor(value));
                }
            }
        }
        public Vector2 PreferredSize
        {
            get { return new Vector2(base.ContentWidth, base.ContentHeight); }
        }
        public Rect LastCaretPosition
        {
            get { return mCaretBounds; }
        }
        public void SetBorder(UnityEngine.Color bc, Vector2 distance)
        {
            mDefaultTextAttribute.borderCount = TextBorderCount.Border;
            mDefaultTextAttribute.borderColor = UIUtils.Color_To_UInt32_RGBA(bc);
        }
        public void SetShadow(UnityEngine.Color bc, Vector2 distance)
        {
            mDefaultTextAttribute.borderCount = UIUtils.ToTextShadowCount(distance);
            mDefaultTextAttribute.borderColor = UIUtils.Color_To_UInt32_RGBA(bc);
        }
        public void SetFont(Font font)
        {
            this.DefaultFont = font;
            this.mDefaultTextAttribute.fontName = font.name;
        }

        #endregion
        //--------------------------------------------------------------------------------------------
        #region Drawable

        public override Drawable CreateDrawable(Region rg, object content)
        {
            DisplayNode region = null;
            if (content is TextDrawable)
            {
                region = content as DisplayNode;
            }
            else if (content is TImageRegion)
            {
                region = new DrawImage(this, rg, (TImageRegion)content);
            }
            else if (content is TSpriteMetaAnimateFrame)
            {
                region = new DrawSprite(this, rg, (TSpriteMetaAnimateFrame)content);
            }
            else if (UseBitmapFont)
            {
                region = new DrawBitmapText(this, rg, content.ToString());
            }
            else
            {
                region = new DrawText(this, rg, content.ToString());
            }
            mOwner.AddChild(region);
            return region as Drawable;
        }

        //--------------------------------------------------------------------------------------------
        public class DrawText : TextSprite, Drawable
        {
            public DrawText(UGUIRichTextLayer layer, Region rg, string text)
                : base(string.Format("region {0}({1}-{2}):\"{3}\"", rg.Index, rg.CharStartIndex, rg.CharEndIndex, rg.Text))
            {
                TextAttribute ta = rg.Attribute;
                this.Text = text;
                this.Graphics.supportRichText = false;
                this.SetTextFont(layer.mFont, (int)ta.fontSize, (UnityEngine.FontStyle)ta.fontStyle);
                this.Graphics.alignment = UnityEngine.TextAnchor.UpperLeft;
                this.Graphics.resizeTextForBestFit = false;
                this.Graphics.IsUnderline = rg.Attribute.underline;
                this.Graphics.color = UIUtils.UInt32_RGBA_To_Color(ta.fontColor);
                switch (rg.Attribute.borderCount)
                {
                    case CommonUI.Data.TextBorderCount.Null:
                        break;
                    case CommonUI.Data.TextBorderCount.Border:
                        this.AddBorder(UIUtils.UInt32_RGBA_To_Color(ta.borderColor), new Vector2(1, 1));
                        break;
                    default:
                        this.AddShadow(UIUtils.UInt32_RGBA_To_Color(ta.borderColor), UIUtils.ToTextBorderOffset(rg.Attribute.borderCount));
                        break;
                }
                this.Size2D = new Vector2(rg.Bounds.width, rg.Bounds.height);
                this.Position2D = new Vector2(rg.Bounds.x, rg.Bounds.y);
            }
            public float CharWidth { get { return this.Size2D.x; } }
            public float CharHeight { get { return this.Size2D.y; } }
            public void Render(CommonUI.Display.Graphics g, Region rg, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = true;
            }
            public void Hide(BaseRichTextLayer.Region self, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = false;
            }
        }//--------------------------------------------------------------------------------------------
        public class DrawBitmapText : BitmapTextSprite, Drawable
        {
            public DrawBitmapText(UGUIRichTextLayer layer, Region rg, string text)
                : base(string.Format("region {0}({1}-{2}):\"{3}\"", rg.Index, rg.CharStartIndex, rg.CharEndIndex, rg.Text))
            {
                TextAttribute ta = rg.Attribute;
                this.FontSize = (int)ta.fontSize;
                this.FontColor = UIUtils.UInt32_RGBA_To_Color(ta.fontColor);
                this.Graphics.LayerFontStyle = ta.fontStyle;
                this.Text = text;
                this.Anchor = CommonUI.Data.TextAnchor.L_T;
                switch (rg.Attribute.borderCount)
                {
                    case CommonUI.Data.TextBorderCount.Null:
                        break;
                    case CommonUI.Data.TextBorderCount.Border:
                        this.Graphics.SetBorder(UIUtils.UInt32_RGBA_To_Color(ta.borderColor), new Vector2(1, 1));
                        break;
                    default:
                        this.Graphics.SetShadow(UIUtils.UInt32_RGBA_To_Color(ta.borderColor), UIUtils.ToTextBorderOffset(rg.Attribute.borderCount));
                        break;
                }
                this.Size2D = new Vector2(rg.Bounds.width, rg.Bounds.height);
                this.Position2D = new Vector2(rg.Bounds.x, rg.Bounds.y);
            }

            public float CharWidth { get { return this.Size2D.x; } }
            public float CharHeight { get { return this.Size2D.y; } }
            public void Render(CommonUI.Display.Graphics g, Region rg, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = true;
            }
            public void Hide(BaseRichTextLayer.Region self, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = false;
            }
        }
        //--------------------------------------------------------------------------------------------
        public class DrawImage : ImageSprite, Drawable
        {
            private TImageRegion image;
            private TextAttribute ta;
            private Vector2 csize;
            public DrawImage(UGUIRichTextLayer layer, Region rg, TImageRegion img)
                : base(string.Format("region {0}({1}-{2}):\"{3}\"", rg.Index, rg.CharStartIndex, rg.CharEndIndex, rg.Text))
            {
                this.ta = rg.Attribute;
                this.image = img;
                this.SetImage(img.image as UnityImage, new UnityEngine.Rect(img.sx, img.sy, img.sw, img.sh), new UnityEngine.Vector2(0, 0));
                this.Graphics.material = (img.image as UnityImage).TextureMaterial;
                if (rg.CharCount > 1)
                {
                    this.Graphics.type = UnityEngine.UI.Image.Type.Tiled;
                }
                else
                {
                    this.Graphics.type = UnityEngine.UI.Image.Type.Sliced;
                }
                if (ta.resImageZoom != null)
                {
                    this.Size2D = new Vector2(ta.resImageZoom.Width * rg.CharCount, ta.resImageZoom.Height);
                    this.csize = new Vector2(ta.resImageZoom.Width, ta.resImageZoom.Height);
                }
                else
                {
                    this.Size2D = new Vector2(image.sw * rg.CharCount, image.sh);
                    this.csize = new Vector2(image.sw, image.sh);
                }
                this.Position2D = new Vector2(rg.Bounds.x, rg.Bounds.y);
            }
            public float CharWidth { get { return csize.x; } }
            public float CharHeight { get { return csize.y; } }
            public void Render(CommonUI.Display.Graphics g, Region rg, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = true;
            }
            public void Hide(BaseRichTextLayer.Region self, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = false;
            }
        }
        //--------------------------------------------------------------------------------------------
        public class DrawSprite : CPJSprite, Drawable
        {
            private CCD bounds;

            public DrawSprite(UGUIRichTextLayer layer, Region rg, TSpriteMetaAnimateFrame spr)
                : base(string.Format("region {0}({1}-{2}):\"{3}\"", rg.Index, rg.CharStartIndex, rg.CharEndIndex, rg.Text))
            {
                this.bounds = spr.sprite.getVisibleBounds(spr.anim);
                this.SpriteMeta = spr.sprite;
                this.Controller.SetCurrentAnimate(spr.anim);
                if (rg.CharCount > 1)
                {
                    this.Graphics.drawType = CPJSpriteGraphics.DrawType.FillGrid;
                    this.Graphics.drawGridSize = new Vector2(bounds.Width, bounds.Height);
                }
                else
                {
                    this.Graphics.drawType = CPJSpriteGraphics.DrawType.Simple;
                }
                this.Size2D = new Vector2(bounds.Width * rg.CharCount, bounds.Height);
                this.Position2D = new Vector2(rg.Bounds.x, rg.Bounds.y);
            }
            public float CharWidth { get { return bounds.Width; } }
            public float CharHeight { get { return bounds.Height; } }
            public void Render(CommonUI.Display.Graphics g, Region rg, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = true;
            }
            public void Hide(BaseRichTextLayer.Region self, float x, float y)
            {
                this.Position2D = new Vector2(x, y);
                this.VisibleInParent = false;
            }
        }

        #endregion
        //--------------------------------------------------------------------------------------------

    }


}