#include "MPFW_HL.h"
#include "MPFW_Utils.h"
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <exception>

MPFW::HL::WAD::WAD()
{
	std::cout << "Warning: Empty WAD instance created.\n";
}

MPFW::HL::WAD::WAD(std::string path)
{
	LoadWAD(path);
}

void MPFW::HL::WAD::LoadWAD(std::string path)
{
	loaded = false;
	lumps.clear();
	lumpCount = 0;
	std::cout << "Loading file " << path << "...\n";
	std::ifstream file(path, std::ios::binary);
	std::string filedata;
	std::stringstream filestream; filestream << file.rdbuf();
	filedata = filestream.str();/*
	if (


		MPFW::Utils::Strings::IterativeComp(filedata, 0, "IWAD")) {
		wadType = IWAD;
		std::cout << "File is an IWAD\n";
	}
	else if (MPFW::Utils::Strings::IterativeComp(filedata, 0, "PWAD")) {
		wadType = PWAD;
		std::cout << "File is a PWAD\n";
	}
	else {
		throw std::runtime_error("Invalid WAD file: Error at header start(IWAD/PWAD)\n");
	}*/
	lumpCount = MPFW::Utils::Strings::StringIndexToInteger_4b_le(filedata, 4);

	std::cout << "File has " << lumpCount << " lumps\n";
	int directoryPointer = MPFW::Utils::Strings::StringIndexToInteger_4b_le(filedata, 8);

	std::string directory = MPFW::Utils::Strings::IterativeStringExcerpt(filedata, directoryPointer, 16 * lumpCount);

	for (int i = 0; i < lumpCount; i++) {
		Lump lump;
		std::string lumpIndex = MPFW::Utils::Strings::IterativeStringExcerpt(directory, i * 16, 16);
		int lumpPointer = MPFW::Utils::Strings::StringIndexToInteger_4b_le(lumpIndex, 0);
		int lumpSize = MPFW::Utils::Strings::StringIndexToInteger_4b_le(lumpIndex, 4);
		lump.name = "", lump.data = "";
		for (int j = 0; j < 8; j++) {
			if (lumpIndex.at(8 + j) != 0x0) lump.name += lumpIndex.at(8 + j);
		}

		lump.data = MPFW::Utils::Strings::IterativeStringExcerpt(filedata, lumpPointer, lumpSize);

		lumps.push_back(lump);

		std::cout << "(" << i << "/" << lumpCount << ")" << "Loaded lump \"" << lump.name << "\" of size " << lumpSize << "\n";
	}
	loaded = true;
}

MPFW::HL::WAD::~WAD()
{
}

MPFW::HL::Map::Map()
{
}

MPFW::HL::Map::Map(std::string path)
{
	Load(path);
}

void MPFW::HL::Map::Load(std::string path)
{
	std::ifstream in(path);
	
	if (!in.is_open()) throw std::runtime_error("Cannot open file " + path + "\n");
	
	int scope = 0;


	std::string line;
	GenericUnknownClass* parsedClass = new GenericUnknownClass();
	WorldSpawnClass* worldSpawn = new WorldSpawnClass();
	bool inWorldSpawn = false;
	while (std::getline(in, line)) {
		
		if (line == "{") {
			scope++;
			std::cout << "scope: " << scope << std::endl;
		}
		else if (line == "}") {
			scope--;
			std::cout << "scope: " << scope << std::endl;
			if (scope == 0) {
				if (inWorldSpawn) {
					inWorldSpawn = false;
					mapdata.push_back(worldSpawn);
				}
				else {
					mapdata.push_back(parsedClass);
					parsedClass = new GenericUnknownClass();
				}
			}
		}
		else {
			if (line != "") {
				if (scope == 1) {
					std::string key = MPFW::Utils::Strings::IterativeStringExcerpt_delim(line, 1, '"');
					std::string val = MPFW::Utils::Strings::IterativeStringExcerpt_delim(line, 4 + key.size(), '"');
					std::cout << key << " : " << val << "\n";
					if (key == "classname") {
						if (val == "worldspawn") {
							inWorldSpawn = true;
							std::cout << "in world spawn\n";
							worldSpawn->classname = "worldspawn";
						}
						else {
							parsedClass->classname = val;
						}
					}
					else if (!inWorldSpawn) parsedClass->fields[key] = val;
					else {
						if (key == "defaultteam") worldSpawn->defaultteam = std::stoi(val);
						if (key == "newunit") worldSpawn->newunit = std::stoi(val);
						if (key == "gametitle") worldSpawn->gametitle = std::stoi(val);
						if (key == "startdark") worldSpawn->startdark = std::stoi(val);
						if (key == "MaxRange") worldSpawn->maxrange = std::stoi(val);
						if (key == "sounds") worldSpawn->sounds = std::stoi(val);
						if (key == "mapversion") worldSpawn->mapversion = std::stoi(val);
						if (key == "wad") worldSpawn->wad = val;
					}

				}
				else if (scope == 2) {
					std::stringstream stream(line);
					Plane plane;
					std::string temp;
					stream >>
						temp >> plane.a.x >> plane.a.y >> plane.a.z >> temp >>
						temp >> plane.b.x >> plane.b.y >> plane.b.z >> temp >>
						temp >> plane.c.x >> plane.c.y >> plane.c.z >> temp >>
						plane.texturename >>
						temp >> plane.u.x >> plane.u.y >> plane.u.z >> plane.uOffset >> temp >>
						temp >> plane.v.x >> plane.v.y >> plane.v.z >> plane.vOffset >> temp >>
						plane.rotation >> plane.uScale >> plane.vScale;

					worldSpawn->planes.push_back(plane);
					
				}
				else {
					throw std::out_of_range("Out of scope content");
				}
			}
		}
	}

	if (scope != 0) {
		if (scope > 1) throw std::length_error("File " + path + " is visibly incomplete by scope arithmetics.\n");
		else {
			std::cerr << "[WARNING] File " + path + " is missing a final closing bracket.\n";
		}
	}

	in.close();

}

MPFW::HL::Map::~Map()
{
}
