#pragma once
#include "olcPixelGameEngine.h"
#include <strstream>
#include "TMXParser.h"
#include "Map.h"
#include "olcUTIL_Geometry2D.h"

using namespace olc;

struct Tileset{
	XMLTag ImageData;
    std::map<int,XMLTag> ForegroundTileData;
    std::map<int,XMLTag> UpperForegroundTileData;
    std::map<int,TileCollisionData> CollisionData;
    std::map<int,XMLTag> StaircaseData;
    friend std::ostream& operator << (std::ostream& os, Tileset& rhs);
};

class TSXParser{
	public:
	Tileset&GetData();
	private:
	Tileset parsedTilesetInfo;
	void ParseTag(std::string tag);
    std::string previousTag;
    int previousTagID;
    std::string staircaseTag="";
	public:
	TSXParser(std::string file);
};

#ifdef TSX_PARSER_SETUP
#undef TSX_PARSER_SETUP
	Tileset&TSXParser::GetData() {
		return parsedTilesetInfo;
	}
    std::ostream&operator<<(std::ostream& os, Tileset& rhs){
        os<<rhs.ImageData.FormatTagData(rhs.ImageData.data)<<"\n";
        return os;
    }
    void TSXParser::ParseTag(std::string tag) {
        XMLTag newTag;
        //First character is a '<' so we discard it.
        tag.erase(0,1); tag.erase(tag.length()-1,1); //Erase the first and last characters in the tag. Now parse by spaces.
        std::stringstream s(tag); //Turn it into a string stream to now parse into individual whitespaces.
        std::string data;
        while (s.good()) {
            int quotationMarkCount=0;
            bool pastEquals=false;
            data="";
            bool valid=false;
            while(s.good()){
                int character=s.get();
                if(character=='"'){
                    quotationMarkCount++;
                }
                if(character==' '&&quotationMarkCount%2==0){
                    valid=true;
                    break;
                }
                data+=character;
                if(pastEquals&&quotationMarkCount%2==0){
                    valid=true;
                    break;
                }
                if(character=='='&&quotationMarkCount%2==0){
                    pastEquals=true;
                }
            }
            if(valid&&data.length()>0){
                if (newTag.tag.length()==0) { //Tag's empty, so first line is the tag.
                    newTag.tag=data;
                    std::cout<<"Tag: "<<newTag.tag<<"\n";
                } else {
                    std::string key = data.substr(0,data.find("="));
                    std::string value = data.substr(data.find("=")+1,std::string::npos);

                    //Strip Quotation marks.
                    value = value.substr(1,std::string::npos);
                    value = value.substr(0,value.length()-1);

                    newTag.data[key]=value;
                    std::cout<<"  "<<key<<":"<<newTag.data[key]<<"\n";
                }
            }
        }

        if (newTag.tag=="image") {
            parsedTilesetInfo.ImageData=newTag;
        } else
        if (newTag.tag=="tile"&&newTag.data["type"]=="ForegroundTile"){
            parsedTilesetInfo.ForegroundTileData[newTag.GetInteger("id")]=newTag;
        } else
        if (newTag.tag=="tile"&&newTag.data["type"]=="UpperForegroundTile"){
            parsedTilesetInfo.UpperForegroundTileData[newTag.GetInteger("id")]=newTag;
        } else
        if (newTag.tag=="tile"&&newTag.data["type"]=="Staircase"){
            staircaseTag=newTag.tag;
            previousTagID=newTag.GetInteger("id");
        } else
        if (newTag.tag=="tile"){
            previousTag=newTag.tag;
            previousTagID=newTag.GetInteger("id");
        } else
        if (newTag.tag=="property"&&staircaseTag=="tile"){
            parsedTilesetInfo.StaircaseData[previousTagID]=newTag;
            staircaseTag="";
        } else
        if (newTag.tag=="object"&&previousTag=="tile"){
            TileCollisionData data;
            data.collision=geom2d::rect<int>{{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}};
            parsedTilesetInfo.CollisionData[previousTagID]=data;
        }
        std::cout<<"\n"<<"=============\n";
    }
    TSXParser::TSXParser(std::string file){
        std::ifstream f(file,std::ios::in);

        std::string accumulator="";

        while (f.good()) {
            std::string data;
            f>>data;
            if (data.empty()) continue;

            if (accumulator.length()>0) {
                accumulator+=" "+data;
                //Check if it ends with '>'
                if (data[data.length()-1]=='>') {
                    ParseTag(accumulator);
                    accumulator="";
                }
            } else
                if (data[0]=='<') {
                    //Beginning of XML tag.
                    accumulator=data;
                    if(accumulator.length()>1&&accumulator.at(1)=='/'){
                        accumulator=""; //Restart because this is an end tag.
                    }
                    if(accumulator.length()>1&&accumulator.find('>')!=std::string::npos){
                        accumulator=""; //Restart because this tag has nothing in it!
                    }
                }
        }

        std::cout<<"Parsed Tileset Data:\n"<<parsedTilesetInfo<<"\n";
    }
#endif