using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
    #region ChartMajorGridLines
    #region ChartMajorGridLinesX
    /// 
    /// Represents a chart's MajorGridLines for the X-Axis.
    /// 
    public class ChartMajorGridLinesX : ChartMajorGridLines
    {
        public ChartMajorGridLinesX()
            : base(AxisOrientation.X)
        {
        }
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            if (Visible == true)
            {
                TickmarkTick[] ticks = TickmarkLayout.Ticks;
                if (ticks != null)
                {
                    Graphics g = renderInfo.Graphics;
                    ChartAxis axis = Parent as ChartAxis;
                    ChartXy chartXy = axis.Parent as ChartXy;
                    PieGridLineVisualStyle gstyle = EffectiveStyle;
                    Rectangle scContentBounds = GetScrollBounds(chartXy.ContentBounds);
                    if (gstyle.LinePattern != LinePattern.None &&
                        gstyle.LinePattern != LinePattern.NotSet && gstyle.LineWidth > 0)
                    {
                        using (Pen pen = new Pen(gstyle.LineColor, Dpi.Width(gstyle.LineWidth)))
                        {
                            pen.DashStyle = (DashStyle)gstyle.LinePattern;
                            Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
                            foreach (TickmarkTick tmi in ticks)
                            {
                                Point pt1 = tmi.TickPoint;
                                pt1.X += pt.X;
                                pt1.Y = scContentBounds.Y;
                                Point pt2 = pt1;
                                pt2.Y = scContentBounds.Bottom;
                                g.DrawLine(pen, pt1, pt2);
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #region Copy/CopyTo
        /// 
        /// Create a copy of the MajorGridLine.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            ChartMajorGridLinesX copy = new ChartMajorGridLinesX();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the MajorGridLine to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            ChartMajorGridLinesX c = copy as ChartMajorGridLinesX;
            if (c != null)
                base.CopyTo(c);
        }
        #endregion
    }
    #endregion
    #region ChartMajorGridLinesY
    /// 
    /// Represents a chart's MajorGridLines for the Y-Axis.
    /// 
    public class ChartMajorGridLinesY : ChartMajorGridLines
    {
        public ChartMajorGridLinesY()
            : base(AxisOrientation.Y)
        {
        }
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            if (Visible == true)
            {
                TickmarkTick[] ticks = TickmarkLayout.Ticks;
                if (ticks != null)
                {
                    Graphics g = renderInfo.Graphics;
                    ChartAxis axis = Parent as ChartAxis;
                    ChartXy chartXy = axis.Parent as ChartXy;
                    PieGridLineVisualStyle gstyle = EffectiveStyle;
                    Rectangle scContentBounds = GetScrollBounds(chartXy.ContentBounds);
                    if (gstyle.LinePattern != LinePattern.None &&
                        gstyle.LinePattern != LinePattern.NotSet && gstyle.LineWidth > 0)
                    {
                        using (Pen pen = new Pen(gstyle.LineColor, Dpi.Height(gstyle.LineWidth)))
                        {
                            pen.DashStyle = (DashStyle)gstyle.LinePattern;
                            Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
                            foreach (TickmarkTick tmi in ticks)
                            {
                                Point pt1 = tmi.TickPoint;
                                pt1.X = scContentBounds.X;
                                pt1.Y += pt.Y;
                                Point pt2 = pt1;
                                pt2.X = scContentBounds.Right;
                                g.DrawLine(pen, pt1, pt2);
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #region Copy/CopyTo
        /// 
        /// Create a copy of the MajorGridLine.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            ChartMajorGridLinesY copy = new ChartMajorGridLinesY();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the MajorGridLine to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            ChartMajorGridLinesY c = copy as ChartMajorGridLinesY;
            if (c != null)
                base.CopyTo(c);
        }
        #endregion
    }
    #endregion
    #region ChartMajorGridLines
    /// 
    /// Represents a chart's MajorGridLines.
    /// 
    public class ChartMajorGridLines : ChartGridLines
    {
        public ChartMajorGridLines(AxisOrientation orientation)
            : base(orientation)
        {
        }
    }
    #endregion
    #endregion
    #region ChartMinorGridLines
    #region ChartMinorGridLinesX
    public class ChartMinorGridLinesX : ChartMinorGridLines
    {
        public ChartMinorGridLinesX()
            : base(AxisOrientation.X)
        {
        }
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            if (Visible == true)
            {
                TickmarkTick[] ticks = TickmarkLayout.Ticks;
                if (ticks != null && ticks.Length > 1)
                {
                    Graphics g = renderInfo.Graphics;
                    ChartAxis axis = Parent as ChartAxis;
                    ChartXy chartXy = axis.Parent as ChartXy;
                    PieGridLineVisualStyle gstyle = EffectiveStyle;
                    Rectangle scContentBounds = GetScrollBounds(chartXy.ContentBounds);
                    if (gstyle.LinePattern != LinePattern.None &&
                        gstyle.LinePattern != LinePattern.NotSet && gstyle.LineWidth > 0)
                    {
                        using (Pen pen = new Pen(gstyle.LineColor, Dpi.Width(gstyle.LineWidth)))
                        {
                            pen.DashStyle = (DashStyle)gstyle.LinePattern;
                            int minorTickCount = axis.MinorTickmarks.TickmarkCount;
                            Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
                            for (int i = 0; i < ticks.Length - 1; i++)
                            {
                                TickmarkTick tick = ticks[i];
                                Point pt1 = tick.TickPoint;
                                pt1.Y = scContentBounds.Y;
                                Point pt2 = pt1;
                                pt2.Y = scContentBounds.Bottom;
                                double dx = (double)(ticks[i + 1].TickPoint.X - tick.TickPoint.X) / (minorTickCount + 1);
                                double ddx = dx;
                                for (int j = 0; j < minorTickCount; j++)
                                {
                                    pt1.X = pt.X + (int)(tick.TickPoint.X + ddx);
                                    pt2.X = pt1.X;
                                    ddx += dx;
                                    g.DrawLine(pen, pt1, pt2);
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #region Copy/CopyTo
        /// 
        /// Create a copy of the MinorGridLine.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            ChartMinorGridLinesX copy = new ChartMinorGridLinesX();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the MinorGridLine to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            ChartMinorGridLinesX c = copy as ChartMinorGridLinesX;
            if (c != null)
                base.CopyTo(c);
        }
        #endregion
    }
    #endregion
    #region ChartMinorGridLinesY
    public class ChartMinorGridLinesY : ChartMinorGridLines
    {
        public ChartMinorGridLinesY()
            : base(AxisOrientation.Y)
        {
        }
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
            if (Visible == true)
            {
                TickmarkTick[] ticks = TickmarkLayout.Ticks;
                if (ticks != null)
                {
                    Graphics g = renderInfo.Graphics;
                    ChartAxis axis = Parent as ChartAxis;
                    ChartXy chartXy = axis.Parent as ChartXy;
                    PieGridLineVisualStyle gstyle = EffectiveStyle;
                    Rectangle scContentBounds = GetScrollBounds(chartXy.ContentBounds);
                    if (gstyle.LinePattern != LinePattern.None &&
                        gstyle.LinePattern != LinePattern.NotSet && gstyle.LineWidth > 0)
                    {
                        using (Pen pen = new Pen(gstyle.LineColor, Dpi.Height(gstyle.LineWidth)))
                        {
                            pen.DashStyle = (DashStyle)gstyle.LinePattern;
                            int minorTickCount = axis.MinorTickmarks.TickmarkCount;
                            Point pt = chartXy.GetLocalAdjustedPoint(Point.Empty);
                            for (int i = 0; i < ticks.Length - 1; i++)
                            {
                                TickmarkTick tick = ticks[i];
                                Point pt1 = tick.TickPoint;
                                pt1.X = scContentBounds.X;
                                Point pt2 = pt1;
                                pt2.X = scContentBounds.Right;
                                double dy = (double)(ticks[i + 1].TickPoint.Y - tick.TickPoint.Y) / (minorTickCount + 1);
                                double ddy = dy;
                                for (int j = 0; j < axis.MinorTickmarks.TickmarkCount; j++)
                                {
                                    pt1.Y = pt.Y + (int)(tick.TickPoint.Y + ddy);
                                    pt2.Y = pt1.Y;
                                    ddy += dy;
                                    g.DrawLine(pen, pt1, pt2);
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #region Copy/CopyTo
        /// 
        /// Create a copy of the MinorGridLine.
        /// 
        /// 
        public override ChartVisualElement Copy()
        {
            ChartMinorGridLinesY copy = new ChartMinorGridLinesY();
            CopyTo(copy);
            return (copy);
        }
        /// 
        /// Copies the MinorGridLine to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            ChartMinorGridLinesY c = copy as ChartMinorGridLinesY;
            if (c != null)
                base.CopyTo(c);
        }
        #endregion
    }
    #endregion
    #region ChartMinorGridLines
    public class ChartMinorGridLines : ChartGridLines
    {
        public ChartMinorGridLines(AxisOrientation orientation)
            : base(orientation)
        {
        }
    }
    #endregion
    #endregion
    #region ChartGridLines
    [TypeConverter(typeof(BlankExpandableObjectConverter))]
    public abstract class ChartGridLines : ChartVisualElement
    {
        #region Private variables
        private States _States;
        private AxisOrientation _AxisOrientation;
        private TickmarkLayout _TickmarkLayout;
        private PieGridLineVisualStyle _GridLinesVisualStyle;
        private EffectiveStyle _EffectiveStyle;
        #endregion
        public ChartGridLines(AxisOrientation orientation)
        {
            _AxisOrientation = orientation;
            InitDefaultStates();
            _EffectiveStyle = new EffectiveStyle(this);
        }
        #region InitDefaultStates
        private void InitDefaultStates()
        {
        }
        #endregion
        #region Public properties
        #region DisplayOnTop
        /// 
        /// Gets or sets whether grid lines are displayed on top of chart data.
        /// 
        [DefaultValue(false), Category("Appearance")]
        [Description("Indicates whether grid lines are displayed on top of chart data.")]
        public bool DisplayOnTop
        {
            get { return (TestState(States.DisplayOnTop)); }
            set
            {
                if (value != DisplayOnTop)
                {
                    SetState(States.DisplayOnTop, value);
                    OnPropertyChangedEx("DisplayOnTop", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region EffectiveStyles
        /// 
        /// Gets a reference to the GridLine's Effective (cached, composite) style.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public PieGridLineVisualStyle EffectiveStyle
        {
            get { return (_EffectiveStyle.Style); }
        }
        #endregion
        #region GridLinesVisualStyle
        /// 
        /// Gets or sets the visual style for the GridLines.
        /// 
        [Category("Style")]
        [Description("Indicates the visual style for the GridLines.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public PieGridLineVisualStyle GridLinesVisualStyle
        {
            get
            {
                if (_GridLinesVisualStyle == null)
                {
                    _GridLinesVisualStyle = new PieGridLineVisualStyle();
                    StyleVisualChangeHandler(null, _GridLinesVisualStyle);
                }
                return (_GridLinesVisualStyle);
            }
            set
            {
                if (_GridLinesVisualStyle != value)
                {
                    PieGridLineVisualStyle oldValue = _GridLinesVisualStyle;
                    _GridLinesVisualStyle = value;
                    OnVisualStyleChanged("GridLinesVisualStyle", oldValue, value);
                    if (oldValue != null)
                        oldValue.Dispose();
                }
            }
        }
        #endregion
        #endregion
        #region Internal properties
        #region TickmarkLayout
        internal TickmarkLayout TickmarkLayout
        {
            get { return (_TickmarkLayout); }
            set { _TickmarkLayout = value; }
        }
        #endregion
        #endregion
        #region MeasureOverride
        protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
        {
        }
        #endregion
        #region ArrangeOverride
        protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
        {
            BoundsRelative = layoutInfo.LayoutBounds;
        }
        #endregion
        #region RenderOverride
        protected override void RenderOverride(ChartRenderInfo renderInfo)
        {
        }
        #endregion
        #region Render
        internal override void Render(ChartRenderInfo renderInfo)
        {
            if (Displayed == true)
            {
                Rectangle bounds = BoundsRelative;
                if (renderInfo.ClipRectangle.IntersectsWith(bounds))
                    RenderOverride(renderInfo);
            }
        }
        #endregion
        #region Style handling
        #region ApplyStyles
        public override void ApplyStyles(BaseVisualStyle style)
        {
            PieGridLineVisualStyle sstyle = style as PieGridLineVisualStyle;
            if (sstyle != null)
            {
                ApplyParentStyles(sstyle, Parent as ChartContainer);
                sstyle.ApplyStyle(GridLinesVisualStyle);
                if (sstyle.LineColor.IsEmpty == true)
                {
                    if (this is ChartMajorGridLines)
                        sstyle.LineColor = Color.DimGray;
                    else
                        sstyle.LineColor = Color.LightGray;
                }
                if (sstyle.LinePattern == LinePattern.NotSet)
                    sstyle.LinePattern = LinePattern.Solid;
                if (sstyle.LineWidth < 0)
                    sstyle.LineWidth = 1;
            }
        }
        #region ApplyParentStyles
        private void ApplyParentStyles(PieGridLineVisualStyle pstyle, ChartContainer item)
        {
            if (item != null)
            {
                ApplyParentStyles(pstyle, item.Parent as ChartContainer);
                if (item is ChartPanel)
                {
                    pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.GridLineVisualStyle);
                }
            }
            else
            {
                pstyle.ApplyStyle(ChartControl.BaseVisualStyles.GridLineVisualStyle);
                pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.GridLineVisualStyle);
            }
        }
        #endregion
        #endregion
        #region ClearEffectiveStyles
        protected override void ClearEffectiveStyles()
        {
            base.ClearEffectiveStyles();
            if (_EffectiveStyle.InvalidateStyle() == true)
                InvalidateLayout();
        }
        #endregion
        #endregion
        #region Copy/CopyTo
        /// 
        /// Copies the chart element to the given "copy".
        /// 
        /// 
        public override void CopyTo(ChartVisualElement copy)
        {
            ChartGridLines c = copy as ChartGridLines;
            if (c != null)
            {
                base.CopyTo(c);
                c.DisplayOnTop = DisplayOnTop;
                c.GridLinesVisualStyle = (_GridLinesVisualStyle != null) ? GridLinesVisualStyle.Copy() : null;
            }
        }
        #endregion
        #region GetSerialData
        internal override SerialElementCollection GetSerialData(string serialName)
        {
            SerialElementCollection sec = new SerialElementCollection();
            if (serialName != null)
            {
                if (serialName.Equals("") == true)
                    serialName = "ChartGridLines";
                sec.AddStartElement(serialName);
            }
            sec.AddValue("DisplayOnTop", DisplayOnTop, false);
            if (_GridLinesVisualStyle != null && _GridLinesVisualStyle.IsEmpty == false)
                sec.AddElement(_GridLinesVisualStyle.GetSerialData("GridLinesVisualStyle"));
            sec.AddElement(base.GetSerialData(null));
            if (serialName != null)
                sec.AddEndElement(serialName);
            return (sec);
        }
        #endregion
        #region PutSerialData
        #region ProcessValue
        internal override void ProcessValue(SerialElement se)
        {
            switch (se.Name)
            {
                case "DisplayOnTop":
                    DisplayOnTop = bool.Parse(se.StringValue);
                    break;
                default:
                    base.ProcessValue(se);
                    break;
            }
        }
        #endregion
        #region ProcessCollection
        internal override void ProcessCollection(SerialElement se)
        {
            SerialElementCollection sec = se.Sec;
            switch (se.Name)
            {
                case "GridLinesVisualStyle":
                    sec.PutSerialData(GridLinesVisualStyle);
                    break;
                default:
                    base.ProcessCollection(se);
                    break;
            }
        }
        #endregion
        #endregion
        #region States
        [Flags]
        private enum States : uint
        {
            DisplayOnTop = (1U << 0),
        }
        #region TestState
        private bool TestState(States state)
        {
            return ((_States & state) == state);
        }
        #endregion
        #region SetState
        private void SetState(States state, bool value)
        {
            if (value == true)
                _States |= state;
            else
                _States &= ~state;
        }
        #endregion
        #endregion
        #region IDisposable
        public override void Dispose()
        {
            GridLinesVisualStyle = null;
            base.Dispose();
        }
        #endregion
    }
    #endregion
}