#include "animation.h"
#include "exception.h"
#include "animation_manager.h"
#include "texture_manager.h"
#include "text_reader.h"
#include "resource_locator.h"
#include <sstream>

namespace Halley {
namespace Animation {
	Player::Player(String group)
		: time(0)
		, frameN(-1)
		, direction(0)
	{
		setGroup(group);
	}


	void Player::step(float t) {
		int sz = (int)sequence->size();
		for (int i=0; i < sz && time <= 0; i++) {
			frameN++;
			if (frameN == sz) {
				frameN = 0;
			}
			auto& mFrame = sequence->at(frameN);
			time += mFrame.length;
			frame = &mFrame.frames.at(direction);
		}
		time -= t;
	}


	int Player::getTextureId() const
	{
		return frame->texId;
	}


	Vector2f Player::getPivot() const
	{
		return frame->pivot;
	}


	void Player::setGroup(String name) {
		groupName = name;
		group = AnimationManager::get(name);
	}


	void Player::setSequence(String name) {
		if (sequenceName != name) {
			sequenceName = name;
			auto iter = group->find(name);
			if (iter == group->end()) throw Exception("Unknown animation sequence: "+name+" on group "+groupName);
			sequence = &iter->second;
			frameN = -1;
			time = 0;
		}
	}


	void Player::setDirection(int dir) {
		direction = dir;
	}

	

	//////////////


	MultiFrame parseFrame(String data, int lineN)
	{
		MultiFrame result;

		// Separate length
		data.TrimBoth();
		size_t p = data.Find(':');
		if (p == String::npos) 
			throw Exception("Parse error on line "+String::IntegerToString(lineN)+" - expected colon");
		String dur = data.Left(p);
		data = data.Mid(p+1);
		data.TrimBoth();

		// Parse length
		dur.TrimBoth();
		if (dur.EndsWith("f")) {
			int nFrames = dur.Left(dur.Length()-1).ToInteger();
			result.length = nFrames / 60.0f;	// HACK
		} else {
			result.length = dur.ToFloat();
		}

		// Parse frames
		while (data != "") {
			// Separate current block
			p = data.Find(',');
			String cur = data.Left(p);
			if (p == String::npos) data = "";
			else data = data.Mid(p+1);
			data.TrimBoth();

			// Read texture
			std::stringstream ss(cur.c_str());
			std::string name;
			std::string tmp;
			ss >> name;
			auto tex = TextureManager::get(String(name));
			int id = tex->GetId();

			// Read pivot
			float px, py;
			ss >> tmp;
			String tmp2 = String(tmp);
			px = tmp2.ToFloat();
			if (!tmp2.Contains(".")) px /= tex->GetW();
			ss >> tmp;
			tmp2 = String(tmp);
			py = tmp2.ToFloat();
			if (!tmp2.Contains(".")) py /= tex->GetH();

			result.frames.push_back(Frame(id, Vector2f(px, py)));
		}
		

		return result;
	}


	shared_ptr<Group> parse(StringArray data)
	{
		shared_ptr<Group> g(new Group());
		auto& group = *g;
		Sequence* seq = nullptr;

		int i=0;
		foreach (String line, data) {
			i++;
			line.TrimBoth();
			if (line.StartsWith("#")) continue;

			if (line.StartsWith("sequence ")) {
				String name = line.Mid(9);
				name.TrimBoth();
				group[name] = Sequence();
				seq = &group[name];
			}

			else if (line != "" && seq) {
				seq->push_back(parseFrame(line, i));
			}
		}
		return g;
	}


	shared_ptr<Group> parseFile(String name)
	{
		auto res = ResourceLocator::get(name);
		size_t sz = res->getSize();
		char* data = (char*) res->getData();
		char *data2 = new char[sz+1];
		data2[sz] = 0;
		memcpy(data2, data, sz);

		StringArray result;
		char* p = strtok(data2, "\n");
		while(p) {
			result.push_back(String(p));
			p = strtok(nullptr, "\n");
		}
		
		return parse(result);
	}
}
}