using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Telerik.Windows.Controls.Charting;

namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            RadChart1.DefaultView.ChartArea.AxisX.LayoutMode = AxisLayoutMode.Inside;
            RadChart1.DefaultView.ChartArea.AxisY.IsZeroBased = true;
            RadChart1.DefaultView.ChartArea.AxisY.AutoRange = false;
            RadChart1.DefaultView.ChartArea.AxisY.AddRange(0, 20, 1);

            SeriesMapping mapping = new SeriesMapping();
            mapping.SeriesDefinition = new ScatterErrorBarSeriesDefinition()
            {
                PointSize = 12,
                ItemStyle = this.LayoutRoot.Resources["CustomScatterPointStyle"] as Style
            };

            mapping.ItemMappings.Add(new ItemMapping("YValue", DataPointMember.YValue));
            RadChart1.SeriesMappings.Add(mapping);
            RadChart1.ItemsSource = GetData();
        }

        private static List<ChartData> GetData()
        {
            List<ChartData> data = new List<ChartData>();
            data.Add(new ChartData() { YValue = 10, MinValue = 7, MaxValue = 12 });
            data.Add(new ChartData() { YValue = 6, MinValue = 4, MaxValue = 8 });
            data.Add(new ChartData() { YValue = 5, MinValue = 2, MaxValue = 7 });
            data.Add(new ChartData() { YValue = 13, MinValue = 12, MaxValue = 14 });

            return data;
        }
    }

    public class ScatterErrorBarSeriesDefinition : ScatterSeriesDefinition
    {
        public override IChartItem CreateChartItem()
        {
            return new ScatterErrorBar();
        }
    }

    public class ScatterErrorBar : ScatterPoint
    {
        /// <summary>
        /// Identifies the <see cref="MinValueY"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty MinValueYProperty = DependencyProperty.Register("MinValueY",
            typeof(double),
            typeof(ScatterErrorBar),
            new PropertyMetadata(0d));

        /// <summary>
        /// Identifies the <see cref="MaxValueY"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty MaxValueYProperty = DependencyProperty.Register("MaxValueY",
            typeof(double),
            typeof(ScatterErrorBar),
            new PropertyMetadata(0d));

        /// <summary>
        /// Gets or sets the MaxValueY.
        /// </summary>
        [Description("Gets or sets the MaxValueY")]
        public double MaxValueY
        {
            get
            {
                return (double)this.GetValue(MaxValueYProperty);
            }
            set
            {
                this.SetValue(MaxValueYProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the MinValueY.
        /// </summary>
        [Description("Gets or sets the MinValueY")]
        public double MinValueY
        {
            get
            {
                return (double)this.GetValue(MinValueYProperty);
            }
            set
            {
                this.SetValue(MinValueYProperty, value);
            }
        }

        protected override void CreatePoints(Size arrangedBounds)
        {
            base.CreatePoints(arrangedBounds);

            this.MinValueY = this.CalculateMinValueY(arrangedBounds);
            this.MaxValueY = this.CalculateMaxValueY(arrangedBounds);
        }

        private double CalculateMinValueY(Size arrangedBounds)
        {
            double minValue = (this.DataPoint.DataItem as ChartData).MinValue;
            DataRange minRange = this.CalculateRange(minValue) * arrangedBounds.Height;

            return minRange.From;
        }

        private double CalculateMaxValueY(Size arrangedBounds)
        {
            double maxValue = (this.DataPoint.DataItem as ChartData).MaxValue;
            DataRange maxRange = this.CalculateRange(maxValue) * arrangedBounds.Height;

            return maxRange.From;
        }

        private DataRange CalculateRange(double value)
        {
            DataRange axisRange = new DataRange(this.ChartArea.AxisY.ActualMinValue, this.ChartArea.AxisY.ActualMaxValue);

            double itemY = axisRange.Normalize(value);
            double zero = axisRange.Normalize(0d);
            DataRange restrictedRange = new DataRange(DataRange.Unit.Restrict(zero), itemY);

            return DataRange.Unit.Invert(restrictedRange);
        }
    }

    public class ChartData
    {
        public double YValue
        {
            get;
            set;
        }

        public double MinValue
        {
            get;
            set;
        }

        public double MaxValue
        {
            get;
            set;
        }
    }
}
