using C1.Xaml;
using C1.Xaml.Chart;
using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;

// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236

namespace ChartSamples
{
    public enum Position
    {
        North,
        South,
        East,
        West
    };

    public sealed partial class PieSpin : UserControl
    {
        DoubleCollection _values;
        string[] _itemNames;
        RotateTransform _rot;
        double _mouseAngle;
        Position _position;

        public PieSpin()
        {
            InitializeComponent();

            _position = Position.South;

            // create transform to spin the chart
            pieChart.RenderTransformOrigin = new Point(.5, .5);
            _rot = new RotateTransform();
            pieChart.RenderTransform = _rot;

            // hook up mouse handlers
            var drag = new C1DragHelper(pieChart);
            drag.DragStarted += OnPieChartDragStarted;
            drag.DragDelta += OnPieChartDragDelta;
            drag.DragCompleted += OnPieChartDragCompleted;

            // create sample data
            _values = new DoubleCollection();
            _values.Add(2122342);
            _values.Add(1269210);
            _values.Add(735358);
            _values.Add(310400);
            _values.Add(145898);
            _values.Add(115860);
            _values.Add(94060);
            _values.Add(93065);
            _itemNames = new string[] { "China", "USA", "Russia", "India", "Japan", "Canada", "Uruguay", "Brazil" };

            DataSeries ds = new DataSeries();
            ds.Values = _values;
            ds.PlotElementLoaded += ds_PlotElementLoaded;
            pieChart.Data.Children.Add(ds);
            pieChart.Data.ItemNames = _itemNames;

            // select first point
            RotateToSelected(0);
        }

        void ds_PlotElementLoaded(object sender, EventArgs e)
        {
            PieSlice slice = sender as PieSlice;
            if (slice != null)
            {
                slice.StrokeThickness = 0;
                var tapHelper = new C1TapHelper(slice);
                tapHelper.Tapped += tapHelper_Tapped;
            }
        }

        void tapHelper_Tapped(object sender, C1TappedEventArgs e)
        {
            PieSlice slice = sender as PieSlice;
            if (slice != null)
            {
                var index = slice.DataPoint.PointIndex;
                RotateToSelected(index);
            }
        }

        void OnPieChartDragStarted(object sender, C1DragStartedEventArgs e)
        {
            _mouseAngle = GetPointerAngle(e);
        }

        void OnPieChartDragDelta(object sender, C1DragDeltaEventArgs e)
        {
            // rotate the chart
            _rot.Angle = Math.IEEERemainder(_rot.Angle + GetPointerAngle(e) - _mouseAngle, 360);
        }

        void OnPieChartDragCompleted(object sender, C1DragCompletedEventArgs e)
        {
            var index = GetClosestSlice();

            // select the slice
            if (index > -1)
            {
                //_view.MoveCurrentToPosition(index);
                RotateToSelected(index);
            }
        }

        // get the angle that corresponds to a given pointer position
        double GetPointerAngle(C1InputEventArgs e)
        {
            var pt = e.GetPosition(pieChart);
            pt.X -= pieChart.ActualWidth / 2.0;
            pt.Y -= pieChart.ActualHeight / 2.0;
            var radians = Math.Atan2(pt.Y, pt.X);
            return Math.IEEERemainder(radians * 180.0 / Math.PI, 360);
        }

        int GetClosestSlice()
        {
            var index = -1;
            var minDelta = 0.0;
            for (int i = 0; i < _values.Count; i++)
            {
                var delta = Math.Abs(_rot.Angle - GetSliceAngle(i));
                if (i == 0 || delta < minDelta)
                {
                    index = i;
                    minDelta = delta;
                }
            }
            return index;
        }

        // spin chart to highlight current item
        void RotateToSelected(int index)
        {
            if (index > -1)
            {
                // calculate current and target angles
                var from = _rot.Angle;
                var to = GetSliceAngle(index);
                while (to - from > +180) to -= 360;
                while (to - from < -180) to += 360;
                if (to != from)
                {
                    // create animation
                    var da = new DoubleAnimation();
                    da.From = from;
                    da.To = to;
                    da.Duration = new Duration(TimeSpan.FromMilliseconds(600));
                    Storyboard.SetTargetProperty(da, "Angle");
                    Storyboard.SetTarget(da, _rot);

                    // add cool elastic ease effect
                    var ef = new ElasticEase();
                    ef.Oscillations = 1;
                    ef.Springiness = 3;
                    da.EasingFunction = ef;

                    // play animation
                    var sb = new Storyboard();
                    sb.Children.Add(da);
                    sb.Begin();
                }

                // update labels
                txtName.Text = _itemNames[index];
                txtPopulation.Text = _values[index].ToString("n0");
            }
        }

        // get the angle needed to place a given slice at the selection point
        double GetSliceAngle(int index)
        {
            // calculate angles
            var cur = 0.0;
            var tot = 0.0;
            for (int i = 0; i < _values.Count; i++)
            {
                tot += _values[i];
                if (i < index)
                {
                    cur += _values[i];
                }
                else if (i == index)
                {
                    cur += _values[i] / 2;
                }
            }

            // calculate angle to align the selected slice
            var angle = -cur / tot * 360;
            switch (_position)
            {
                case Position.North:
                    angle += 270;
                    break;
                case Position.South:
                    angle += 90;
                    break;
                case Position.East:
                    angle += 0;
                    break;
                case Position.West:
                    angle += 180;
                    break;
            }

            // done 
            return Math.IEEERemainder(angle, 360);
        }
    }
}
