#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <cstring>

sf::Font font;


int room=0;

bool reset_flag=false;

class ScorePanel{
	char buffer[1024];
public:
	sf::Text text;
	ScorePanel(){
		text.setPosition(0,0);
		text.setColor(sf::Color::Black);
		text.setCharacterSize(40);
		text.setFont(font);
	}
	void update(int health,int money,int power){
		sprintf(buffer,"Health:%i\nMoney:%i\nPower:%i\n",health,money,power);
		text.setString(buffer);
	}
}; 

class Mushroom{
	sf::RenderWindow* window;
	sf::RectangleShape head;
	sf::RectangleShape leg;	
	bool flying_mode;
	int flying_power;
	
	int health;
public:
	ScorePanel panel;
	int health_max;
	int balance;
	int state;
	int jump_y;
	int flying_max;
	Mushroom(sf::RenderWindow* win){
		health_max=1;
		health=health_max;
		balance=0;
		this->window=win;
		state=0;
		jump_y=0;
		flying_mode=false;
		flying_max=50;
		this->leg.setSize(sf::Vector2f(25, 50));
		this->leg.setFillColor(sf::Color::Yellow);
		this->head.setSize(sf::Vector2f(50, 25));
		this->head.setFillColor(sf::Color::Red);
	}
	void update(){
		this->panel.update(health,balance,this->flying_power);
		if(jump_y==0)flying_power=flying_max;
		flying_mode=false;
		if(state==2)if(sf::Keyboard::isKeyPressed(sf::Keyboard::C))flying_mode=true;
		if(flying_mode){
			if(flying_power==0)flying_mode=false;
			else flying_power--;
		}
		if(!flying_mode){
		if(state==2){
			jump_y-=4;
			if(jump_y==0)state=0;
		}
		if(state==1){
			jump_y+=4;
			if(jump_y==100)state=2;
		}}
		if(state==0&&sf::Keyboard::isKeyPressed(sf::Keyboard::Space))state=1;
		
		this->head.setPosition(25,500-jump_y);
		this->leg.setPosition(37,520-jump_y);
	}
	void render(){
		this->window->draw(this->leg);
		this->window->draw(this->head);
		this->window->draw(this->panel.text);
	}
	void coin_pick(){
		balance++;
	}	
	void hurt(){
		health--;
		if(health==0)reset_flag=true;
		this->state=1;
		flying_power=flying_max;
	}
	void reset(){
		health=health_max;
		flying_power=flying_max;
		this->panel.update(health,balance,this->flying_power);
		jump_y=0;
		state=0;
	}
};

class GrassSingle{
public:
	int x;
	bool active;
	int* ticks;
	Mushroom *player;
	GrassSingle(int nx,int* l,Mushroom *player){
		this->x=nx;
		this->active=false;
		this->ticks=l;
		this->player=player;
	}
	void update(){
		if(this->x+50<0){
			this->x=800;
			this->active=rand()%(5-(*ticks)/2000)==0;
		}
		
		if(this->active)if(this->x<=62)if(this->x>=5)if( this->player->jump_y<10 )if( this->player->state!=1 ){
			this->player->hurt();
			//this->active=false;
		}
		this->x-=4+(*ticks)/1000;
	}
};

class Grass{
	sf::RenderWindow* window;
	sf::CircleShape* triangle;
	GrassSingle *grass_map[17];
	Mushroom *player;
public:
	Grass(sf::RenderWindow* win,int* l,Mushroom *player){
		this->window=win;
		this->triangle=new sf::CircleShape(12, 3);
		this->triangle->setFillColor(sf::Color(0,0xAA,0));
		for(int i=0;i<17;i++)this->grass_map[i]=new GrassSingle(i*50,l,player);
		grass_map[6]->active=true;
		this->player=player;
	}
	void single_render(int x){
		triangle->setPosition(x,553);
		this->window->draw(*(this->triangle));
		triangle->setPosition(x+12,553);
		this->window->draw(*(this->triangle));
		triangle->setPosition(x+12*2,553);
		this->window->draw(*(this->triangle));
		triangle->setPosition(x+12*3,553);
		this->window->draw(*(this->triangle));
	}
	void render(){
		for(int i=0;i<17;i++)if(this->grass_map[i]->active)this->single_render(this->grass_map[i]->x);
	}
	void update(){
		for(int i=0;i<17;i++)this->grass_map[i]->update();
	}
	void reset(){
		for(int i=0;i<17;i++)this->grass_map[i]->active=false;
	}
};

class CoinSingle{
public:
	int x,y;
	bool active;
	int* ticks;
	Mushroom *player;
	CoinSingle(int nx,int* l,Mushroom *player){
		this->x=nx;
		this->y=0;
		this->active=false;
		this->ticks=l;
		this->player=player;
	}
	void update(){
		if(this->x+50<0){
			this->x=800;
			this->active=rand()%(10-(*ticks)/1000)==0;
			this->y=rand()%100;
		}
		int dist=(500-this->y)-(500-this->player->jump_y);
		if(this->active)if(this->x<99)if( ((dist<0)&&(-dist<48)) || ((dist>0)&&(dist<85)) || (dist==0) ){
			this->player->coin_pick();
			this->active=false;
			//sf::sleep(sf::milliseconds(200));
		}
		this->x-=4+(*ticks)/1000;
	}
};

class Coin{
	sf::RenderWindow* window;
	sf::CircleShape* circle;
	CoinSingle *grass_map[17];
public:
	Coin(sf::RenderWindow* win,int* l,Mushroom *player){
		this->window=win;
		this->circle=new sf::CircleShape(24);
		this->circle->setFillColor(sf::Color::Yellow);
		for(int i=0;i<17;i++)this->grass_map[i]=new CoinSingle(i*50,l,player);
		grass_map[6]->active=true;
	}
	void single_render(int x,int y){
		circle->setPosition(x,500-y);
		this->window->draw(*(this->circle));
	}
	void render(){
		for(int i=0;i<17;i++)if(this->grass_map[i]->active)this->single_render(this->grass_map[i]->x,this->grass_map[i]->y);
	}
	void update(){
		for(int i=0;i<17;i++)this->grass_map[i]->update();
	}
	void reset(){
		for(int i=0;i<17;i++)this->grass_map[i]->active=false;
	}
};

class World{
	
	sf::RenderWindow* window;
	sf::RectangleShape sky;
	sf::RectangleShape ground;
	Grass* grass;
	Coin *coin;
	int ticks;
public:
	Mushroom* player;
	World(sf::RenderWindow* win){
		this->window=win;
		this->player=new Mushroom(win);
		ticks=0;
		this->grass=new Grass(win,&ticks,player);
		this->coin=new Coin(win,&ticks,player);
		this->sky.setFillColor(sf::Color(0xB0,0xE0,0xE6));
		this->sky.setSize(sf::Vector2f(800, 570));
		this->sky.setPosition(0,0);
		this->ground.setPosition(0,570);
		this->ground.setSize(sf::Vector2f(800, 30));
		this->ground.setFillColor(sf::Color(0xB8,0x86,0x0B));
	}
	void update(){
		if(reset_flag){
			reset_flag=false;
			ticks=0;
			player->reset();
			coin->reset();
			grass->reset();
			room=0;
			return;
		}
		if(ticks<6000)ticks++;
		this->grass->update();
		this->coin->update();
		this->player->update();
	}
	void render(){
		this->window->draw(this->sky);
		this->window->draw(this->ground);
		this->grass->render();
		this->coin->render();
		this->player->render();
		
	}
};

class Button{
	sf::RenderWindow* window;
	sf::RectangleShape frame;
	sf::Text value;
public:
	Button(sf::RenderWindow* window,char *str,int x,int y){
		this->window=window;
		frame.setPosition(x,y);
		value.setPosition(x+10,y+10);
		frame.setSize(sf::Vector2f(strlen(str)*25+10,60));
		value.setCharacterSize(40);
		value.setColor(sf::Color::Black);
		frame.setFillColor(sf::Color::Yellow);
		value.setFont(font);
		value.setString(str);
	}
	void render(){
		window->draw(frame);
		window->draw(value);
	}
	bool pressed(){
		return sf::Rect<int>(frame.getGlobalBounds()).contains(sf::Mouse::getPosition(*window))&&sf::Mouse::isButtonPressed(sf::Mouse::Left);
	}
};

class UpgradeLine{
public:
	sf::RenderWindow* window;
	sf::Text info;
	Button *ub;
	char buffer[1024];
	char *name;
	Mushroom *player;
	int value;
	int cost;
	int *target;
	int level;
	UpgradeLine(int x,int y,sf::RenderWindow* window,char *name,Mushroom *player,int value,int cost,int* target){
		this->player=player;
		this->window=window;
		this->name=name;
		this->value=value;
		this->cost=cost;
		this->target=target;
		this->level=1;
		info.setPosition(x,y);
		info.setCharacterSize(40);
		info.setColor(sf::Color::Black);
		info.setFont(font);
		format();
		ub=new Button(window,"upgrade",x+600,y);
		
	}
	void format(){
		sprintf(buffer,"%s LV%i COST:%i",name,level,level*cost);
		info.setString(buffer);
	}
	void update(){
		if(ub->pressed())if(player->balance>=level*cost){
			player->balance-=level*cost;
			level++;
			format();
			sf::sleep(sf::milliseconds(100));
			*target=level*value;
			player->reset();
		}
	}
	void render(){
		this->window->draw(info);
		this->ub->render();
	}	
};

class Menu{
	sf::RenderWindow* window;
	sf::RectangleShape background;
	Button* play;
	UpgradeLine* health_upgrade;
	UpgradeLine* power_upgrade;
	UpgradeLine* final_upgrade;
public:
	int final_flag;
	Mushroom* player;
	Menu(sf::RenderWindow* window,Mushroom* player){
		final_flag=1;
		this->player=player;
		this->window=window;
		play = new Button(window,"go!",335,520);
		background.setPosition(0,0);
		background.setSize(sf::Vector2f(800,600));
		background.setFillColor(sf::Color(0xA7,0xDD,0x79));
		health_upgrade=new UpgradeLine(10,200,window,"health",player,1,50,&(player->health_max));
		power_upgrade=new UpgradeLine(10,300,window,"power ",player,50,150,&(player->flying_max));
		final_upgrade=new UpgradeLine(10,400,window,"final ",player,1,10000,&(final_flag));
		player->panel.text.setString("MUSHROOM POWER:c\nMUSHROOM  jump:space\nMusic by Goblins from Mars\n");
	}
	void update(){
		if(final_flag==2){
			player->panel.text.setString("YOU WIN!");
			player->panel.text.setPosition(300,300);
		}
		if(final_flag!=2)if(play->pressed())room=1;
		health_upgrade->update();
		power_upgrade->update();
		final_upgrade->update();
	}	
	void render(){
		window->draw(background);
		if(final_flag!=2){
		play->render();
		health_upgrade->render();
		power_upgrade->render();
		final_upgrade->render();
		}
		window->draw(player->panel.text);
	}	
};



int main()
{
	sf::Music music;
	music.openFromFile("music.ogg");
	music.play();
	music.setLoop(true);
	font.loadFromFile("Fixation.ttf");
    sf::RenderWindow window(sf::VideoMode(800, 600), "Legend of Mushroom");
    window.setFramerateLimit(100);
    window.setVerticalSyncEnabled(true);
	World world(&window);
	Menu menu(&window,world.player);
    while(window.isOpen())
    {
		sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }
        if(room==0){	
   			menu.update();
   			menu.render();
   		}
		if(room==1){	
   			world.update();
   			world.render();
   		}
        window.display();
    }

    return 0;
}
