#include <iostream>
#include "SDL.h"
#include "gdlib.hpp"
#include "area.hpp"
#include "gfxlib.hpp"
#include "wm.hpp"

struct Shot {
    gdlib::Point pos;
    int speed;
    bool alive;
};

#define MAX_SHOTS   80
#define SHOT_VIS    MAX_VIS_STATES-1

class SpaceShip : public gdlib::Entity {
protected:
    Shot shots[MAX_SHOTS];
    int rate_of_fire;

public:
    SpaceShip();

    virtual void Fire();
    virtual void Draw();
};

void KeyHandler(const void *arg);
void MainLoop(const void *arg);

#define MOVE_DIST   4
//gdlib::Entity sship;
SpaceShip sship;
gdlib::Area area;

bool Init() {
    wm::SetHandler(wm::HTYPE_KEY, KeyHandler);
    wm::SetHandler(wm::HTYPE_IDLE, MainLoop);

    gfxlib::InitVideo(640, 480, false);

    sship.SetVisual(new gdlib::Image("data/sship.png"), 0);
    sship.SetVisual(new gdlib::Image("data/sship_left.png"), 1);
    sship.SetVisual(new gdlib::Image("data/sship_right.png"), 2);
    sship.SetVisual(new gdlib::Image("data/shot.png"), SHOT_VIS);
    sship.SetPosition(320, 400);

    area.AddLayer(new gdlib::Background("data/bg0_big.png"));
    area.AddLayer(new gdlib::Background("data/bg1_big.png"));
    area.SetVisible(gfxlib::MakeRect(0, 2400 - 480, 640, 2400));

    return true;
}

void MainLoop(const void *arg) {
    static unsigned long prev;

    while(SDL_GetTicks() - prev < 32);
    prev = SDL_GetTicks();

    sship.SetActiveState(0);

    if(wm::GetKeyState(SDLK_UP)) {
        sship.Move(0, -MOVE_DIST);
    }
    if(wm::GetKeyState(SDLK_DOWN)) {
        sship.Move(0, MOVE_DIST);
    }
    if(wm::GetKeyState(SDLK_LEFT)) {
        sship.SetActiveState(1);
        sship.Move(-MOVE_DIST, 0);
    }
    if(wm::GetKeyState(SDLK_RIGHT)) {
        sship.SetActiveState(2);
        sship.Move(MOVE_DIST, 0);
    }
    if(wm::GetKeyState(SDLK_SPACE)) {
        sship.Fire();
    }

    area.Move(0, -1);

    PixelBuffer *pbuf = gfxlib::Lock(0);

    gfxlib::Clear(pbuf, 0);

    area.SetSurface(pbuf);
    area.Draw();

    sship.SetSurface(pbuf);
    sship.Draw();

    gfxlib::Unlock(0);
    gfxlib::Flip();
}

void KeyHandler(const void *arg) {
    if(((wm::KeyHandlerArg*)arg)->key == 27) {
        gfxlib::CloseVideo();
        wm::ShutDown();
    }
}

int main() {

    if(!Init()) {
        std::cerr << "Initialization error\n";
        return 0;
    }

    wm::Run();
}

/////////////// SpaceShip implementation /////////////////

SpaceShip::SpaceShip() {
    memset(shots, 0, MAX_SHOTS * sizeof(Shot));
    rate_of_fire = 10;
}

void SpaceShip::Fire() {
    static unsigned long last_fire;

    if(SDL_GetTicks() - last_fire < 1000 / rate_of_fire) return;
    for(int i=0; i<MAX_SHOTS; i++) {
        if(!shots[i].alive) {
            shots[i].alive = true;
            shots[i].pos = gdlib::Point(pos.x, pos.y - 60);
            shots[i].speed = -10;
            last_fire = SDL_GetTicks();
            break;
        }
    }
}

void SpaceShip::Draw() {
    Entity::Draw();

    // advance all shots and check their lifespan
    for(int i=0; i<MAX_SHOTS; i++) {
        if(shots[i].alive) {
            shots[i].pos.y += shots[i].speed;
            if(shots[i].pos.y <= 0) shots[i].alive = false;

            vis[SHOT_VIS]->Set(gdlib::VS_POSITION, shots[i].pos.x, shots[i].pos.y);
            vis[SHOT_VIS]->Show();
        }
    }
}