// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CandleStickSeriesExamples.cs" company="OxyPlot">
//   Copyright (c) 2014 OxyPlot contributors
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace ExampleLibrary
{
    using System;
    using System.Linq;

    using OxyPlot;
    using OxyPlot.Axes;
    using OxyPlot.Series;

    [Examples("CandleStickSeries"), Tags("Series")]
    public static class CandleStickSeriesExamples
    {
        [Example("Large Data Set (wide window)")]
        public static Example LargeDataSetWide()
        {
            var pm = new PlotModel { Title = "Large Data Set (wide window)" };

            var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom };
            pm.Axes.Add(timeSpanAxis1);
            var linearAxis1 = new LinearAxis { Position = AxisPosition.Left };
            pm.Axes.Add(linearAxis1);
            var series = new CandleStickSeries
            {
                Color = OxyColors.Black,
                IncreasingColor = OxyColors.DarkGreen,
                DecreasingColor = OxyColors.Red,
                DataFieldX = "Time",
                DataFieldHigh = "H",
                DataFieldLow = "L",
                DataFieldOpen = "O",
                DataFieldClose = "C",
                TrackerFormatString = "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}",
            };

            var n = 1000000;
            foreach (var bar in HighLowItemGenerator.MRProcess(n))
            {
                series.Append(bar);
            }

            timeSpanAxis1.Minimum = series.Items[n - 200].X;
            timeSpanAxis1.Maximum = series.Items[n - 130].X;

            linearAxis1.Minimum = series.Items.Skip(n - 200).Take(70).Select(x => x.Low).Min();
            linearAxis1.Maximum = series.Items.Skip(n - 200).Take(70).Select(x => x.High).Max();

            pm.Series.Add(series);

            timeSpanAxis1.AxisChanged += (sender, e) => AdjustYExtent(series, timeSpanAxis1, linearAxis1);

            var controller = new PlotController();
            controller.UnbindAll();
            controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt);
            return new Example(pm, controller);
        }

        [Example("Large Data Set (narrow window)")]
        public static Example LargeDataSetNarrow()
        {
            var pm = new PlotModel { Title = "Large Data Set (narrow window)" };

            var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom };
            pm.Axes.Add(timeSpanAxis1);
            var linearAxis1 = new LinearAxis { Position = AxisPosition.Left };
            pm.Axes.Add(linearAxis1);
            var series = new CandleStickSeries
            {
                Color = OxyColors.Black,
                IncreasingColor = OxyColors.DarkGreen,
                DecreasingColor = OxyColors.Red,
                DataFieldX = "Time",
                DataFieldHigh = "H",
                DataFieldLow = "L",
                DataFieldOpen = "O",
                DataFieldClose = "C",
                TrackerFormatString = "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}",
            };

            var n = 1000000;
            foreach (var bar in HighLowItemGenerator.MRProcess(n))
            {
                series.Append(bar);
            }

            timeSpanAxis1.Minimum = series.Items[0].X;
            timeSpanAxis1.Maximum = series.Items[29].X;

            linearAxis1.Minimum = series.Items.Take(30).Select(x => x.Low).Min();
            linearAxis1.Maximum = series.Items.Take(30).Select(x => x.High).Max();

            pm.Series.Add(series);

            timeSpanAxis1.AxisChanged += (sender, e) => AdjustYExtent(series, timeSpanAxis1, linearAxis1);

            var controller = new PlotController();
            controller.UnbindAll();
            controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt);
            return new Example(pm, controller);
        }

        [Example("Small Set")]
        public static Example SmallDataSet()
        {
            var pm = new PlotModel { Title = "Small Data Set" };

            var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom };
            pm.Axes.Add(timeSpanAxis1);
            var linearAxis1 = new LinearAxis { Position = AxisPosition.Left };
            pm.Axes.Add(linearAxis1);
            var series = new CandleStickSeries
            {
                Color = OxyColors.Black,
                IncreasingColor = OxyColors.DarkGreen,
                DecreasingColor = OxyColors.Red,
                DataFieldX = "Time",
                DataFieldHigh = "H",
                DataFieldLow = "L",
                DataFieldOpen = "O",
                DataFieldClose = "C",
                TrackerFormatString = "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}",
            };

            var n = 100;
            foreach (var bar in HighLowItemGenerator.MRProcess(n))
            {
                series.Append(bar);
            }

            pm.Series.Add(series);

            timeSpanAxis1.AxisChanged += (sender, e) => AdjustYExtent(series, timeSpanAxis1, linearAxis1);

            var controller = new PlotController();
            controller.UnbindAll();
            controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt);
            return new Example(pm, controller);
        }

        /// <summary>
        /// Adjusts the Y extent.
        /// </summary>
        /// <param name="series">Series.</param>
        /// <param name="xaxis">Xaxis.</param>
        /// <param name="yaxis">Yaxis.</param>
        private static void AdjustYExtent(CandleStickSeries series, DateTimeAxis xaxis, LinearAxis yaxis)
        {
            var xmin = xaxis.ActualMinimum;
            var xmax = xaxis.ActualMaximum;

            var istart = series.FindByX(xmin);
            var iend = series.FindByX(xmax, istart);

            var ymin = double.MaxValue;
            var ymax = double.MinValue;
            for (int i = istart; i <= iend; i++)
            {
                var bar = series.Items[i];
                ymin = Math.Min(ymin, bar.Low);
                ymax = Math.Max(ymax, bar.High);
            }

            var extent = ymax - ymin;
            var margin = extent * 0.10;

            yaxis.Zoom(ymin - margin, ymax + margin);
        }
    }
}