#include "pixelGameEngine.h"

using namespace olc;

struct Cursor{
	int line=0;
	int pos=0;
};

struct PrintKey{
	char normal;
	char shift;
};

class IDE : public olc::PixelGameEngine
{
public:
	std::vector<Cursor>cursors={{0,2}};
	std::vector<std::string>document={{"Test"}};
	std::map<Key,PrintKey>PRINTABLE={
		{K0,{')'}},{K1,{'!'}},{K2,{'@'}},{K3,{'#'}},{K4,{'$'}},{K5,{'%'}},{K6,{'^'}},{K7,{'&'}},{K8,{'*'}},{K9,{'('}},
		{SPACE,{' ',' '}},
		{NP_MUL,{'*','*'}},{NP_DIV,{'/','/'}},{NP_ADD,{'+','+'}},{NP_SUB,{'-','-'}},{NP_DECIMAL,{'.','.'}},{PERIOD,{'.','>'}},
		{EQUALS,{'=','+'}},{COMMA,{',','<'}},{MINUS,{'-','_'}},
		{OEM_1,{';',':'}},{OEM_2,{'/','?'}},{OEM_3,{'`','~'}},{OEM_4,{'[','{'}},{OEM_5,{' '}},{OEM_6,{']','}'}},{OEM_7,{'\'','"'}},{OEM_8,{'\\','|'}}
	};
	float lastBlinkTime=0;

	IDE()
	{
		sAppName = "PGEIDE";
	}

public:
	bool OnUserCreate() override
	{
		std::cout<<"Created IDE: "<<ScreenWidth()<<"x"<<ScreenHeight()<<std::endl;
		return true;
	}

	bool OnUserUpdate(float fElapsedTime) override
	{
		if (GetKey(RIGHT).bPressed){
			if (cursors[0].pos<document[cursors[0].line].size()){
				cursors[0].pos++;
			} else 
			if (cursors[0].line<document.size()-1){
				cursors[0].line++;
				cursors[0].pos=0;
			}
		}
		if (GetKey(LEFT).bPressed){
			if (cursors[0].pos>0){
				cursors[0].pos--;
			} else 
			if (cursors[0].line>0){
				cursors[0].line--;
				cursors[0].pos=document[cursors[0].line].size();
			}
		}
		if (GetKey(DOWN).bPressed){
			if (cursors[0].line<document.size()-1){
				cursors[0].line++;
			}
		}
		if (GetKey(UP).bPressed){
			if (cursors[0].line>0){
				cursors[0].line--;
			}
		}
		if (GetKey(HOME).bPressed){
			if(GetKey(CTRL).bHeld){
				cursors[0].line=0;
			}
			cursors[0].pos=0;
		}
		if (GetKey(END).bPressed){
			if(GetKey(CTRL).bHeld){
				cursors[0].line=document.size()-1;
			}
			cursors[0].pos=document[cursors[0].line].size();
		}
		if (GetKey(ENTER).bPressed){
			if(cursors[0].pos==0){
				//Insert in front of line.
				document.insert(document.begin()+cursors[0].line++,{{}});
			} else{
				document.insert(document.begin()+cursors[0].line+1,document[cursors[0].line].substr(cursors[0].pos,document[cursors[0].line].size()));
				document[cursors[0].line]=document[cursors[0].line].substr(0,cursors[0].pos);
				cursors[0].pos=0;
				cursors[0].line++;
			}
		}
		int i=0;
		for (std::string&line:document){
			DrawStringDecal({0,float(i)*10},line);
			if(cursors[0].line==i&&lastBlinkTime>=0.5f){DrawStringDecal({float(cursors[0].pos)*8-2,float(i)*10+1},"|",GREY,{0.5,0.8});}
			i++;
		}
		lastBlinkTime+=fElapsedTime;
		if (lastBlinkTime>1.f){
			lastBlinkTime--;
		}
		return true;
	}

	bool OnUserDestroy()override{
		return true;
	}

	void GetAnyKeyPress(olc::Key k)override{
		lastBlinkTime=0.5f;
		if (k==DEL){
			if (cursors[0].pos==document[cursors[0].line].size()){
				if (cursors[0].line<document.size()-1){
					document[cursors[0].line].append(document[cursors[0].line+1]);
					document.erase(document.begin()+cursors[0].line+1);
				}
			} else {
				document[cursors[0].line].erase(cursors[0].pos,1);
			}
		} else
		if (k==BACK){
			if (cursors[0].pos==0){
				if (cursors[0].line>0){
					cursors[0].pos=document[cursors[0].line-1].size();
					document[cursors[0].line-1].append(document[cursors[0].line]);
					document.erase(document.begin()+cursors[0].line--);
				}
			} else {
				document[cursors[0].line].erase(cursors[0].pos---1,1);
			}
		} else
		if (k>=A&&k<=Z){
			if (GetKey(SHIFT).bHeld){
				document[cursors[0].line].insert(cursors[0].pos++,std::string(1,k-1+'A'));
			} else {
				document[cursors[0].line].insert(cursors[0].pos++,std::string(1,k-1+'a'));
			}
		} else
		if (k>=K0&&k<=K9){
			if (GetKey(SHIFT).bHeld){
				document[cursors[0].line].insert(cursors[0].pos++,std::string(1,PRINTABLE[k].normal));
			} else {
				document[cursors[0].line].insert(cursors[0].pos++,std::string(1,k-K0+'0'));
			}
		} else {
			if (PRINTABLE.find(k)!=PRINTABLE.end()){
				if (GetKey(SHIFT).bHeld){
					document[cursors[0].line].insert(cursors[0].pos++,std::string(1,PRINTABLE[k].shift));
				} else {
					document[cursors[0].line].insert(cursors[0].pos++,std::string(1,PRINTABLE[k].normal));
				}
			}
		}
	}
};

int main(int argc, char** argv)
{	
	IDE demo;
	rcode code;
	if (argc==3){
		code=demo.Construct(std::stoi(argv[1]), std::stoi(argv[2]), 1, 1);
	} else {
		code=demo.Construct(200, 200, 1, 1);
	}
	if (code!=FAIL){
		demo.Start();
	}
	return 0;
}