using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.Instrumentation.Primitives;
namespace DevComponents.Instrumentation
{
    /// 
    /// Collection of GaugeText items
    /// 
    public class GaugeTextCollection : GenericCollection
    {
    }
    public class GaugeText : GaugeItem
    {
        #region Private variables
        private string _Text;
        private SizeF _Size;
        private PointF _Location;
        private float _Angle;
        private Font _Font;
        private Font _AbsFont;
        private bool _AutoSize;
        private TextAlignment _TextAlignment;
        private Color _ForeColor;
        private GradientFillColor _BackColor;
        private Rectangle _Bounds;
        private Point _Center;
        private bool _UnderScale;
        private GaugeControl _GaugeControl;
        #endregion
        public GaugeText(GaugeControl gaugeControl)
            : this()
        {
            _GaugeControl = gaugeControl;
            InitGaugeText();
        }
        public GaugeText()
        {
            InitGaugeText();
        }
        #region InitGagueText
        private void InitGaugeText()
        {
            _Text = "Text";
            BackColor.BorderColor = Color.Black;
            _ForeColor = Color.Black;
            _Size = new SizeF(.2f, .2f);
            _Location = new PointF(.3f, .5f);
            _AutoSize = true;
            _TextAlignment = TextAlignment.MiddleCenter;
            _UnderScale = true;
        }
        #endregion
        #region Public properties
        #region Angle
        /// 
        /// Gets or sets the amount to rotate the text, specified in degrees.
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(0f)]
        [Editor("DevComponents.Instrumentation.Design.AngleRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Determines the amount to rotate the text, specified in degrees.")]
        public float Angle
        {
            get { return (_Angle); }
            set
            {
                if (_Angle != value)
                {
                    _Angle = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region AutoSize
        /// 
        /// Gets or sets whether the text Font size is auto sized
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(true)]
        [Editor("DevComponents.Instrumentation.Design.AngleRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates whether the text Font size is auto sized.")]
        public bool AutoSize
        {
            get { return (_AutoSize); }
            set
            {
                if (_AutoSize != value)
                {
                    _AutoSize = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region BackColor
        /// 
        /// Gets or sets the text BackColor
        /// 
        [Browsable(true), Category("Appearance")]
        [Description("Indicates the BackColor.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public GradientFillColor BackColor
        {
            get
            {
                if (_BackColor == null)
                {
                    _BackColor = new GradientFillColor();
                    _BackColor.ColorTableChanged += BackColor_ColorTableChanged;
                }
                return (_BackColor);
            }
            set
            {
                if (_BackColor != null)
                    _BackColor.ColorTableChanged -= BackColor_ColorTableChanged;
                _BackColor = value;
                if (_BackColor != null)
                    _BackColor.ColorTableChanged += BackColor_ColorTableChanged;
                OnGaugeItemChanged();
            }
        }
        #endregion
        #region Font
        /// 
        /// Gets or sets the text Font
        /// 
        [Browsable(true), Category("Appearance")]
        [Description("Indicates the text Font.")]
        public Font Font
        {
            get
            {
                if (_Font == null)
                    _Font = new Font("Microsoft SanSerif", 12);
                return (_Font);
            }
            set
            {
                if (_Font != null)
                    _Font.Dispose();
                _Font = value;
                AbsFont = null;
                OnGaugeItemChanged(true);
            }
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        internal virtual bool ShouldSerializeFont()
        {
            if (_Font == null)
                return (false);
            using (Font font = new Font("Microsoft SanSerif", 12))
                return (_Font.Equals(font) == false);
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        internal virtual void ResetFont()
        {
            Font = new Font("Microsoft SanSerif", 12);
        }
        #endregion
        #region ForeColor
        /// 
        /// Gets or sets the text ForeColor
        /// 
        [Browsable(true), Category("Appearance"), DefaultValue(typeof(Color), "Black")]
        [Description("Indicates the text ForeColor.")]
        public Color ForeColor
        {
            get { return (_ForeColor); }
            set
            {
                if (_ForeColor != value)
                {
                    _ForeColor = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region Location
        /// 
        /// Gets or sets the center location of the text area, specified as a percentage
        /// 
        [Browsable(true), Category("Layout")]
        [Editor("DevComponents.Instrumentation.Design.LocationEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the center location of the text area, specified as a percentage.")]
        [TypeConverter(typeof(PointFConverter))]
        public PointF Location
        {
            get { return (_Location); }
            set
            {
                if (_Location != value)
                {
                    _Location = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeLocation()
        {
            return (_Location.X != .3f || _Location.Y != .5f);
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetLocation()
        {
            _Location = new PointF(.3f, .5f);
        }
        #endregion
        #region Size
        /// 
        /// Gets or sets the size of the text area, specified as a percentage
        /// 
        [Browsable(true), Category("Layout")]
        [Editor("DevComponents.Instrumentation.Design.SizeEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the size of the text area, specified as a percentage.")]
        public SizeF Size
        {
            get { return (_Size); }
            set
            {
                if (_Size != value)
                {
                    _Size = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeSize()
        {
            return (_Size.Width != .2f || _Size.Height != .2f);
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetSize()
        {
            _Size = new SizeF(.2f, .2f);
        }
        #endregion
        #region Text
        /// 
        /// Gets or sets the text to be displayed
        /// 
        [Browsable(true), Category("Appearance"), DefaultValue("Text")]
        [Description("Indicates the text to be displayed.")]
        public string Text
        {
            get { return (_Text); }
            set
            {
                if (_Text != value)
                {
                    _Text = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region TextAlignment
        /// 
        /// Gets or sets the alignment of the text
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(TextAlignment.MiddleCenter)]
        [Description("Indicates the alignment of the text.")]
        public TextAlignment TextAlignment
        {
            get { return (_TextAlignment); }
            set
            {
                if (_TextAlignment != value)
                {
                    _TextAlignment = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region UnderScale
        /// 
        /// Gets or sets whether the text is displayed under the scale
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(true)]
        [Editor("DevComponents.Instrumentation.Design.AngleRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates whether the text is displayed under the scale.")]
        public bool UnderScale
        {
            get { return (_UnderScale); }
            set
            {
                if (_UnderScale != value)
                {
                    _UnderScale = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #endregion
        #region Internal properties
        #region AbsFont
        internal Font AbsFont
        {
            get
            {
                if (_AutoSize == false)
                    return (Font);
                if (_AbsFont == null)
                {
                    int n = (_GaugeControl.Frame.AutoCenter == true)
                        ? Math.Min(_GaugeControl.Width, _GaugeControl.Height) / 2
                        : Math.Max(_GaugeControl.Width, _GaugeControl.Height) / 3;
                    float emSize = Font.SizeInPoints;
                    emSize = (emSize / 170) * n;
                    AbsFont = new Font(_Font.FontFamily, emSize, _Font.Style);
                }
                return (_AbsFont);
            }
            set
            {
                if (_AbsFont != null)
                    _AbsFont.Dispose();
                _AbsFont = value;
            }
        }
        #endregion
        #region Bounds
        internal Rectangle Bounds
        {
            get { return (_Bounds); }
            set { _Bounds = value; }
        }
        #endregion
        #region GaugeControl
        internal GaugeControl GaugeControl
        {
            get { return (_GaugeControl); }
            set { _GaugeControl = value; }
        }
        #endregion
        #endregion
        #region Event processing
        void BackColor_ColorTableChanged(object sender, EventArgs e)
        {
            OnGaugeItemChanged(true);
        }
        #endregion
        #region RecalcLayout
        public override void RecalcLayout()
        {
            if (NeedRecalcLayout == true)
            {
                base.RecalcLayout();
                bool autoCenter = _GaugeControl.Frame.AutoCenter;
                Size size = _GaugeControl.GetAbsSize(_Size, autoCenter);
                if (size.Equals(_Bounds.Size) == false)
                    AbsFont = null;
                _Center = _GaugeControl.GetAbsPoint(_Location, autoCenter);
                _Bounds = new Rectangle(
                    _Center.X - size.Width / 2, _Center.Y - size.Height / 2,
                    size.Width, size.Height);
            }
        }
        #endregion
        #region OnPaint
        public override void OnPaint(PaintEventArgs e)
        {
            RecalcLayout();
            Graphics g = e.Graphics;
            if (_Bounds.Width > 0 && _Bounds.Height > 0)
            {
                g.TranslateTransform(_Center.X, _Center.Y);
                g.RotateTransform(_Angle % 360);
                Rectangle r = new Rectangle(0, 0, _Bounds.Width, _Bounds.Height);
                r.X -= _Bounds.Width / 2;
                r.Y -= _Bounds.Height / 2;
                if (_BackColor.Color1.IsEmpty == false)
                    PaintBackColor(e, r);
                if (_BackColor.BorderWidth > 0)
                {
                    using (Pen pen = new Pen(_BackColor.BorderColor, _BackColor.BorderWidth))
                        g.DrawRectangle(pen, r);
                }
                if (string.IsNullOrEmpty(_Text) == false)
                {
                    using (StringFormat sf = new StringFormat())
                    {
                        SetStringAlignment(sf);
                        if (_BackColor.BorderWidth > 0)
                            r.Inflate(-(_BackColor.BorderWidth + 1), -(_BackColor.BorderWidth + 1));
                        using (Brush br = new SolidBrush(_ForeColor))
                            g.DrawString(_Text, AbsFont, br, r, sf);
                    }
                }
                g.ResetTransform();
            }
        }
        #region PaintBackColor
        private void PaintBackColor(PaintEventArgs e, Rectangle r)
        {
            Graphics g = e.Graphics;
            GradientFillType fillType = _BackColor.GradientFillType;
            
            if (_BackColor.End.IsEmpty == true || (_BackColor.Color1 == _BackColor.Color2))
                fillType = GradientFillType.None;
            switch (fillType)
            {
                case GradientFillType.Auto:
                case GradientFillType.Angle:
                    using (Brush br = _BackColor.GetBrush(r))
                    {
                        if (br is LinearGradientBrush)
                            ((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipXY;
                        g.FillRectangle(br, r);
                    }
                    break;
                case GradientFillType.StartToEnd:
                    using (Brush br = _BackColor.GetBrush(r, 90))
                    {
                        if (br is LinearGradientBrush)
                            ((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipXY;
                        g.FillRectangle(br, r);
                    }
                    break;
                case GradientFillType.HorizontalCenter:
                    Rectangle t1 = r;
                    t1.Height /= 2;
                    using (LinearGradientBrush br = new
                        LinearGradientBrush(t1, _BackColor.Start, _BackColor.End, 90))
                    {
                        br.WrapMode = WrapMode.TileFlipXY;
                        g.FillRectangle(br, r);
                    }
                    break;
                case GradientFillType.VerticalCenter:
                    Rectangle t2 = r;
                    t2.Width /= 2;
                    using (LinearGradientBrush br = new
                        LinearGradientBrush(t2, _BackColor.Start, _BackColor.End, 0f))
                    {
                        br.WrapMode = WrapMode.TileFlipXY;
                        g.FillRectangle(br, r);
                    }
                    break;
                case GradientFillType.Center:
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddRectangle(r);
                        using (PathGradientBrush br = new PathGradientBrush(path))
                        {
                            br.CenterColor = _BackColor.Start;
                            br.SurroundColors = new Color[] {_BackColor.End};
                            g.FillRectangle(br, r);
                        }
                    }
                    break;
                default:
                    using (Brush br = new SolidBrush(_BackColor.Start))
                        g.FillRectangle(br, r);
                    break;
            }
        }
        #endregion
        #region SetStringAlignment
        private void SetStringAlignment(StringFormat sf)
        {
            switch (_TextAlignment)
            {
                case TextAlignment.TopLeft:
                    sf.LineAlignment = StringAlignment.Near;
                    sf.Alignment = StringAlignment.Near;
                    break;
                case TextAlignment.TopCenter:
                    sf.LineAlignment = StringAlignment.Near;
                    sf.Alignment = StringAlignment.Center;
                    break;
                case TextAlignment.TopRight:
                    sf.LineAlignment = StringAlignment.Near;
                    sf.Alignment = StringAlignment.Far;
                    break;
                case TextAlignment.MiddleLeft:
                    sf.LineAlignment = StringAlignment.Center;
                    sf.Alignment = StringAlignment.Near;
                    break;
                case TextAlignment.MiddleCenter:
                    sf.LineAlignment = StringAlignment.Center;
                    sf.Alignment = StringAlignment.Center;
                    break;
                case TextAlignment.MiddleRight:
                    sf.LineAlignment = StringAlignment.Center;
                    sf.Alignment = StringAlignment.Far;
                    break;
                case TextAlignment.BottomLeft:
                    sf.LineAlignment = StringAlignment.Far;
                    sf.Alignment = StringAlignment.Near;
                    break;
                case TextAlignment.BottomCenter:
                    sf.LineAlignment = StringAlignment.Far;
                    sf.Alignment = StringAlignment.Center;
                    break;
                case TextAlignment.BottomRight:
                    sf.LineAlignment = StringAlignment.Far;
                    sf.Alignment = StringAlignment.Far;
                    break;
            }
        }
        #endregion
        #endregion
        #region Contains
        internal bool Contains(Point pt)
        {
            if (Angle == 0)
            {
                return (_Bounds.Contains(pt));
            }
            
            using (GraphicsPath path = new GraphicsPath())
            {
                path.AddRectangle(Bounds);
                Matrix matrix = new Matrix();
                matrix.RotateAt(_Angle, _Center);
                path.Transform(matrix);
                return (path.IsVisible(pt));
            }
        }
        #endregion
        #region ICloneable Members
        public override object Clone()
        {
            GaugeText copy = new GaugeText();
            CopyToItem(copy);
            return (copy);
        }
        #endregion
        #region CopyToItem
        public override void CopyToItem(GaugeItem copy)
        {
            GaugeText c = copy as GaugeText;
            if (c != null)
            {
                base.CopyToItem(c);
                c.Angle = _Angle;
                c.AutoSize = _AutoSize;
                if (_BackColor != null)
                    c.BackColor = (GradientFillColor)_BackColor.Clone();
                if (_Font != null)
                    c.Font = (Font)_Font.Clone();
                c.ForeColor = _ForeColor;
                c.Location = _Location;
                c.Size = _Size;
                c.Text = _Text;
                c.TextAlignment = _TextAlignment;
                c.UnderScale = _UnderScale;
            }
        }
        #endregion
    }
    #region Enums
    public enum TextAlignment
    {
        TopLeft,
        TopCenter,
        TopRight,
        MiddleLeft,
        MiddleCenter,
        MiddleRight,
        BottomLeft,
        BottomCenter,
        BottomRight,
    }
    #endregion
}