using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace Valg.EVA.Skanning.UserInterfaceElements.AnimatedGif
{
    
    
    
    public class ImageAnimationController : IDisposable
    {
        private static readonly DependencyPropertyDescriptor _sourceDescriptor;

        static ImageAnimationController()
        {
            _sourceDescriptor = DependencyPropertyDescriptor.FromProperty(Image.SourceProperty, typeof (Image));
        }

        private readonly Image _image;
        private readonly ObjectAnimationUsingKeyFrames _animation;
        private readonly AnimationClock _clock;
        private readonly ClockController _clockController;
        
        internal ImageAnimationController(Image image, ObjectAnimationUsingKeyFrames animation, bool autoStart)
        {
            _image = image;
            _animation = animation;
            _animation.Completed += AnimationCompleted;
            _clock = _animation.CreateClock();
            _clockController = _clock.Controller;
            _sourceDescriptor.AddValueChanged(image, ImageSourceChanged);

            
            _clockController.Pause();
            
            
            _image.ApplyAnimationClock(Image.SourceProperty, _clock);
            
            if (autoStart)
                _clockController.Resume();
        }

        void AnimationCompleted(object sender, System.EventArgs e)
        {
            _image.RaiseEvent(new System.Windows.RoutedEventArgs(ImageBehavior.AnimationCompletedEvent, _image));
        }

        private void ImageSourceChanged(object sender, System.EventArgs e)
        {
            OnCurrentFrameChanged();
        }

        
        
        
        public int FrameCount
        {
            get { return _animation.KeyFrames.Count; }
        }

        
        
        
        public bool IsPaused
        {
            get { return _clock.IsPaused; }
        }

        
        
        
        public bool IsComplete
        {
            get { return _clock.CurrentState == ClockState.Filling; }
        }

        
        
        
        
        public void GotoFrame(int index)
        {
            var frame = _animation.KeyFrames[index];
            _clockController.Seek(frame.KeyTime.TimeSpan, TimeSeekOrigin.BeginTime);
        }

        
        
        
        public int CurrentFrame
        {
            get
            {
                var time = _clock.CurrentTime;
                var frameAndIndex =
                    _animation.KeyFrames
                              .Cast<ObjectKeyFrame>()
                              .Select((f, i) => new { Time = f.KeyTime.TimeSpan, Index = i })
                              .FirstOrDefault(fi => fi.Time >= time);
                if (frameAndIndex != null)
                    return frameAndIndex.Index;
                return -1;
            }
        }

        
        
        
        public void Pause()
        {
            _clockController.Pause();
        }

        
        
        
        public void Play()
        {
            switch (_clock.CurrentState)
            {
                case ClockState.Active:
                    _clockController.Resume();
                    break;
                case ClockState.Filling:
                case ClockState.Stopped:
                    _clockController.Begin();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        
        
        
        public event EventHandler CurrentFrameChanged;

        private void OnCurrentFrameChanged()
        {
            EventHandler handler = CurrentFrameChanged;
            if (handler != null) handler(this, System.EventArgs.Empty);
        }

        
        
        
        ~ImageAnimationController()
        {
            Dispose(false);
        }

        
        
        
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        
        
        
        
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _image.BeginAnimation(Image.SourceProperty, null);
                _animation.Completed -= AnimationCompleted;
                _sourceDescriptor.RemoveValueChanged(_image, ImageSourceChanged);
                _image.Source = null;
            }
        }
    }
}
