using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

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

            // create some random data
            var list = new List<ProductData>();
            var sales = 10;
            var downloads = 100;
            var revisions = 0;
            var rnd = new Random();
            for (var month = DateTime.Today.AddYears(-150); month <= DateTime.Today; month = month.AddMonths(1))
            {
                var sd = new ProductData();
                sd.ProductName = "Widgets";
                sd.Month = month;
                sd.Sales = sales;
                sd.Downloads = downloads;
                sd.Revisions = revisions;
                list.Add(sd);

                sales = Math.Max(0, sales + rnd.Next(-2, +2));
                downloads = Math.Max(0, downloads + rnd.Next(-8, +8));
                revisions = Math.Max(0, revisions + rnd.Next(-1, +1));

                if (rnd.NextDouble() > .90)
                {
                    sales = Math.Max(0, sales + rnd.Next(-100, +90));
                    downloads = Math.Max(0, downloads + rnd.Next(-500, +450));
                    revisions = Math.Max(0, revisions + rnd.Next(-50, +45));
                }
            }

            // configure chart
            _chart.ChartType = C1.Silverlight.Chart.ChartType.Line;

            // bind chart
            _chart.Data.ItemsSource = list;

            // configure X axis
            var ax = _chart.View.AxisX;
            //ax.MajorGridStroke = ax.MinorGridStroke = null;
            ax.IsTime = true; // << ** PERF NOTE: if values are DateTime, set this to true!
            ax.ItemsValueBinding = new Binding("Month");
            ax.AnnoFormat = "MMM-yy";
            ax.AnnoAngle = 45;

            // configure Y axis
            var ay = _chart.View.AxisY;
            //ay.MajorGridStroke = ay.MinorGridStroke = null;

            // ** PERF NOTE: only do this if the items really are names (not values)
            //_chart.Data.ItemNameBinding = new Binding("Month");

            // add series
            foreach (var seriesName in "Sales;Downloads;Revisions".Split(';'))
            {
                var ds = new C1.Silverlight.Chart.DataSeries();
                ds.ValueBinding = new Binding(seriesName);
                ds.Label = seriesName;
                _chart.Data.Children.Add(ds);
            }

            // look for mouse clicks
            // PERF NOTES: 
            // a) more efficient than attaching event handlers to each chart point
            // b) allows hit testing for line charts (symbol elements are not required)
            // c) allows near-hit testing (clicking near but not on an element)
            // d) reduces the chances of memory leaks when the chart is regenerated and
            //    event handlers attached to old chart elements are not removed.
            _chart.MouseLeftButtonDown += _chart_MouseLeftButtonDown;
        }

        void _chart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            C1.Silverlight.Chart.DataSeries ds;
            int pointIndex;
            if (TryGetClosestPoint(_chart, e, 200, out ds, out pointIndex))
            {
                string msg = string.Format("Thanks for clicking point {0} on data series {1}", pointIndex, ds.Label);
                MessageBox.Show(msg);
            }
        }

        // find the closest series to the mouse, including threshold
        bool TryGetClosestPoint(C1.Silverlight.Chart.C1Chart chart, MouseEventArgs e, double threshold, out C1.Silverlight.Chart.DataSeries ds, out int pointIndex)
        {
            // initialize variables
            ds = null;
            pointIndex = -1;
            int dsIndex = -1;
            int ptIndex = -1;
            double distMin = double.MaxValue;
            double dist = 0;

            // get position in chart coordinates
            var pt = e.GetPosition(chart);

            // look for the closest series using the DataIndexFromPoint method
            for (int i = 0; i < chart.Data.Children.Count; i++)
            {
                ptIndex = chart.View.DataIndexFromPoint(pt, i, C1.Silverlight.Chart.MeasureOption.XY, out dist);
                if (dist < distMin)
                {
                    distMin = dist;
                    dsIndex = i;
                }
            }

            // return result
            if (distMin <= threshold)
            {
                ds = chart.Data.Children[dsIndex];
                pointIndex = ptIndex;
                return true;
            }
            return false;
        }
    }

    // dummy data class
    public class ProductData
    {
        public string ProductName { get; set; }
        public DateTime Month { get; set; }
        public int Sales { get; set; }
        public int Downloads { get; set; }
        public int Revisions { get; set; }
    }
}
