using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace ControlExplorer
{
    public class TileControl : System.Windows.Controls.Control
    {
        private Storyboard storyboard = new Storyboard();
        private Storyboard storyboard2 = new Storyboard();
        private DoubleAnimation horizontalAnimation = new DoubleAnimation();
        private DoubleAnimation verticalAnimation = new DoubleAnimation();
        private DoubleAnimation scaleAnimationX = new DoubleAnimation();
        private DoubleAnimation scaleAnimationY = new DoubleAnimation();
        private static double SCALE = 0.9;
        private static double SPRINGINESS = 0.5;
        private static int ROTATION_FACTOR = 32;

        public TileControl()
        {
            DefaultStyleKey = typeof(TileControl);

            Projection = new PlaneProjection();
            RenderTransform = new ScaleTransform();

            Storyboard.SetTargetProperty(horizontalAnimation, new PropertyPath("RotationX"));
            Storyboard.SetTargetProperty(verticalAnimation, new PropertyPath("RotationY"));
            Storyboard.SetTargetProperty(scaleAnimationX, new PropertyPath("ScaleX"));
            Storyboard.SetTargetProperty(scaleAnimationY, new PropertyPath("ScaleY"));
            Storyboard.SetTarget(horizontalAnimation, Projection);
            Storyboard.SetTarget(verticalAnimation, Projection);
            Storyboard.SetTarget(scaleAnimationX, RenderTransform);
            Storyboard.SetTarget(scaleAnimationY, RenderTransform);

            // add cool elastic ease effect
            var ef1 = new ElasticEase();
            ef1.Oscillations = 1;
            ef1.Springiness = SPRINGINESS;
            ef1.EasingMode = EasingMode.EaseOut;
            horizontalAnimation.EasingFunction = ef1;
            horizontalAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(1500));

            // add cool elastic ease effect
            var ef2 = new ElasticEase();
            ef2.Oscillations = 1;
            ef2.Springiness = SPRINGINESS;
            ef2.EasingMode = EasingMode.EaseOut;
            verticalAnimation.EasingFunction = ef2;
            verticalAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(1500));

            scaleAnimationX.Duration = new Duration(TimeSpan.FromMilliseconds(100));
            scaleAnimationY.Duration = new Duration(TimeSpan.FromMilliseconds(100));

            storyboard.Children.Add(horizontalAnimation);
            storyboard.Children.Add(verticalAnimation);
            storyboard2.Children.Add(scaleAnimationX);
            storyboard2.Children.Add(scaleAnimationY);
        }

        public DataTemplate IconTemplate
        {
            get
            {
                return (DataTemplate)GetValue(IconTemplateProperty);
            }
            set
            {
                SetValue(IconTemplateProperty, value);
            }
        }

        public static readonly DependencyProperty IconTemplateProperty =
            DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(TileControl), new PropertyMetadata(null, (d, a) =>
            {
                if (DesignerProperties.IsInDesignTool)
                    (d as TileControl).SetValue(IconTemplateProperty, App.Current.Resources["CalendarIcon"] as DataTemplate);
            }));

        public double IconWidth
        {
            get { return (double)GetValue(IconWidthProperty); }
            set { SetValue(IconWidthProperty, value); }
        }

        public static readonly DependencyProperty IconWidthProperty =
            DependencyProperty.Register("IconWidth", typeof(double), typeof(TileControl), new PropertyMetadata(double.NaN));


        public double IconHeight
        {
            get { return (double)GetValue(IconHeightProperty); }
            set { SetValue(IconHeightProperty, value); }
        }

        public static readonly DependencyProperty IconHeightProperty =
            DependencyProperty.Register("IconHeight", typeof(double), typeof(TileControl), new PropertyMetadata(double.NaN));



        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(TileControl), null);


        protected override void OnMouseEnter(MouseEventArgs e)
        {
            if (storyboard.GetCurrentState() == ClockState.Active)
                return;
            storyboard.Pause();

            var position = e.GetPosition(this);

            var halfWidth = ActualWidth * 0.5;
            var halfHeight = ActualHeight * 0.5;
            verticalAnimation.From = -(position.X - halfWidth) / halfWidth * ROTATION_FACTOR;
            verticalAnimation.To = 0;
            horizontalAnimation.From = (position.Y - halfHeight) / halfHeight * ROTATION_FACTOR;
            horizontalAnimation.To = 0;

            storyboard.Begin();
        }

        private Point? downPosition = null;

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            downPosition = e.GetPosition(this);
            (RenderTransform as ScaleTransform).CenterX = ActualWidth * 0.5;
            (RenderTransform as ScaleTransform).CenterY = ActualHeight * 0.5;
            storyboard2.Pause();
            scaleAnimationX.From = 1;
            scaleAnimationX.To = SCALE;
            scaleAnimationY.From = 1;
            scaleAnimationY.To = SCALE;
            storyboard2.Begin();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (downPosition.HasValue)
            {
                var mousePosition = e.GetPosition(this);
                var distance = Math.Max(Math.Abs(downPosition.Value.X - mousePosition.X), Math.Abs(downPosition.Value.Y - mousePosition.Y));
                if (distance > 10)
                {
                    downPosition = null;
                    storyboard2.Pause();
                    scaleAnimationX.To = 1;
                    scaleAnimationY.To = 1;
                    storyboard2.Begin();
                }
            }
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (downPosition.HasValue)
            {
                storyboard2.Completed += new EventHandler(OnClickStoryboardCompleted);
                storyboard2.Pause();
                scaleAnimationX.From = SCALE;
                scaleAnimationX.To = 1;
                scaleAnimationY.From = SCALE;
                scaleAnimationY.To = 1;
                storyboard2.Begin();
            }
        }

        void OnClickStoryboardCompleted(object sender, EventArgs e)
        {
            storyboard2.Completed -= new EventHandler(OnClickStoryboardCompleted);
            if (Click != null)
                Click(this, new EventArgs());
        }

        public event EventHandler Click;
    }
}
