using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace WaterTest
{
    class Replay
    {
        struct CameraSnapshot
        {
            public Vector3 Position;
            public Vector3 LookAt;
            public float Time;
        }

        public Replay(Camera camera)
        {
            this.camera = camera;
        }

        public void Reset()
        {
            lastSnapshot = null;
            snapshots.Clear();
        }

        private TimeSpan? lastSnapshot;
        public void TakeSnapshot(GameTime gameTime)
        {
            if (inReplay)
            {
                inReplay = false;
            }
            if (wasInReplay)
            {
                wasInReplay = false;
                Reset();
            }
            CameraSnapshot cs = new CameraSnapshot();
            cs.Position = camera.Position;
            cs.LookAt = camera.LookAt;
            if (lastSnapshot.HasValue)
            {
                TimeSpan delta = gameTime.TotalGameTime.Subtract(lastSnapshot.Value);
                cs.Time = (float)delta.TotalSeconds;
            }
            else
            {
                // First time
                cs.Time = 0f;
            }
            snapshots.Add(cs);
            lastSnapshot = gameTime.TotalGameTime;
        }

        private bool inReplay = false;
        private bool wasInReplay = false;

        private float timeEllapsed = 0f;
        private float nextTime;
        private int currentSnapshotIndex;   // and then there is a next too.
        public void StartReplay()
        {
            if (snapshots.Count > 1)
            {
                wasInReplay = true;
                inReplay = true;
                currentSnapshotIndex = 0;
                timeEllapsed = 0f;
                nextTime = snapshots[1].Time;
            }
        }

        public void Update(GameTime gameTime)
        {
            if (inReplay)
            {
                if ((timeEllapsed / nextTime) >= 1f)
                {
                    currentSnapshotIndex++;
                    timeEllapsed -= nextTime;
                }

                if (currentSnapshotIndex < (snapshots.Count - 1))
                {
                    CameraSnapshot p1 = (currentSnapshotIndex > 0) ? snapshots[currentSnapshotIndex - 1] : snapshots[currentSnapshotIndex];
                    CameraSnapshot p2 = snapshots[currentSnapshotIndex];
                    CameraSnapshot p3 = snapshots[currentSnapshotIndex + 1];
                    nextTime = p3.Time;
                    CameraSnapshot p4 = ((currentSnapshotIndex + 2) < snapshots.Count) ? snapshots[currentSnapshotIndex + 2] : p3;

                    float progression = timeEllapsed / nextTime;

                    Vector3 lookAt = Vector3.CatmullRom(p1.LookAt, p2.LookAt, p3.LookAt, p4.LookAt, progression);
                    Vector3 position = Vector3.CatmullRom(p1.Position, p2.Position, p3.Position, p4.Position, progression);
                    camera.LookAt = lookAt;
                    camera.Position = position;
                    camera.Update();
                }
                else
                {
                    inReplay = false;
                }
            }

            timeEllapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;
        }

        public bool InReplay { get { return inReplay; } }

        private Camera camera;
        private List<CameraSnapshot> snapshots = new List<CameraSnapshot>();
    }
}
