#pragma once

#include <vector>
#include <algorithm>
#include <cmath>

namespace psemek::util
{

	template <typename Time, typename Data>
	struct animation_manager
	{
		struct animation
		{
			Time time;
			Time duration;
			Data data;

			Time position() const
			{
				return std::max(Time{0}, std::min(Time{1}, time / duration));
			}

			Time remaining() const
			{
				return duration - time;
			}

			bool finished() const
			{
				return remaining() <= Time{0};
			}
		};

		void add(Time duration, Data data)
		{
			animations_.push_back(animation{Time{0}, duration, data});
			std::push_heap(animations_.begin(), animations_.end(), compare{});
		}

		std::vector<Data> update(Time dt)
		{
			for (auto & animation : animations_)
				animation.time += dt;

			std::vector<Data> finished;
			while (!animations_.empty() && animations_.front().finished())
			{
				std::pop_heap(animations_.begin(), animations_.end(), compare{});
				finished.push_back(std::move(animations_.back().data));
				animations_.pop_back();
			}
			return finished;
		}

		animation const * begin() const
		{
			return animations_.data();
		}

		animation const * end() const
		{
			return animations_.data() + animations_.size();
		}

		std::size_t size() const
		{
			return animations_.size();
		}

		void clear()
		{
			animations_.clear();
		}

	private:
		std::vector<animation> animations_;

		struct compare
		{
			bool operator() (animation const & a1, animation const & a2)
			{
				return a1.remaining() > a2.remaining();
			}
		};
	};

}
