#include "Game.h"
#include "sprig.h"
#include "Libraries/MixBox.h"
#include "extraMath.h"
#include <cmath>


GameState::GameState()
    : PL_State()
    , scrollX(0)
    , scrollY(0)
    , sminX(0), sminY(0), smaxX(2520), smaxY(1384)
    , minX(372), minY(546), maxX(2361), maxY(1200)
{}



GameUpdate::GameUpdate()
    : PL_Update()
{}


void collide(Boat* A, Boat* B)
{
    float dir = atan2(B->y - A->y, B->x - A->x);
    float s = sin(dir);
    float c = cos(dir);
    A->velx -= 200*c;
    A->vely -= 200*s;
    B->velx += 200*c;
    B->vely += 200*s;
}
void collide(Boat* A, Island* B)
{
    float dir = atan2(B->y - A->y, B->x - A->x);
    float s = sin(dir);
    float c = cos(dir);
    A->velx -= 200*c;
    A->vely -= 200*s;
    if(B->chest != NULL)
    {
        if(B->chest->isOpen)
        {
            if(B->chest->map != NULL)
            {
                A->maps.push_back(B->chest->map);
                B->chest->map = NULL;
                delete B->chest;
                B->chest = NULL;
            }
            else
            {
                A->gold += B->chest->gold;
                B->chest->gold = 0;
                delete B->chest;
                B->chest = NULL;
            }
        }
    }
}

void GameUpdate::update(PL_State* state)
{
    GameState* s = static_cast<GameState*>(state);


    s->scrollX = s->player->boat->x - s->screen->w/2;
    s->scrollY = s->player->boat->y - s->screen->h/2;
    if(s->scrollX < s->sminX)
        s->scrollX = s->sminX;
    if(s->scrollY < s->sminY)
        s->scrollY = s->sminY;

    if(s->scrollX > s->smaxX - s->screen->w)
        s->scrollX = s->smaxX - s->screen->w;
    if(s->scrollY > s->smaxY - s->screen->h)
        s->scrollY = s->smaxY - s->screen->h;


    int mx, my;
    SDL_GetMouseState(&mx, &my);
    Boat* b = s->player->boat;
    b->target.x = s->scrollX + mx;
    b->target.y = s->scrollY + my;

    s->player->update(s);


    for(vector<CPU*>::iterator e = s->cpus.begin(); e != s->cpus.end(); e++)
    {
        (*e)->update(s);
    }

    // Boat collision
    for(vector<Boat*>::iterator e = s->boats.begin(); e != s->boats.end(); e++)
    {
        if((*e)->hp <= 0)
        {
            (*e)->hp = (*e)->hpMax;
            (*e)->x = rand()%int(s->maxX - s->minX) + s->minX;
            (*e)->y = rand()%int(s->maxY - s->minY) + s->minY;
            (*e)->invinceTimer = 2.0f;
            continue;
        }
        for(vector<Boat*>::iterator f = s->boats.begin(); f != s->boats.end(); f++)
        {
            if((*f)->hp <= 0)
                continue;
            if(*f != *e && dist(*e, *f) < 50)
                collide(*e, *f);
        }
        // Floating map collision
        for(list<Map*>::iterator f = s->floatingMaps.begin(); f != s->floatingMaps.end(); f++)
        {
            if(dist(*e, *f) < 50)
            {
                (*e)->maps.push_back(*f);
                s->floatingMaps.erase(f);
                break;
            }
        }
    }
    // Island collision
    for(vector<Boat*>::iterator e = s->boats.begin(); e != s->boats.end(); e++)
    {
        if((*e)->hp <= 0)
            continue;
        for(vector<Island*>::iterator f = s->islands.begin(); f != s->islands.end(); f++)
        {
            if(dist(*e, *f) < (*f)->radius)
                collide(*e, *f);
        }
    }



    for(list<CannonBall*>::iterator e = s->balls.begin(); e != s->balls.end();)
    {
        if(!(*e)->update(s->dt))
        {
            list<CannonBall*>::iterator f = e;
            e++;

            Boat* hit = NULL;
            for(vector<Boat*>::iterator g = s->boats.begin(); g != s->boats.end(); g++)
            {
                if((*f)->owner == (*g))
                    continue;
                if((*g)->invinceTimer < 0 && (*g)->hp > 0 && dist(*g, *f) < 75)
                {
                    hit = *g;
                    break;
                }
            }

            if(hit == NULL)
            {
                s->splashes.push_back(new Splash((*f)->x, (*f)->y));
                MB::MixBox::instance().play(MB::SoundID(rand()%3));
            }
            else
            {
                s->splashes.push_back(new Blast((*f)->x, (*f)->y));
                MB::MixBox::instance().play(MB::SoundID(rand()%3+6));
                hit->hit();
                if(hit->hp <= 0 && hit->maps.size() > 0)
                {
                    Map* map = hit->maps.front();
                    map->x = hit->x;
                    map->y = hit->y;
                    s->floatingMaps.push_back(map);
                    hit->maps.erase(hit->maps.begin());
                }
            }

            if(hit == NULL)
            {
                Island* hit = NULL;

                for(vector<Island*>::iterator g = s->islands.begin(); g != s->islands.end(); g++)
                {
                    if(dist(*g, *f) < 75)
                    {
                        hit = *g;
                        break;
                    }
                }

                if(hit == NULL)
                {
                    s->splashes.push_back(new Splash((*f)->x, (*f)->y));
                    MB::MixBox::instance().play(MB::SoundID(rand()%3));
                }
                else
                {
                    s->splashes.push_back(new Blast((*f)->x, (*f)->y));

                    MB::MixBox::instance().play(MB::SoundID(rand()%3+6));
                    hit->hit();
                }
            }


            delete *f;
            s->balls.erase(f);
            continue;
        }
        e++;
    }

    for(list<Splash*>::iterator e = s->splashes.begin(); e != s->splashes.end();)
    {
        if(!(*e)->update(s->dt))
        {
            list<Splash*>::iterator f = e;
            e++;
            delete *f;
            s->splashes.erase(f);
            continue;
        }
        e++;
    }

    if(s->underwaterChests.size() == 0)
        s->done = true;

}




GameDraw::GameDraw()
    : PL_Draw()
{}

void GameDraw::draw(PL_State* state)
{
    GameState* s = static_cast<GameState*>(state);

    //SDL_FillRect(s->screen, NULL, 0x000000);

    // Tub
    SPG_Draw(tub, s->screen, -s->scrollX, -s->scrollY);

    // Islands
    for(vector<Island*>::iterator e = s->islands.begin(); e != s->islands.end(); e++)
    {
        (*e)->draw(s->screen, s->scrollX, s->scrollY);
    }
    // Floating maps
    for(list<Map*>::iterator e = s->floatingMaps.begin(); e != s->floatingMaps.end(); e++)
    {
        SPG_Draw((*e)->pic, state->screen, (*e)->x - s->scrollX, (*e)->y - s->scrollY);
    }
    // Boats
    for(vector<Boat*>::iterator e = s->boats.begin(); e != s->boats.end(); e++)
    {
        (*e)->draw(s->screen, s->scrollX, s->scrollY);
    }
    // Splashes
    for(list<Splash*>::iterator e = s->splashes.begin(); e != s->splashes.end(); e++)
    {
        (*e)->draw(s->screen, s->scrollX, s->scrollY);
    }
    // Underwater Chests (debug)
    /*for(list<Chest*>::iterator e = s->underwaterChests.begin(); e != s->underwaterChests.end(); e++)
    {
        SPG_Circle(s->screen, (*e)->x - s->scrollX, (*e)->y - s->scrollY, 10, SDL_MapRGB(s->screen->format, 0, 255, 0));
    }*/
    // CannonBalls
    for(list<CannonBall*>::iterator e = s->balls.begin(); e != s->balls.end(); e++)
    {
        (*e)->draw(s->screen, s->scrollX, s->scrollY);
    }

    // Draw foreground
    // Islands
    for(vector<Island*>::iterator e = s->islands.begin(); e != s->islands.end(); e++)
    {
        (*e)->drawFore(s->screen, s->scrollX, s->scrollY);
    }
    // Tub
    SPG_Draw(spoutFore, s->screen, 187 - s->scrollX, 520 - s->scrollY);
    SPG_Draw(tubFore, s->screen, 93 - s->scrollX, 648 - s->scrollY);

    // Draw UI

    // Draw minimap
    if(s->player->boat->maps.size() > 0)
    {
        s->player->boat->maps.front()->draw(s->screen, s);
    }

    // Draw gold
    font1->draw(5, s->screen->h - 55, "Gold: %d", s->player->boat->gold);

    // Draw chests
    font1->draw(5, 5, "Chests Left: %d", s->underwaterChests.size());

    // Draw hitpoints
    font2->draw(5, s->screen->h - 30, "HP:");
    for(int i = 0; i < s->player->boat->hp; i++)
    {
        SPG_RectFilled(s->screen, 45 + i*25, s->screen->h - 25, 45 + (i+1)*25 - 5, s->screen->h - 5, SDL_MapRGB(s->screen->format, 200, 0, 0));
    }


    SDL_Flip(s->screen);
}



GameEvent::GameEvent()
    : PL_AnyEvent()
{}

bool GameEvent::handleEvent(PL_State* state, SDL_Event& event)
{
    GameState* s = static_cast<GameState*>(state);

    if(s->player->checkInput(event, s))
        return true;

    if(event.type == SDL_QUIT)
        exit(0);

    if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)
    {
        s->player->boat->gold = -1;
        s->done = true;
    }

    return true;
}


