using System;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace DevComponents.DotNetBar.Controls
{
    /// 
    /// Represents an single line of text label control with text-markup support and built-in reflection.
    /// 
    [ToolboxItem(true), Designer("DevComponents.DotNetBar.Design.ReflectionLabelDesigner, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf"), ToolboxBitmap(typeof(LabelX), "Controls.ReflectionLabel.ico")]
    public class ReflectionLabel : ControlWithBackgroundStyle
    {
        #region Private Variables
        private TextMarkup.BodyElement _TextMarkup = null;
        private Bitmap _ReflectionBitmap = null;
        private float _ReflectionFactor = .52f;
        private Size _TextSize = Size.Empty;
        #endregion
        #region Events
        /// 
        /// Occurs when text markup link is clicked. Markup links can be created using "a" tag, for example:
        /// Markup link
        /// 
        public event MarkupLinkClickEventHandler MarkupLinkClick;
        #endregion
        #region Constructor
        #endregion
        #region Internal Implementation
        protected override void Dispose(bool disposing)
        {
            DisposeReflectionImage();
            base.Dispose(disposing);
        }
        protected override void PaintContent(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            SmoothingMode sm = g.SmoothingMode;
            if (AntiAlias)
            {
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
            }
            Rectangle r = GetContentRectangle();
            Point reflectionLocation = r.Location;
            bool disposeStyle = false;
            ElementStyle style = this.GetBackgroundStyle(out disposeStyle);
            if (_TextMarkup != null)
            {
                TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, (style.TextColor.IsEmpty?this.ForeColor:style.TextColor), 
                    (this.RightToLeft == RightToLeft.Yes), Rectangle.Empty, true);
                if (!this.Enabled)
                {
                    d.IgnoreFormattingColors = true;
                    d.CurrentForeColor = SystemColors.ControlDark;
                }
                _TextMarkup.Render(d);
                reflectionLocation.Y = _TextMarkup.Bounds.Bottom;
                reflectionLocation.X = 0;
            }
            else
            {
                int totalHeight = (int)(_TextSize.Height * (1 + _ReflectionFactor));
                int y = r.Y, x = r.X;
                if (style.TextLineAlignment == eStyleTextAlignment.Center)
                {
                    y += (r.Height - totalHeight) / 2;
                }
                else if (style.TextLineAlignment == eStyleTextAlignment.Far)
                {
                    y += (r.Height - totalHeight);
                }
                TextDrawing.DrawString(g, this.Text, this.Font, (style.TextColor.IsEmpty ? this.ForeColor : style.TextColor), new Rectangle(x, y, r.Width, r.Height), GetTextFormat(style));
                reflectionLocation.Y = y + _TextSize.Height;
            }
            Rectangle rClip = new Rectangle(0, reflectionLocation.Y, this.Width, this.Height - reflectionLocation.Y);
            g.SetClip(rClip, CombineMode.Replace);
            int fontBaseOffset = (int)Math.Floor(Font.Size * Font.FontFamily.GetCellDescent(Font.Style) / Font.FontFamily.GetEmHeight(Font.Style));
            reflectionLocation.Y -= fontBaseOffset;
            if (_ReflectionBitmap != null && _ReflectionEnabled)
            {
                g.DrawImage(_ReflectionBitmap, reflectionLocation);
            }
            g.ResetClip();
            if (disposeStyle) style.Dispose();
            if (AntiAlias)
                g.SmoothingMode = sm;
        }
        protected override void OnTextChanged(EventArgs e)
        {
            UpdateDisplay();
            base.OnTextChanged(e);
        }
        protected override void OnFontChanged(EventArgs e)
        {
            UpdateDisplay();
            base.OnFontChanged(e);
        }
        protected override void OnForeColorChanged(EventArgs e)
        {
            UpdateDisplay();
            base.OnForeColorChanged(e);
        }
        protected override void OnVisualPropertyChanged()
        {
            UpdateDisplay();
            base.OnVisualPropertyChanged();
        }
        protected override void OnResize(EventArgs e)
        {
            UpdateDisplay();
            base.OnResize(e);
        }
        private void UpdateDisplay()
        {
            string text = this.Text;
            if (_TextMarkup != null)
            {
                _TextMarkup.MouseLeave(this);
                _TextMarkup.HyperLinkClick -= new EventHandler(TextMarkupLinkClicked);
                _TextMarkup = null;
            }
            if (TextMarkup.MarkupParser.IsMarkup(ref text))
                _TextMarkup = TextMarkup.MarkupParser.Parse(text);
            if (_TextMarkup != null)
            {
                _TextMarkup.HyperLinkClick += new EventHandler(TextMarkupLinkClicked);
            }
            CreateReflection();
            this.Invalidate();
        }
        private void CreateReflection()
        {
            DisposeReflectionImage();
            if (Text.Length == 0 || this.Width <= 0 || this.Height <= 0 || this.Font == null) return;
            // Create image based on the control content
            Bitmap bmp = null;
            if (_TextMarkup == null)
            {
                using(Graphics g = this.CreateGraphics())
                {
                    if (AntiAlias)
                    {
                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                    }
                    Size s = TextDrawing.MeasureString(g, this.Text, this.Font);
                    bmp = new Bitmap(this.Width, s.Height, PixelFormat.Format32bppArgb);
                    _TextSize = s;
                }
                bmp.MakeTransparent();
                Color transparentColor = Color.Empty;
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    bool disposeStyle = false;
                    ElementStyle style = this.GetBackgroundStyle(out disposeStyle);
                    
                    if (AntiAlias)
                    {
                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                        transparentColor = style.BackColor.IsEmpty ? this.BackColor : style.BackColor;
                        if (transparentColor.IsEmpty || transparentColor == Color.Transparent) transparentColor = Color.WhiteSmoke;
                        DisplayHelp.FillRectangle(g, new Rectangle(0, 0, bmp.Width, bmp.Height), transparentColor);
                    }
                    TextDrawing.DrawString(g, this.Text, this.Font, (style.TextColor.IsEmpty ? this.ForeColor : style.TextColor),
                        new Rectangle(0, 0, bmp.Width, bmp.Height), GetTextFormat(style));
                    if (disposeStyle) style.Dispose();
                }
                if (!transparentColor.IsEmpty)
                    bmp.MakeTransparent(transparentColor);
            }
            else
            {
                ResizeMarkup();
                if (_TextMarkup.Bounds.Height > 0)
                {
                    bmp = new Bitmap(this.Width, _TextMarkup.Bounds.Height, PixelFormat.Format32bppArgb);
                    Color transparentColor = Color.Empty;
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        bool disposeStyle = false;
                        ElementStyle style = this.GetBackgroundStyle(out disposeStyle);
                        if (AntiAlias)
                        {
                            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                            g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                            transparentColor = style.BackColor.IsEmpty ? this.BackColor : style.BackColor;
                            if (transparentColor.IsEmpty || transparentColor == Color.Transparent) transparentColor = Color.WhiteSmoke;
                            DisplayHelp.FillRectangle(g, new Rectangle(0, 0, bmp.Width, bmp.Height), transparentColor);
                        }
                        if (_TextMarkup.Bounds.Top > 0)
                            g.TranslateTransform(0, -(_TextMarkup.Bounds.Top - GetContentRectangle().Y));
                        TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, (style.TextColor.IsEmpty ? this.ForeColor : style.TextColor),
                        (this.RightToLeft == RightToLeft.Yes), Rectangle.Empty, true);
                        if (!this.Enabled)
                        {
                            d.IgnoreFormattingColors = true;
                            d.CurrentForeColor = SystemColors.ControlDark;
                        }
                        _TextMarkup.Render(d);
                        if (disposeStyle) style.Dispose();
                    }
                    if (!transparentColor.IsEmpty)
                        bmp.MakeTransparent(transparentColor);
                }
            }
            if (bmp != null)
            {
                _ReflectionBitmap = ImageHelper.CreateReflectionImage(bmp);
                bmp.Dispose();
            }
        }
        private eTextFormat GetTextFormat(ElementStyle style)
        {
            if (style.TextAlignment == eStyleTextAlignment.Center)
                return eTextFormat.HorizontalCenter;
            else if (style.TextAlignment == eStyleTextAlignment.Far)
                return eTextFormat.Right;
            return eTextFormat.Default;
        }
        private void DisposeReflectionImage()
        {
            if (_ReflectionBitmap != null)
            {
                _ReflectionBitmap.Dispose();
                _ReflectionBitmap = null;
            }
        }
        private void TextMarkupLinkClicked(object sender, EventArgs e)
        {
            TextMarkup.HyperLink link = sender as TextMarkup.HyperLink;
            if (link != null)
            {
                OnMarkupLinkClick(new MarkupLinkClickEventArgs(link.Name, link.HRef));
            }
        }
        protected virtual void OnMarkupLinkClick(MarkupLinkClickEventArgs e)
        {
            if (this.MarkupLinkClick != null)
                MarkupLinkClick(this, e);
        }
        protected virtual void ResizeMarkup()
        {
            if (_TextMarkup != null)
            {
                Rectangle r = this.GetContentRectangle();
                if (r.Width <= 0 || r.Height <= 0)
                    return;
                Graphics g = this.CreateGraphics();
                try
                {
                    if (AntiAlias)
                    {
                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                    }
                    TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, SystemColors.Control, (this.RightToLeft == RightToLeft.Yes));
                    Size measureSize = new Size(10000, r.Height);
                    _TextMarkup.Measure(measureSize, d);
                    bool disposeStyle = false;
                    ElementStyle style = this.GetBackgroundStyle(out disposeStyle);
                    int totalHeight = (int)(_TextMarkup.Bounds.Height * (1 + _ReflectionFactor));
                    if (totalHeight < r.Height)
                    {
                        if (style.TextLineAlignment == eStyleTextAlignment.Center)
                        {
                            r.Y += (r.Height - totalHeight) / 2;
                            r.Height = _TextMarkup.Bounds.Height;
                        }
                        else if (style.TextLineAlignment == eStyleTextAlignment.Far)
                        {
                            r.Y = (r.Bottom - totalHeight);
                            r.Height = _TextMarkup.Bounds.Height;
                        }
                    }
                    if (_TextMarkup.Bounds.Width < r.Width)
                    {
                        if (style.TextAlignment == eStyleTextAlignment.Center)
                        {
                            r.X += (r.Width - _TextMarkup.Bounds.Width) / 2;
                            r.Width = _TextMarkup.Bounds.Width;
                        }
                        else if (style.TextAlignment == eStyleTextAlignment.Far && this.RightToLeft == RightToLeft.No ||
                            style.TextAlignment == eStyleTextAlignment.Near && this.RightToLeft == RightToLeft.Yes)
                        {
                            r.X = (r.Right - _TextMarkup.Bounds.Width);
                            r.Width = _TextMarkup.Bounds.Width;
                        }
                    }
                    _TextMarkup.Arrange(r, d);
                    if (disposeStyle) style.Dispose();
                }
                finally
                {
                    g.Dispose();
                }
            }
        }
        protected override void OnEnabledChanged(EventArgs e)
        {
            CreateReflection();
            this.Invalidate();
            base.OnEnabledChanged(e);
        }
        protected override Size DefaultSize
        {
            get
            {
                return new Size(175, 70);
            }
        }
        private bool _ReflectionEnabled = true;
        /// 
        /// Gets or sets whether reflection effect is enabled. Default value is true.
        /// 
        [DefaultValue(true), Description("Indicates whether reflection effect is enabled.")]
        public bool ReflectionEnabled
        {
            get { return _ReflectionEnabled; }
            set
            {
                if (_ReflectionEnabled != value)
                {
                    _ReflectionEnabled = value;
                    this.Invalidate();
                }
            }
        }
        #endregion
        #region Property hiding
        [Browsable(false)]
        public override Image BackgroundImage
        {
            get
            {
                return base.BackgroundImage;
            }
            set
            {
                base.BackgroundImage = value;
            }
        }
#if FRAMEWORK20
		[Browsable(false)]
        public override ImageLayout BackgroundImageLayout
        {
            get
            {
                return base.BackgroundImageLayout;
            }
            set
            {
                base.BackgroundImageLayout = value;
            }
        }
        [Browsable(false)]
        public new System.Windows.Forms.Padding Padding
        {
            get
            {
                return base.Padding;
            }
            set
            {
                base.Padding = value;
            }
        }
#endif
        [Browsable(true), DefaultValue(""), Editor("DevComponents.DotNetBar.Design.TextMarkupUIEditor, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf", typeof(System.Drawing.Design.UITypeEditor)), EditorBrowsable(EditorBrowsableState.Always), Category("Appearance"), Description("Gets or sets the text displayed on label.")]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }
        #endregion
    }
}