#pragma once
#include <mof/Color.hpp>
#include <lua.hpp>
#include <vector>
#include <stdexcept>
#include <mof/streams.hpp>


// seq_factory クラスにする必要なし？
namespace mof
{
namespace script
{
	template <typename T>
	class seq_parser 
	{
	public:
		typedef typename KeyFrameAnimation<T>::KeyFrame key_frame;
//{{{ parse
		typename Manipulator<T>::ptr parse(lua_State* l, size_t offset) const
		{
			std::vector<typename KeyFrameAnimation<T>::KeyFrame> v;
			std::shared_ptr<mof::Vector3D> world2client_pos;
			std::shared_ptr<std::pair<mof::frame_t, mof::frame_t>> looping;

			lua_pushnil(l);
			while (lua_next(l, offset) != 0) {
				if (lua_isnumber(l, -2)) {
					v.push_back(pop_key_frame(l));
				}
				else if (lua_isstring(l, -2)) {
					mof::tstring key = lua_tostring(l, -2);
					if (key == "world2client") world2client_pos = make_worldclient_pos(l);
					else if (key == "loop") looping = make_looping(l);
				}
				lua_pop(l, 1);// pop the value
			}
			auto tween = make_manip(v, world2client_pos);
			if (looping) {
				return mof::makeLoopHandler<T>(tween, looping->first, looping->second);
			} else return tween;
		}
//}}}
	private:
//{{{ pop_key_frame
		key_frame pop_key_frame(lua_State* l) const
		{
		}
//}}}
//{{{ make_manip
		typename Manipulator<T>::ptr make_manip
		(
			const std::vector<key_frame>& v,
			const std::shared_ptr<mof::Vector3D>& world2client_pos
		) const
		{
		}
//}}}
//{{{ make_worldclient_pos
		std::shared_ptr<mof::Vector3D> make_worldclient_pos(lua_State* l) const
		{
			float values[3];
			int index = 0;
			lua_pushnil(l);
			for (; lua_next(l, -2) && index < 3; ++index) {
				values[index] = static_cast<float>(lua_tonumber(l, -1));
				lua_pop(l, 1);
			}
			if (index == 3) {
				return std::make_shared<mof::Vector3D>(values[0], values[1], values[2]);
			}
			else throw std::runtime_error("too few world2client_pos parameters");
		}
//}}}
//{{{ make_looping
		std::shared_ptr<std::pair<mof::frame_t, mof::frame_t>> make_looping(lua_State* l) const
		{
			using namespace std;
			FrameNumber values[2];
			int index = 0;
			lua_pushnil(l);
			for (; lua_next(l, -2) && index < 2; ++index) {
				values[index] = static_cast<int>(lua_tonumber(l, -1));
				lua_pop(l, 1);
			}
			if (index == 2) {
				auto p = make_shared<std::pair<mof::frame_t, mof::frame_t>>();
				p->first = values[0];
				p->second = values[1];
				return p;
			}
			else throw std::runtime_error("too few loop parameters");
		}
//}}}
	};
//{{{ <Color4f>
		seq_parser<Color4f>::key_frame seq_parser<Color4f>::pop_key_frame(lua_State* l) const
		{
			FrameNumber frame = lua_tointeger(l, -2);
			double values[4];
			int index = 0;
			lua_pushnil(l);
			for (; lua_next(l, -2) && index < 4; ++index) {
				values[index] = lua_tonumber(l, -1);
				lua_pop(l, 1);
			}
			if (index == 4) {
				return key_frame(frame, Color4f(values[0], values[1], values[2], values[3]));// ARGB
			}
			else if (index == 3) {
				return key_frame(frame, Color4f(values[0], values[1], values[2]));// RGB
			}
			else throw std::runtime_error("too few color parameters");
		}

		Manipulator<Color4f>::ptr seq_parser<Color4f>::make_manip
		(
			const std::vector<seq_parser<Color4f>::key_frame>& v,
			const std::shared_ptr<mof::Vector3D>& world2client_pos
		) const
		{
			return makeKeyFrameAnimationHandler<Color4f>(v.front(), v.back());
		}
	//};
//}}}
//{{{ <Vector2D>
		seq_parser<Vector2D>::key_frame seq_parser<Vector2D>::pop_key_frame(lua_State* l) const
		{
			FrameNumber frame = lua_tointeger(l, -2);
			double values[2];
			int index = 0;
			lua_pushnil(l);
			for (; lua_next(l, -2) && index < 2; ++index) {
				values[index] = lua_tonumber(l, -1);
				lua_pop(l, 1);
			}
			if (index == 2) {
				return key_frame(frame, Vector2D(static_cast<float>(values[0]), static_cast<float>(values[1])));
			}
			else throw std::runtime_error("too few position2D parameters");
		}

		Manipulator<Vector2D>::ptr seq_parser<Vector2D>::make_manip
		(
			const std::vector<seq_parser<Vector2D>::key_frame>& v,
			const std::shared_ptr<mof::Vector3D>& world2client_pos
		) const
		{
			if (world2client_pos) {
				// world2client_posを解釈する
				Manipulator<Vector2D>::ptr tweens[] = {
					std::make_shared<mof::world2client_tween>(mof::makeConstantHandler<mof::Vector3D>(*world2client_pos)),
					makeKeyFrameAnimationHandler<Vector2D>(v.front(), v.back()),
				};
				return makeCascadeHandler<Vector2D, Add<Vector2D>>(tweens[0], mof::lastOf(tweens));
			} else return makeKeyFrameAnimationHandler<Vector2D>(v.front(), v.back());
		}
	//};
//}}}
//{{{ <Vector3D>
		seq_parser<Vector3D>::key_frame seq_parser<Vector3D>::pop_key_frame(lua_State* l) const
		{
			FrameNumber frame = lua_tointeger(l, -2);
			float values[3];
			int index = 0;
			lua_pushnil(l);
			for (; lua_next(l, -2) && index < 3; ++index) {
				values[index] = static_cast<float>(lua_tonumber(l, -1));
				lua_pop(l, 1);
			}
			if (index == 3) {
				return key_frame(frame, Vector3D(values[0], values[1], values[2]));
			}
			else throw std::runtime_error("too few position3D parameters");
		}

		Manipulator<Vector3D>::ptr seq_parser<Vector3D>::make_manip
		(
			const std::vector<seq_parser<Vector3D>::key_frame>& v,
			const std::shared_ptr<mof::Vector3D>& world2client_pos
		) const
		{
			return makeKeyFrameAnimationHandler<Vector3D>(v.front(), v.back());
		}
	//};
//}}}
//{{{ <Rectangle<float>>
		seq_parser<Rectangle<float>>::key_frame seq_parser<Rectangle<float>>::pop_key_frame(lua_State* l) const
		{
			FrameNumber frame = lua_tointeger(l, -2);
			float values[4];
			int index = 0;
			lua_pushnil(l);
			for (; lua_next(l, -2) && index < 4; ++index) {
				values[index] = static_cast<float>(lua_tonumber(l, -1));
				lua_pop(l, 1);
			}
			if (index == 4) {
				return key_frame(frame, Rectangle<float>(values[0], values[1], values[2], values[3]));
			}
			else throw std::runtime_error("too few texcoord parameters");
		}

		Manipulator<Rectangle<float>>::ptr seq_parser<Rectangle<float>>::make_manip
		(
			const std::vector<seq_parser<Rectangle<float>>::key_frame>& v,
			const std::shared_ptr<mof::Vector3D>& world2client_pos
		) const
		{
			return makeKeyFrameAnimationHandler<Rectangle<float>>(v.front(), v.back(), mof::stepInterpolate<Rectangle<float>>);
		}
	//};
//}}}
}// namespace script
}// namespace mof

