#include <zf.h>

#define WINDOW_WIDTH  800
#define WINDOW_HEIGHT 600

static bool   done = false;
static GLuint fx_texture_id;

static float  camera_zoom = 10.0f;

CLvertex drone_location;

CLlight  light;

static GLfloat    view_rotx = 0.0;
static GLfloat    view_roty = 0.0;
static GLfloat    view_rotz = 0.0;
static float      begin_x = 0.0;
static float      begin_y = 0.0;
static unsigned int mouse_x;
static unsigned int mouse_y; /* 2D mouse coords from SDL */
static bool         mouse_down = false;

static void init_SDL(void)
{
    const SDL_VideoInfo* info;
  
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
	exit(1);
  
    info = SDL_GetVideoInfo();
  
    if (!info)
	exit(1);
   
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  
    if (SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT,
			 info->vfmt->BitsPerPixel,
			 SDL_OPENGL) == 0)
			 /* SDL_OPENGL | SDL_FULLSCREEN) == 0) */
	exit(1);
  
    SDL_WM_SetCaption("My Flux Asplode!", 0);

    /*
      SDL_WM_GrabInput(SDL_GRAB_ON);
      SDL_ShowCursor(SDL_DISABLE);
    */
}

static void init_GL(void)
{
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}

static void close_SDL(void)
{
    SDL_Quit();
}

/* the "real stuff" */

static void
init(void)
{
    srand(time(0)); /* why not? */

    init_SDL();
    init_GL();

    /* initialise a light source */
    clDefaultLight(&light);

    cluSetColour(&light.ambient, 0.0f, 0.0f, 0.0f, 1.0f);
    cluSetColour(&light.diffuse, 1.0f, 1.0f, 1.0f, 1.0f);
    light.position[0] = 0.0f;
    light.position[1] = 0.0f;
    light.position[2] = 0.0f;
    light.position[3] = 1.0f;

    clPrintLight(&light);
}

static void
close(void)
{
    close_SDL();
}

static void
handle_key_down(SDL_keysym* keysym)
{
    switch(keysym->sym)
    {
    case SDLK_ESCAPE:
	printf("escape\n");
	done = true;
	break;

    case SDLK_UP:
	printf("zoom in\n");
	camera_zoom -= 1.0f;
	break;

    case SDLK_DOWN:
	printf("zoom out\n");
	camera_zoom += 1.0f;
	break;

    case SDLK_e:
	{
	    printf("new explosion\n");
	    
	    zf_explosion_new(&drone_location, 2.0f);
	}

	break;

    case SDLK_l:
	light.position[2] = 0.0f;
	break;

    case SDLK_c:
	{
	    CLvertex start_vertex;
	    printf("new collider\n");

	    cluSetVertex(&start_vertex,
			 3.0f,
			 0.0f,
			 10.0f);
	    
	    zf_missile_new(&start_vertex,
			   0.05f,
			   &drone_location,
			   0,
			   0);
	}
	break;

    default:
	break;
    }
}

static void
handle_mouse_state(void)
{
    Uint8 mouse_state;

    /* update 2d mouse pos */
    mouse_state = SDL_GetMouseState(&mouse_x, &mouse_y);

    if (mouse_down)
    {
	view_rotx += ((GLfloat)(begin_y - mouse_y) / WINDOW_HEIGHT) * CL_PI;
	view_roty += ((GLfloat)(begin_x - mouse_x) / WINDOW_WIDTH) * CL_PI;
    }

    begin_x = mouse_x;
    begin_y = mouse_y;
}

static void
process_events(void)
{
    SDL_Event event;
   
    while(SDL_PollEvent(&event))
    {
	switch(event.type)
	{
	case SDL_KEYDOWN:
	    /* Handle key presses. */
	    handle_key_down(&event.key.keysym);
	    break;
	    
	case SDL_MOUSEBUTTONDOWN:
	    mouse_down = true;
	    break;
	    
	case SDL_MOUSEBUTTONUP:
	    mouse_down = false;
	    break;

	case SDL_QUIT:
	    /* Handle quit requests (like Ctrl-c). */
	    done = true;
	    break;
	}
    }

    handle_mouse_state();
}

static void
draw_screen(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();

    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -camera_zoom);
    glRotatef (CL_RAD2DEG(view_rotx), 1.0, 0.0, 0.0);
    glRotatef (CL_RAD2DEG(view_roty), 0.0, 1.0, 0.0);
    glRotatef (CL_RAD2DEG(view_rotz), 0.0, 0.0, 1.0);

    glEnable(GL_LIGHTING);
    glEnable(light.id);
    clLoadLight(&light);

    /* render scene */
    zf_render_system_step();

#if 0
    /* render made up scene */
    glPushMatrix();
    glTranslatef(2.0f, 0.0f, 0.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glutSolidSphere(0.8f, 16, 16);
    glPopMatrix();
#endif

    /* render light source */    
    glDisable(GL_LIGHTING);
    glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
    glPushMatrix();
    glTranslatef(light.position[0], light.position[1], light.position[2]);
    //glutSolidSphere(0.1f, 16, 16);
    glPointSize(8.0f);
    glBegin(GL_POINTS);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glEnd();
    glPopMatrix();

    /* render axis */
    glBegin(GL_LINES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, 0.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 1.0f, 0.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.0f, 1.0f);
    glEnd();

#if 0
    /* render debug text */
    {
	char string[8];

	glDisable(GL_LIGHTING);

	glPushMatrix();
	glLoadIdentity();
	
	/* WHITE */
	glColor3f(1.0f, 1.0f, 1.0f);
	
	/* animators */
	glPushMatrix();
	glTranslatef(-22.0f, -10.0f, -30.0f);
	zf_text_draw("animators");
	glPopMatrix();

	glPushMatrix();
	sprintf(string, "%u", zf_animation_system_get_animator_count());
	glTranslatef(-8.0f, -10.0f, -30.0f);
	zf_text_draw(string);
	glPopMatrix();
	
	/* colliders */
	glPushMatrix();
	glTranslatef(-22.0f, -12.0f, -30.0f);
	zf_text_draw("colliders");
	glPopMatrix();

	glPushMatrix();
	sprintf(string, "%u", zf_collision_system_get_collider_count());
	glTranslatef(-8.0f, -12.0f, -30.0f);
	zf_text_draw(string);
	glPopMatrix();

	/* particles */
	glPushMatrix();
	glTranslatef(-22.0f, -14.0f, -30.0f);
	zf_text_draw("particles");
	glPopMatrix();

	glPushMatrix();
	sprintf(string, "%u", zf_particle_system_get_particle_count());
	glTranslatef(-8.0f, -14.0f, -30.0f);
	zf_text_draw(string);
	glPopMatrix();

	/* render */
	glPushMatrix();
	glTranslatef(-22.0f, -16.0f, -30.0f);
	zf_text_draw("renderables");
	glPopMatrix();

	glPushMatrix();
	sprintf(string, "%u", zf_render_system_get_renderable_count());
	glTranslatef(-8.0f, -16.0f, -30.0f);
	zf_text_draw(string);
	glPopMatrix();

	glPopMatrix();
    }
#endif

	       glPopMatrix();

    glFlush();
    glFinish();
    SDL_GL_SwapBuffers();
}

int
main_loop(void)
{
    Uint32 game_time;
    Uint32 lt;
    Uint32 t;
    double viewport[4];

    glGetDoublev(GL_VIEWPORT, viewport);
   
    lt = SDL_GetTicks();
    done = 0;

    glPushAttrib(GL_ALL_ATTRIB_BITS);

    /* load a projection matrix that matches the window aspect ratio */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (double)viewport[2]/(double)viewport[3], 0.1, 512.0);

    /* reset the modelview matrix */
    glMatrixMode(GL_MODELVIEW);

    game_time = SDL_GetTicks();

    while(!done)
    {
	/* time for game slice */
	t = SDL_GetTicks();
	lt = t;

	process_events();
	
	while ((t - game_time) > ZF_TIME_STEP)
	{
  
	    zf_animation_system_step();
	    zf_collision_system_step();
	    
	    game_time += ZF_TIME_STEP;
	}
	
	draw_screen();

#if 1
	/* update position of light source */
	light.position[2]+=1.0;
#endif
    }
   
    glPopAttrib();

    return 0;
}

int
main(int argc, char* argv[])
{
    // nickl - required to use glut primitives
    glutInit(&argc, argv);

    /* clioEnable(CLIO_VERBOSE); */

    init();

    /* init subsystems */
    zf_animation_system_init();
    zf_collision_system_init();
    zf_render_system_init();
    zf_particle_system_init();
    zf_camera_init();
    zf_heightmap_init("../data/level/heightmap.zf");
    zf_missile_init();
    zf_explosion_init();
    zf_drone_init("../data/level/drones_empty.zf");
    zf_drone_pickup_init();

    /* add drone to scene */
    printf("adding drone\n");
    cluSetVertex(&drone_location, -3.0f, 0.0f, 0.0f);
    zf_drone_new(1, &drone_location);

    /* run a loop */
    main_loop();

    /* close subsystems */
    zf_drone_close();
    zf_explosion_close();
    zf_missile_close();
    zf_heightmap_close();
    zf_camera_close();
    zf_particle_system_close();
    zf_render_system_close();
    zf_collision_system_close();
    zf_animation_system_close();

    close();
    
    return 0;
}
