using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.ComponentModel;
namespace DevComponents.DotNetBar
{
    /// 
    /// Represents toast display control. This class is not for public use.
    /// 
    [ToolboxItem(false), EditorBrowsable(EditorBrowsableState.Never)]
    public class ToastDisplay : Control
    {
        private const int GlowSize = 4;
        private readonly Size TextPadding = new Size(4, 4);
        #region Constructor
        /// 
        /// Initializes a new instance of the ToastDisplay class.
        /// 
        public ToastDisplay()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint
                        | ControlStyles.OptimizedDoubleBuffer
                        | ControlStyles.UserPaint
                        | ControlStyles.SupportsTransparentBackColor, true);
            this.ForeColor = Color.White;
        }
        protected override void Dispose(bool disposing)
        {
            if (_BackgroundImage != null)
            {
                _BackgroundImage.Dispose();
                _BackgroundImage = null;
            }
            base.Dispose(disposing);
        }
        #endregion
        #region Implementation
        protected override void OnPaint(PaintEventArgs e)
        {
            BufferedGraphicsContext context = new BufferedGraphicsContext();
            using (Bitmap canvas = new Bitmap(this.Width, this.Height, e.Graphics))
            {
                Graphics g = Graphics.FromImage(canvas);
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                Color glowColor = GetGlowColor(_GlowColor);
                Rectangle r = this.ClientRectangle;
                Color back = _ToastBackColor;
                r.Inflate(-3, -3);
                if (!glowColor.IsEmpty)
                {
                    for (int i = 0; i < GlowSize; i++)
                    {
                        using (Pen pen = new Pen(glowColor, 5))
                        {
                            pen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
                            g.DrawRectangle(pen, r);
                        }
                        r.Inflate(-1, -1);
                    }
                }
                r = this.ClientRectangle;
                r.Inflate(-GlowSize, -GlowSize);
                using (Pen pen = new Pen(_ToastBackColor, 5))
                {
                    pen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
                    r.Inflate(-3, -3);
                    g.DrawRectangle(pen, r);
                }
                DisplayHelp.FillRectangle(g, r, _ToastBackColor);
                r = this.ClientRectangle;
                r.Inflate(-(TextPadding.Width + GlowSize), -(TextPadding.Height + GlowSize));
                if (_Image != null)
                {
                    if (_ImageBox != null)
                    {
                        _ImageBox.Bounds = new Rectangle(r.Location, _Image.Size);
                    }
                    else
                        g.DrawImage(_Image, r.Location);
                    r.X += _Image.Width + TextPadding.Width;
                    r.Width -= _Image.Width + TextPadding.Width;
                }
                if (r.Width > 1)
                {
                    if (_TextMarkup == null)
                    {
                        eTextFormat format = TextFormat;
                        if (this.RightToLeft == RightToLeft.Yes) format |= eTextFormat.RightToLeft;
                        //TextDrawing.DrawString(g, Text, this.Font, this.ForeColor, r, format);
                        TextRenderer.DrawText(g, Text, Font, r, this.ForeColor, _ToastBackColor);
                    }
                    else
                    {
                        TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, this.ForeColor,
                            (this.RightToLeft == RightToLeft.Yes), r, true);
                        _TextMarkup.Arrange(r, d);
                        _TextMarkup.Render(d);
                    }
                }
                g.Dispose();
                if (_Alpha == 255)
                {
                    e.Graphics.DrawImage(canvas, 0, 0);
                }
                else
                {
                    ColorMatrix matrix = new ColorMatrix();
                    matrix.Matrix33 = _Alpha / 255f;
                    using (ImageAttributes imageAtt = new ImageAttributes())
                    {
                        imageAtt.SetColorMatrix(matrix);
                        e.Graphics.DrawImage(canvas, new Rectangle(0, 0, canvas.Width, canvas.Height), 0, 0, canvas.Width, canvas.Height, GraphicsUnit.Pixel, imageAtt);
                    }
                }
            }
            base.OnPaint(e);
        }
        internal Size DesiredSize(Padding margin, Rectangle parentBounds)
        {
            parentBounds.Width -= margin.Horizontal;
            parentBounds.Height -= margin.Vertical;
            parentBounds.Width -= GlowSize + TextPadding.Width * 2;
            parentBounds.Height -= GlowSize + TextPadding.Height * 2;
            Size desiredSize = new Size(GlowSize * 2 + TextPadding.Width * 2, GlowSize * 2 + TextPadding.Height * 2);
            using (Graphics g = this.CreateGraphics())
            {
                if (_TextMarkup != null)
                {
                    TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, Color.Black, (this.RightToLeft == RightToLeft.Yes));
                    _TextMarkup.Measure(new Size(parentBounds.Width, 1), d);
                    Size textSize = _TextMarkup.Bounds.Size;
                    _TextMarkup.Arrange(new Rectangle(Point.Empty, new Size(parentBounds.Width, 1)), d);
                    textSize = _TextMarkup.Bounds.Size;
                    if (_Image != null)
                    {
                        textSize.Width += _Image.Width + TextPadding.Width;
                        textSize.Height = Math.Max(_Image.Height, textSize.Height);
                    }
                    desiredSize.Width += textSize.Width;
                    desiredSize.Height += textSize.Height;
                }
                else
                {
                    //Size textSize = TextDrawing.MeasureString(g, Text, this.Font, parentBounds.Size, TextFormat);
                    Size textSize = TextRenderer.MeasureText(Text, this.Font, parentBounds.Size, TextFormatFlags.WordBreak);
                    if (_Image != null)
                    {
                        textSize.Width += _Image.Width + TextPadding.Width;
                        textSize.Height = Math.Max(_Image.Height, textSize.Height);
                    }
                    desiredSize.Width += textSize.Width;
                    desiredSize.Height += textSize.Height;
                }
            }
            return desiredSize;
        }
        private eTextFormat TextFormat
        {
            get
            {
                return eTextFormat.Default | eTextFormat.WordBreak | eTextFormat.VerticalCenter;
            }
        }
        private int _Alpha = 255;
        /// 
        /// Specifies the alpha-blending, opacity for the content rendered by the control. Setting this property allows fading in and out of the control content.
        /// 
        [System.Reflection.Obfuscation(Exclude = true, ApplyToMembers = false)]
        public int Alpha
        {
            get { return _Alpha; }
            set
            {
                if (value == _Alpha) return;
                if (value < 0) value = 0; else if (value > 255) value = 255;
                _Alpha = value;
                if (_Alpha == 0 && _BackgroundImage != null)
                {
                    _BackgroundImage.Dispose();
                    _BackgroundImage = null;
                }
                if (this.IsHandleCreated)
                {
                    this.Invalidate();
                }
            }
        }
        private Color GetGlowColor(eToastGlowColor glowColor)
        {
            if (glowColor == eToastGlowColor.Blue)
                return ColorScheme.GetColor(32, 0x0070C0); // Color.FromArgb(48, Color.Blue);
            else if (glowColor == eToastGlowColor.Green)
                return Color.FromArgb(32, Color.Green);
            else if (glowColor == eToastGlowColor.Orange)
                return Color.FromArgb(32, Color.Orange);
            else if (glowColor == eToastGlowColor.Red)
                return Color.FromArgb(32, Color.Red);
            else if (glowColor == eToastGlowColor.None)
                return Color.Empty;
            else if (glowColor == eToastGlowColor.Custom)
                return ToastNotification.CustomGlowColor;
            return Color.FromArgb(50, Color.Red);
        }
        private Image _BackgroundImage = null;
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            if (_BackgroundImage != null) // Background image is cached during animation to improve performance its disposed once animation is done
            {
                pevent.Graphics.DrawImage(_BackgroundImage, Point.Empty);
                if (_Alpha == 255)
                {
                    _BackgroundImage.Dispose();
                    _BackgroundImage = null;
                }
                return;
            }
            if (_Alpha != 255 && _BackgroundImage == null && this.Width > 0 && this.Height > 0) // Create cached background image to improve performance on subsequent rendering
            {
                _BackgroundImage = new Bitmap(this.Width, this.Height, pevent.Graphics);
                using (Graphics g = Graphics.FromImage(_BackgroundImage))
                {
                    PaintEventArgs pe = new PaintEventArgs(g, pevent.ClipRectangle);
                    base.OnPaintBackground(pe);
                    PaintParentControlOnBackground(g);
                }
                pevent.Graphics.DrawImage(_BackgroundImage, Point.Empty);
                return;
            }
            base.OnPaintBackground(pevent);
            PaintParentControlOnBackground(pevent.Graphics);
        }
        private void PaintParentControlOnBackground(Graphics g)
        {
            if (this.Parent != null)
            {
                for (int i = this.Parent.Controls.Count - 1; i >= 0; i--)
                {
                    Control ctrl = this.Parent.Controls[i];
                    if (!(ctrl is ToastDisplay) && ctrl.Visible && ctrl.Bounds.IntersectsWith(this.Bounds) && ctrl.Bounds.Width > 0 && ctrl.Bounds.Height > 0)
                    {
                        using (Bitmap bmp = new Bitmap(ctrl.Width, ctrl.Height, g))
                        {
                            ctrl.DrawToBitmap(bmp, ctrl.ClientRectangle);
                            g.TranslateTransform(ctrl.Left - Left, ctrl.Top - Top);
                            g.DrawImage(bmp, Point.Empty);
                            g.TranslateTransform(Left - ctrl.Left, Top - ctrl.Top);
                        }
                    }
                }
            }
        }
        private TextMarkup.BodyElement _TextMarkup = null;
        protected override void OnTextChanged(EventArgs e)
        {
            string text = this.Text;
            if (TextMarkup.MarkupParser.IsMarkup(ref text))
            {
                _TextMarkup = TextMarkup.MarkupParser.Parse(text);
            }
            else
                _TextMarkup = null;
            this.Invalidate();
            base.OnTextChanged(e);
        }
        private Color _ToastBackColor = Color.FromArgb(7, 7, 7);
        /// 
        /// Gets or sets the toast background color.
        /// 
        public Color ToastBackColor
        {
            get { return _ToastBackColor; }
            set { _ToastBackColor = value; }
        }
        private eToastGlowColor _GlowColor = eToastGlowColor.Blue;
        /// 
        /// Gets or sets the toast glow color.
        /// 
        public eToastGlowColor GlowColor
        {
            get { return _GlowColor; }
            set { _GlowColor = value; }
        }
        private PictureBox _ImageBox = null;
        private Image _Image = null;
        /// 
        /// Gets or sets the image displayed on the toast.
        /// 
        public Image Image
        {
            get { return _Image; }
            set
            {
                _Image = value; this.Invalidate();
                bool animatedGif = false;
                if (_Image != null && _Image.RawFormat.Equals(ImageFormat.Gif))
                {
                    Guid[] dimensions = _Image.FrameDimensionsList;
                    foreach (Guid guid in dimensions)
                    {
                        FrameDimension dimension = new FrameDimension(guid);
                        if (dimension.Equals(FrameDimension.Time))
                        {
                            animatedGif = _Image.GetFrameCount(FrameDimension.Time) > 1;
                            break;
                        }
                    }
                }
                if (animatedGif)
                {
                    if (_ImageBox == null)
                    {
                        _ImageBox = new PictureBox();
                        _ImageBox.Image = _Image;
                        this.Controls.Add(_ImageBox);
                    }
                }
                else if (_ImageBox != null)
                {
                    this.Controls.Remove(_ImageBox);
                    _ImageBox.Dispose();
                }
            }
        }
        public eToastPosition? ToastPosition { get; set; }
        #endregion
    }
}