 #include "SDL.h"
 #include "SDL_image.h"
 #include "sprig.h"
 #include "Game.h"
 #include "Libraries/MixBox.h"
 #include "Libraries/StickyInput.h"
 #include <cassert>

 //#define NOT_RANDOM


 SDL_Surface* loadImage(const char* filename)
 {
     SDL_Surface* temp = IMG_Load(filename);
     if(temp != NULL)
     {
         SDL_Surface* result = SDL_DisplayFormatAlpha(temp);
         SDL_FreeSurface(temp);
         return result;
     }
     return temp;
 }

 #define drawpct \
    SPG_ArcFilledBlend(screen, screen->w/2, screen->h/2, screen->w/8, 0, 360*pct, SDL_MapRGB(screen->format, 200, 200, 200), 40); \
    SDL_Flip(screen); \
    pct += dpct;

 bool loadGameImages(SDL_Surface** images, SDL_Surface* screen)
 {
    float pct = 0;
    float dpct = 1/30.0f;

	images[0] = loadImage("images/boat1/boat1s.png");
	drawpct;
	images[1] = loadImage("images/boat1/boat2s.png");
	drawpct;
	images[2] = loadImage("images/boat1/boat3s.png");
	drawpct;
	images[3] = loadImage("images/boat1/boat4s.png");
	drawpct;
	images[4] = loadImage("images/boat1/boat5s.png");
	drawpct;
	images[5] = loadImage("images/boat1/boat6s.png");
	drawpct;
	images[6] = loadImage("images/boat1/boat7s.png");
	drawpct;
	images[7] = loadImage("images/boat1/boat8s.png");
	drawpct;

	images[8] = loadImage("images/tub/tub1a.jpg");
	drawpct;
	images[9] = loadImage("images/tub/tub1a-fore.png");
	drawpct;

	images[10] = loadImage("images/islands/island1.png");
	drawpct;
	images[11] = loadImage("images/islands/island1-fore.png");
	drawpct;
	images[12] = loadImage("images/islands/island1a.png");
	drawpct;
	images[13] = loadImage("images/islands/island1a-fore.png");
	drawpct;

	images[14] = loadImage("images/treasure/chest1.png");
	drawpct;
	images[15] = loadImage("images/treasure/chest1a.png");
	drawpct;

	images[16] = loadImage("images/treasure/map1.png");
	drawpct;

	images[17] = loadImage("images/objects/ball.png");
	drawpct;

	images[18] = loadImage("images/boat2/boat1s.png");
	drawpct;
	images[19] = loadImage("images/boat2/boat2s.png");
	drawpct;
	images[20] = loadImage("images/boat2/boat3s.png");
	drawpct;
	images[21] = loadImage("images/boat2/boat4s.png");
	drawpct;
	images[22] = loadImage("images/boat2/boat5s.png");
	drawpct;
	images[23] = loadImage("images/boat2/boat6s.png");
	drawpct;
	images[24] = loadImage("images/boat2/boat7s.png");
	drawpct;
	images[25] = loadImage("images/boat2/boat8s.png");
	drawpct;

	images[26] = loadImage("images/objects/ball2.png");
	drawpct;
	images[27] = loadImage("images/treasure/map-big.png");
	drawpct;
	images[28] = loadImage("images/tub/spout-fore.png");
	drawpct;
	images[29] = loadImage("images/hook.png");
	drawpct;
	SDL_Delay(100);
	drawpct;
	SDL_Delay(100);
	drawpct;
	SDL_Delay(100);
	drawpct;
	SDL_Delay(100);
	drawpct;
	SDL_Delay(100);
	drawpct;
	SDL_Delay(100);
	drawpct;

	for(int i = 0; i < 30; i++)
	{
	    if(images[i] == NULL)
            return false;
	}
	return true;
 }


// Add maps to link together all the chests
void linkEmUp(GameState* state, vector<Chest*>& chests, SDL_Surface** images)
{
    // Make sure there's at least one map on an island
    bool hasIslandMap = false;
    for(vector<Island*>::iterator e = state->islands.begin(); e != state->islands.end(); e++)
    {
        if((*e)->chest != NULL && (*e)->chest->map != NULL)
            hasIslandMap = true;
    }

    if(!hasIslandMap)
    {
        // Make the first island have a map in its chest
        assert(state->islands.size() > 0);
        Island* island = state->islands.front();
        if(island->chest == NULL)
        {
            island->chest = new Chest;
            island->chest->type = Chest::ISLAND;
            island->chest->x = island->x;
            island->chest->y = island->y;
            island->chest->pic = images[14];
            island->chest->picOpen = images[15];
            chests.push_back(island->chest);
        }

        island->chest->map = new Map;
        island->chest->map->pic = images[16];
        island->chest->map->bigpic = images[27];
    }

    vector<Chest*> linked;
    vector<Chest*> heads;

    // Choose the starting heads (the island maps)
    for(vector<Chest*>::iterator e = chests.begin(); e != chests.end();)
    {
        if((*e)->type == Chest::ISLAND)
        {
            linked.push_back(*e);
            if((*e)->map != NULL)
                heads.push_back(*e);
            chests.erase(e);
            e = chests.begin();
            continue;
        }
        e++;
    }

    // While there are unlinked chests, link an unlinked chest to a head and replace that head
    while(chests.size() > 0)
    {
        for(vector<Chest*>::iterator e = heads.begin(); e != heads.end(); e++)
        {
            if(chests.size() > 0)
            {
                if((*e)->map == NULL)
                {
                    (*e)->map = new Map;
                    (*e)->map->pic = images[16];
                    (*e)->map->bigpic = images[27];
                }
                (*e)->map->target = chests.front();
                *e = (*e)->map->target;
                chests.erase(chests.begin());
            }
        }
    }
}

// Hide all the goodies
void easterBunny(GameState* state, SDL_Surface** images)
{
    int chests = 10 + rand()%11;
    vector<Chest*> chestList;
    while(chests > 0)
    {
        int place = rand()%2;
        if(place == 0)
        {
            // On an island
            bool placed = false;
            for(vector<Island*>::iterator e = state->islands.begin(); e != state->islands.end(); e++)
            {
                if((*e)->chest == NULL)
                {
                    (*e)->chest = new Chest;
                    (*e)->chest->type = Chest::ISLAND;
                    (*e)->chest->x = (*e)->x;
                    (*e)->chest->y = (*e)->y;
                    (*e)->chest->pic = images[14];
                    (*e)->chest->picOpen = images[15];
                    if(rand()%2)
                    {
                        (*e)->chest->map = new Map;
                        (*e)->chest->map->pic = images[16];
                        (*e)->chest->map->bigpic = images[27];
                    }
                    (*e)->chest->gold = rand()%300 + 100;
                    chests--;
                    chestList.push_back((*e)->chest);
                    placed = true;
                    break;
                }
            }
            if(!placed)
            {
                // Uh oh, the islands are full.  Just try again.
                continue;
            }
        }
        else// if(place == 1)
        {
            // Underwater
            Chest* chest = new Chest;
            chest->type = Chest::UNDERWATER;
            chest->x = rand()%int(state->maxX - state->minX) + state->minX;
            chest->y = rand()%int(state->maxY - state->minY) + state->minY;
            chest->pic = images[14];
            chest->picOpen = images[15];
            chest->gold = rand()%300 + 100;
            chests--;
            state->underwaterChests.push_back(chest);
            chestList.push_back(chest);
        }
    }

    // Add the maps to link them
    linkEmUp(state, chestList, images);
}



void instructions(SDL_Surface* screen, NFont* font)
{

    SPG_RectFilledBlend(screen, 40, 40, screen->w - 40, screen->h - 40, 0x000000, 200);
    font->drawCenter(screen->w/2, 40,
                                      "Find more GOLD than your opponents to win!\n"
                                      "Locate treasure chests on islands first.\n"
                                      "Shoot them to open them.  Touch them to collect.\n"
                                      "If you find a map, it will lead you to more gold.\n"
                                      "Fish at the X to get the treasure.\n"
                                      "Destroy others to steal their maps.\n"
                                      "The game ends when all the treasure is found.\n"
                                      "\n"
                                      "Use 'W', 'A', 'S', 'D' (or arrow keys) to move.\n"
                                      "Use LEFT mouse button (or space) to fire.\n"
                                      "Use RIGHT mouse button (or left shift) to fish for treasure.\n"
                                      "\n"
                                      "Treasure Tub is brought to you by Jonathan Dearborn\n"
                                      "for Ludum Dare 17: Islands.\n"
                                      "Find Jonny D at: http://code.bluedinosaurs.com"
                                      );

    SDL_Flip(screen);

    SDL_Event event;
    bool done = false;

    while(!done)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)
            {
                exit(0);
            }
            else if(event.type == SDL_KEYDOWN)
            {
                done = true;
            }
        }

        SDL_Delay(10);
    }

}

bool titleScreen(SDL_Surface* screen)
{
    SDL_Color fontColor = {200, 200, 0, 255};
    NFont* font = new NFont("fonts/FreeSans.ttf", 20, fontColor);
    font->setDest(screen);

    SDL_Event event;
    bool done = false;
    bool start = false;

    SDL_Surface* bg = IMG_Load("images/title.png");

    while(!done)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)
            {
                exit(0);
            }
            else if(event.type == SDL_KEYDOWN)
            {
                if(event.key.keysym.sym == SDLK_ESCAPE)
                    exit(0);
                if(event.key.keysym.sym == SDLK_i)
                    instructions(screen, font);

                if(event.key.keysym.sym == SDLK_SPACE || event.key.keysym.sym == SDLK_RETURN)
                {
                    done = true;
                    start = true;
                }
            }
            else if(event.type == SDL_MOUSEBUTTONDOWN)
            {
                if(event.button.button == SDL_BUTTON_LEFT)
                {
                    int mx, my;
                    SDL_GetMouseState(&mx, &my);
                    done = true;
                    start = true;
                }
            }
        }

        SPG_Draw(bg, screen, 0, 0);

        font->drawCenter(screen->w/2, 500, "Press 'i' for instructions.\nPress SPACE to begin.");

        SDL_Flip(screen);

        SDL_Delay(10);
    }

    SDL_FreeSurface(bg);

    SDL_FreeSurface(font->getSurface());
    delete font;

    return start;
}



void winScreen(SDL_Surface* screen, NFont* font, int gold)
{
    SDL_Surface* bg = IMG_Load("images/win.png");
    SPG_Draw(bg, screen, 0, 0);
    font->drawCenter(424, 116, "Gold: %d", gold);

    SDL_Flip(screen);

    // Remove all events from the queue and pause a bit.
    SDL_Event event;

    SDL_Delay(1000);
    while(SDL_PollEvent(&event));


    bool done = false;


    while(!done)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)
            {
                exit(0);
            }
            else if(event.type == SDL_KEYDOWN)
            {
                done = true;
            }
        }

        SPG_Draw(bg, screen, 0, 0);

        font->drawCenter(424, 116, "Gold: %d", gold);

        SDL_Flip(screen);

        SDL_Delay(10);
    }

    SDL_FreeSurface(bg);
}

void loseScreen(SDL_Surface* screen, SDL_Surface** images, NFont* font, int winGold, int gold)
{
    SDL_FillRect(screen, NULL, 0x000000);
    font->drawCenter(424, 116, "You LOSE!!\nWinner's Gold: %d\n Your Gold: %d", winGold, gold);
    SPG_Draw(images[21], screen, screen->w/2 - images[21]->w/2, 300);

    SDL_Flip(screen);

    // Remove all events from the queue and pause a bit.
    SDL_Event event;

    SDL_Delay(1000);
    while(SDL_PollEvent(&event));

    bool done = false;

    while(!done)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)
            {
                exit(0);
            }
            else if(event.type == SDL_KEYDOWN)
            {
                done = true;
            }
        }
        SDL_FillRect(screen, NULL, 0x000000);

        font->drawCenter(424, 116, "You LOSE!!\nWinner's Gold: %d\n Your Gold: %d", winGold, gold);

        SPG_Draw(images[21], screen, screen->w/2 - images[21]->w/2, 300);

        SDL_Flip(screen);

        SDL_Delay(10);
    }
}


int main(int argc, char* argv[])
{

    SDL_putenv(const_cast<char*>("SDL_VIDEO_CENTERED=center"));
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("Failed to initialize SDL: %s\n", SDL_GetError());
		return 1;
	}

	SDL_Surface* screen = SDL_SetVideoMode(800, 600, 0, SDL_SWSURFACE);

	if(screen == NULL)
	{
		printf("Failed to create a display surface: %s\n", SDL_GetError());
		return 1;
	}

	SDL_WM_SetCaption("Treasure Tub", NULL);

	SI::Reset(false);

	#ifndef NOT_RANDOM
        srand(time(NULL));
	#endif



    MB::MixBox::instance().openMixer();


    MB::MixBox& mixer = MB::MixBox::instance();

    mixer.loadSound("sounds/splish1.wav");
    mixer.loadSound("sounds/splish2.wav");
    mixer.loadSound("sounds/splish3.wav");
    mixer.loadSound("sounds/cannon1.wav");
    mixer.loadSound("sounds/cannon2.wav");
    mixer.loadSound("sounds/cannon3.wav");
    mixer.loadSound("sounds/boom1.wav");
    mixer.loadSound("sounds/boom2.wav");
    mixer.loadSound("sounds/boom3.wav");


	// Load all graphics for the game
	SDL_Surface* images[50];
	images[0] = NULL;

    bool done = false;
    bool startGame = false;


    while(!done)
    {
        startGame = titleScreen(screen);

        if(startGame)
        {
            if(images[0] == NULL && !loadGameImages(images, screen))
            {
                printf("Failed to load images!\n");
                return 1;
            }

            GameState gameState;
            gameState.screen = screen;

            Player* player = new Player;
            gameState.player = player;

            player->boat->x = screen->w;
            player->boat->y = screen->h;

            Boat* b = player->boat;
            b->isPlayer = true;
            for(int i = 0; i < 8; i++)
                b->pic[i] = images[i+18];
            b->ball = images[17];
            b->hook = images[29];
            gameState.boats.push_back(b);

            for(int j = 0; j < 4; j++)
            {
                CPU* cpu = new CPU;
                gameState.cpus.push_back(cpu);
                b = cpu->boat;
                b->x = rand()%int(gameState.maxX - gameState.minX) + gameState.minX;
                b->y = rand()%int(gameState.maxY - gameState.minY) + gameState.minY;
                for(int i = 0; i < 8; i++)
                    b->pic[i] = images[i];
                b->ball = images[26];
                b->hook = images[29];
                gameState.boats.push_back(b);
            }


            GameDraw gameDraw;
            gameDraw.tub = images[8];
            gameDraw.tubFore = images[9];
            gameDraw.spoutFore = images[28];
            SDL_Color fontColor = {200, 200, 0, 255};
            gameDraw.font1 = new NFont("fonts/FreeSans.ttf", 20, fontColor);
            gameDraw.font1->setDest(screen);
            fontColor.r = 200;
            fontColor.g = 0;
            fontColor.b = 0;
            gameDraw.font2 = new NFont("fonts/FreeSans.ttf", 20, fontColor);
            gameDraw.font2->setDest(screen);
            int numisles = 3 + rand()%4;
            for(int j = 0; j < numisles; j++)
            {
                Island* island = new Island(0, 0);
                island->x = rand()%int(gameState.maxX - gameState.minX) + gameState.minX;
                island->y = rand()%int(gameState.maxY - gameState.minY) + gameState.minY;
                island->pic = images[10];
                island->fore = images[11];
                island->picBroke = images[12];
                island->foreBroke = images[13];

                gameState.islands.push_back(island);
            }

            easterBunny(&gameState, images);

            GameUpdate gameUpdate;

            GameEvent gameEvent;

            PL_Set gameSet;
            gameSet.draw = &gameDraw;
            gameSet.update = &gameUpdate;
            gameSet.any = &gameEvent;

            PL_Loop(&gameState, gameSet);

            Boat* winner = NULL;
            for(vector<Boat*>::iterator e = gameState.boats.begin(); e != gameState.boats.end(); e++)
            {
                if(winner == NULL || (*e)->gold > winner->gold)
                    winner = *e;
            }

            if(winner == gameState.player->boat)
                winScreen(screen, gameDraw.font1, winner->gold);
            else
                loseScreen(screen, images, gameDraw.font1, winner->gold, gameState.player->boat->gold);


            for(vector<CPU*>::iterator e = gameState.cpus.begin(); e != gameState.cpus.end(); e++)
            {
                delete *e;
            }
            for(vector<Island*>::iterator e = gameState.islands.begin(); e != gameState.islands.end(); e++)
            {
                delete *e;
            }

            delete player;
        }
    }

    for(int i = 0; i < 28; i++)
        SDL_FreeSurface(images[i]);


    MB::MixBox::instance().freeSounds();
    MB::MixBox::instance().closeMixer();

	return 0;
}
