#include "resource_locator.h"
#include "exception.h"

#ifdef _MSC_VER
#ifdef _DEBUG
#pragma comment(lib,"SDL_d.lib")
#else
#pragma comment(lib,"SDL.lib")
#endif
#endif

namespace Halley {
	ResourceData::ResourceData(void* _data, size_t _size, String _path)
		: data(_data)
		, size(_size)
		, path(_path)
	{
	}

	ResourceData::~ResourceData()
	{
		delete[] data;
		data = nullptr;
	}

	SDL_RWops* ResourceData::getRWOps()
	{
		return SDL_RWFromConstMem(data, size);
	}

	void ResourceLocator::add(shared_ptr<ResourceLocator> locator)
	{
		auto res = locator->getResourceList();
		for (size_t i=0; i<res.size(); i++) {
			// Check if resource is already listed
			auto result = locators.find(res[i]);
			if (result != locators.end()) {
				// Already listed, check if we should override
				if (result->second->getPriority() >= locator->getPriority()) break;
			}
				
			locators[res[i]] = locator;
		}
	}

	shared_ptr<ResourceData> ResourceLocator::get(String resource)
	{
		resource = resource.AsciiLower();
		auto result = locators.find(resource);
		if (result != locators.end()) {
			// Found a locator
			return result->second->doGet(resource);
		} else {
			// Could not find, try the generic locator
			result = locators.find("*");
			if (result != locators.end()) {
				// Generic locator found, use it
				return result->second->doGet(resource);
			} else {
				// No generic locator, give up
				std::cout << "Unable to locate resource: " << resource << std::endl;
				throw Exception("Unable to locate resource: "+resource);
			}
		}
	}

	FileSystemResourceLocator::FileSystemResourceLocator(String _basePath)
		: basePath(_basePath)
	{
	}

	shared_ptr<ResourceData> FileSystemResourceLocator::doGet(String resource)
	{
		String path = basePath+resource;
		FILE* fp = fopen(path.c_str(), "rb");
		if (!fp) throw Exception("Unable to open resource: "+resource);

		fseek(fp, 0, SEEK_END);
		size_t sz = ftell(fp);
		fseek(fp, 0, SEEK_SET);

		char* buf = new char[sz];
		fread(buf, 1, sz, fp);
		shared_ptr<ResourceData> data(new ResourceData(buf, sz, path));

		fclose(fp);

		return data;
	}
	
	std::vector<String> FileSystemResourceLocator::getResourceList()
	{
		std::vector<String> res;
		res.push_back("*");
		return res;
	}

	std::map<String, shared_ptr<ResourceLocator> > ResourceLocator::locators;
}
