using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Shapes;

using C1.Xaml.Chart;

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

namespace ChartSamples
{
  public sealed partial class LoadAnimation : UserControl
  {
    Random rnd = new Random();

    public LoadAnimation()
    {
      this.InitializeComponent();

      cbChartType.ItemsSource = new ChartType[] 
      { 
        ChartType.Column, ChartType.ColumnStacked, ChartType.Bar, ChartType.BarStacked,
        ChartType.AreaStacked, ChartType.StepArea,
        ChartType.LineSymbols, ChartType.XYPlot, ChartType.Pie, ChartType.PieExplodedDoughnut
      };
      cbChartType.SelectedIndex = 0;
      cbChartType.SelectionChanged += (s, e) => chart.ChartType = (ChartType)cbChartType.SelectedItem;

      cbTransform.ItemsSource = Utils.GetEnumValues(typeof(AnimationTransform));
      cbTransform.SelectedIndex = 1;

      cbOrigin.ItemsSource = Utils.GetEnumValues(typeof(AnimationOrigin));
      cbOrigin.SelectedIndex = 1;

      cbEasing.ItemsSource = Utils.GetEnumValues(typeof(Easing));
      cbEasing.SelectedIndex = 0;

      chart.Tapped += (s, e) => NewData();
      chart.Loaded += (s, e) => NewData();
    }

    void NewData()
    {
        chart.BeginUpdate();

        AnimationTransform at = (AnimationTransform)Enum.Parse(typeof(AnimationTransform), (string)cbTransform.SelectedItem, false);
        AnimationOrigin ao = (AnimationOrigin)Enum.Parse(typeof(AnimationOrigin), (string)cbOrigin.SelectedItem, false);
        Easing ea = (Easing)Enum.Parse(typeof(Easing), (string)cbEasing.SelectedItem, false);
        chart.Data.LoadAnimation = CreateAnimation(at, ao, cbIndexDelay.IsChecked == true, ea);

        int nser = rnd.Next(2, 6);
        int npts = rnd.Next(5, 10);

        chart.Data.Children.Clear();
        for (int i = 0; i < nser; i++)
            chart.Data.Children.Add(CreateDataSeries(npts));
        chart.EndUpdate();
    }

    public PlotElementAnimation CreateAnimation(AnimationTransform transform, AnimationOrigin origin, bool indexDelay, Easing easing)
    {
        var sb = new Storyboard();
        var duration = new Duration(TimeSpan.FromSeconds(0.5));

        var style = new Style();
        style.TargetType = typeof(Windows.UI.Xaml.Shapes.Path);
        if (transform == AnimationTransform.Scale)
            style.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.RenderTransformProperty, new ScaleTransform() { ScaleX = 0, ScaleY = 0 }));
        else if (transform == AnimationTransform.Rotation)
            style.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.RenderTransformProperty, new RotateTransform() { Angle = 180 }));
        else if(transform == AnimationTransform.Opacity)
            style.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.OpacityProperty, 0));


        var point = new Point(0.5, 0.5);
        switch (origin)
        {
            case AnimationOrigin.Bottom:
                point = new Point(0.5, 2);
                break;
            case AnimationOrigin.Top:
                point = new Point(0.5, -2);
                break;
            case AnimationOrigin.Left:
                point = new Point(-2, 0.5);
                break;
            case AnimationOrigin.Right:
                point = new Point(2, 0.5);
                break;
            case AnimationOrigin.TopRight:
                point = new Point(2, -2);
                break;
            case AnimationOrigin.TopLeft:
                point = new Point(-2, -2);
                break;
            case AnimationOrigin.BottomRight:
                point = new Point(2, 2);
                break;
            case AnimationOrigin.BottomLeft:
                point = new Point(-2, 2);
                break;
            default:
                break;
        }

        style.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.RenderTransformOriginProperty, point));

        var da = new DoubleAnimation() { From = 0, To = 1, Duration = duration };
        Storyboard.SetTargetProperty(da, "Opacity");
        sb.Children.Add(da);

        if (transform == AnimationTransform.Scale)
        {
            var da2 = new DoubleAnimation() { From = 0, To = 1, Duration = duration };
            Storyboard.SetTargetProperty(da2, "(UIElement.RenderTransform).(ScaleTransform.ScaleX)");

            var da3 = new DoubleAnimation() { From = 0, To = 1, Duration = duration };
            Storyboard.SetTargetProperty(da3, "(UIElement.RenderTransform).(ScaleTransform.ScaleY)");

            sb.Children.Add(da2);
            sb.Children.Add(da3);
        }
        else if (transform == AnimationTransform.Rotation)
        {
            var da2 = new DoubleAnimation() { To = 0, Duration = duration };
            Storyboard.SetTargetProperty(da2, "(UIElement.RenderTransform).(RotateTransform.Angle)");
            sb.Children.Add(da2);
        }

        if (indexDelay)
        {
            foreach (var anim in sb.Children)
                PlotElementAnimation.SetIndexDelay(anim, 0.5);
        }

        if (easing != Easing.None)
        {
            EasingFunctionBase ef = null;
            
            switch (easing)
            {
                case Easing.BackEase:
                    ef = new BackEase(); break;
                case Easing.BounceEase:
                    ef = new BounceEase(); break;
                case Easing.CircleEase:
                    ef = new CircleEase(); break;
                case Easing.CubicEase:
                    ef = new CubicEase(); break;
                case Easing.ElasticEase:
                    ef = new ElasticEase(); break;
                case Easing.ExponentialEase:
                    ef = new ExponentialEase(); break;
                case Easing.PowerEase:
                    ef = new PowerEase(); break;
                case Easing.QuadraticEase:
                    ef = new QuadraticEase(); break;
                case Easing.QuarticEase:
                    ef = new QuarticEase(); break;
                case Easing.QuinticEase:
                    ef = new QuinticEase(); break;
                case Easing.SineEase:
                    ef = new SineEase(); break;

                default:
                    break;
            }

            foreach (DoubleAnimation anim in sb.Children)
                anim.EasingFunction = ef;
        }

        return new PlotElementAnimation() { Storyboard = sb, SymbolStyle = style };
    }

    public DataSeries CreateDataSeries(int npts, bool invert = false)
    {
      var ds = new XYDataSeries() { SymbolSize = new Size(20, 20) };

      int cnt = npts;
      var x = new double[cnt];
      var y = new double[cnt];

      for (int i = 0; i < cnt; i++)
      {
        x[i] = i; y[i] = rnd.NextDouble();
      }

      if (invert)
      {
        ds.XValuesSource = y; ds.ValuesSource = x;
      }
      else
      {
        ds.XValuesSource = x; ds.ValuesSource = y;
      }
      return ds;
    }
  }

  public enum AnimationOrigin
  {
      Center,
      Top,
      Left,
      Bottom,
      Right,
      TopLeft,
      TopRight,
      BottomLeft,
      BottomRight
  }

  public enum Easing
  {
      None,
      BackEase,
      BounceEase,
      CircleEase,
      CubicEase,
      ElasticEase,
      ExponentialEase,
      PowerEase,
      QuadraticEase,
      QuarticEase,
      QuinticEase,
      SineEase
  }

  public enum AnimationTransform
  {
      Opacity,
      Scale,
      Rotation
  }

}
