#include "light.h"
#include "macros.h"

void Lights::GL(double time = 0.0)
{
  if(__entity_list.size()==0)
    return;
  glDisable(GL_LIGHT0);
  glDisable(GL_LIGHT1);
  glDisable(GL_LIGHT2);
  glDisable(GL_LIGHT3);
  glDisable(GL_LIGHT4);
  glDisable(GL_LIGHT5);
  glDisable(GL_LIGHT6);
  glDisable(GL_LIGHT7);
  __entity_list.rewind();
  int i = (__entity_list.size()>8) ? 8 : __entity_list.size();
  switch(i)
  {
    case 8:
      (*__entity_list)->GL(GL_LIGHT7, time);
      ++__entity_list;
      glEnable(GL_LIGHT7);
    case 7:
      (*__entity_list)->GL(GL_LIGHT6, time);
      ++__entity_list;
      glEnable(GL_LIGHT6);
    case 6:
      (*__entity_list)->GL(GL_LIGHT5, time);
      ++__entity_list;
      glEnable(GL_LIGHT5);
    case 5:
      (*__entity_list)->GL(GL_LIGHT4, time);
      ++__entity_list;
      glEnable(GL_LIGHT4);
    case 4:
      (*__entity_list)->GL(GL_LIGHT3, time);
      ++__entity_list;
      glEnable(GL_LIGHT3);
    case 3:
      (*__entity_list)->GL(GL_LIGHT2, time);
      ++__entity_list;
      glEnable(GL_LIGHT2);
    case 2:
      (*__entity_list)->GL(GL_LIGHT1, time);
      ++__entity_list;
      glEnable(GL_LIGHT1);
    case 1:
      (*__entity_list)->GL(GL_LIGHT0, time);
      ++__entity_list;
      glEnable(GL_LIGHT0);
      break;
  }
}

LightGL::LightGL () {
  Reset();
}

void LightGL::Reset ()
{
  ambient[0] = ambient[1] = ambient[2] = 0.0F; ambient[3] = 1.0F;
  diffuse[0] = diffuse[1] = diffuse[2] = 0.0F; diffuse[3] = 1.0F;
  specular[0] = specular[1] = specular[2] = 0.0F; specular[3] = 1.0F;
  position[0] = position[1] = position[2] = 0.0F; position[4] = 1.0F;
  spot_direction[0] = spot_direction[1] = 0.0; spot_direction[2] = -1.0F;

  spot_exponent = 0.0F;
  spot_cutoff = 180.0F;
  constant_attenuation = 1.0F;
  linear_attenuation = 0.0F;
  quadratic_attenuation = 0.0F;
}

void LightGL::GL (GLenum light, double time = 0.0)
{
  glLightfv(light, GL_AMBIENT, ambient);
  glLightfv(light, GL_DIFFUSE, diffuse);
  glLightfv(light, GL_SPECULAR, specular);
  glLightfv(light, GL_POSITION, position);
  glLightfv(light, GL_SPOT_DIRECTION, spot_direction);

  glLightf(light, GL_SPOT_EXPONENT, spot_exponent);
  glLightf(light, GL_SPOT_CUTOFF, spot_cutoff);
  glLightf(light, GL_CONSTANT_ATTENUATION, constant_attenuation);
  glLightf(light, GL_LINEAR_ATTENUATION, linear_attenuation);
  glLightf(light, GL_QUADRATIC_ATTENUATION, quadratic_attenuation);
}

void LightGL::Ambient (GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0F) {
  SetVector4(ambient, r, g, b, a);
}
void LightGL::Diffuse (GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0F) {
  SetVector4(diffuse, r, g, b, a);
}
void LightGL::Specular (GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0F) {
  SetVector4(specular, r, g, b, a);
}
void LightGL::Ambient (GLfloat* v) {
  SetVector4(ambient, *v, *(v+1), *(v+2), *(v+3));
}
void LightGL::Diffuse (GLfloat* v) {
  SetVector4(diffuse, *v, *(v+1), *(v+2), *(v+3));
}
void LightGL::Specular (GLfloat* v) {
  SetVector4(specular, *v, *(v+1), *(v+2), *(v+3));
}

void LightGL::Position (GLfloat x, GLfloat y, GLfloat z, GLfloat w = 1.0F) {
  SetVector4(position, x, y, z, w);
}
void LightGL::Position (GLfloat* v) {
  SetVector4(position, *v, *(v+1), *(v+2), *(v+3));
}

void LightGL::SpotDirection (GLfloat i, GLfloat j, GLfloat k) {
  SetVector3(spot_direction, i, j, k);
}
void LightGL::SpotDirection (GLfloat* v) {
  SetVector3(spot_direction, *v, *(v+1), *(v+2));
}

void LightGL::SpotExponent (GLfloat f) {
  spot_exponent = f;
}
void LightGL::SpotCutoff (GLfloat f) {
  spot_cutoff = f;
}
void LightGL::ConstantAttenuation (GLfloat f) {
  constant_attenuation = f;
}
void LightGL::LinearAttenuation (GLfloat f) {
  linear_attenuation = f;
}
void LightGL::QuadraticAttenuation (GLfloat f) {
  quadratic_attenuation = f;
}

const GLfloat* LightGL::Ambient () {
  return ambient;
}
const GLfloat* LightGL::Diffuse () {
  return diffuse;
}
const GLfloat* LightGL::Specular () {
  return specular;
}
const GLfloat* LightGL::Position () {
  return position;
}
const GLfloat* LightGL::SpotDirection () {
  return spot_direction;
}

GLfloat LightGL::SpotExponent () {
  return spot_exponent;
}
GLfloat LightGL::SpotCutoff () { 
  return spot_cutoff;
}
GLfloat LightGL::ConstantAttenuation () {
  return constant_attenuation;
}
GLfloat LightGL::LinearAttenuation () {
  return linear_attenuation;
}
GLfloat LightGL::QuadraticAttenuation () {
  return quadratic_attenuation;
}
