#include <stdio.h>

#include "config.h"

#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_mixer.h"

#include "enum.h"
#include "Engine.h"
#include "Player.h"
#include "Room.h"
#include "HyperKaos.h"
#include "Synergy.h"

typedef struct timer Timer;
typedef struct textBox TextBox;
typedef struct scene Scene;
#include "extern.h"

Room* newRoom(char* filename, int a)
{
  Room* self = (Room*)malloc(sizeof(Room));

  self->obstacle = malloc(4*sizeof(SDL_Rect));
  self->numberOfObstacles = 0;
  self->maxNumberOfObstacles = 4;

  self->fgObject = malloc(4*sizeof(FGImage));
  self->numberOfObj = 0;
  self->maxNumberOfObj = 4;
  self->objSpeed = a;
  self->objIterator = 0;

  self->warps = malloc(4*sizeof(WarpZone));
  self->numberOfWarps = 0;
  self->maxNumberOfWarps = 4;

  self->eventTriggers = malloc(4*sizeof(HyperKaos*));
  self->numberOfTriggers = 0;
  self->maxNumberOfTriggers =4;

  self->people = malloc(4*sizeof(Player*));
  self->numberOfPeople = 0;
  self->maxNumberOfPeople = 4;

  self->sigils = malloc(4*sizeof(Synergy*));
  self->numberOfSigils = 0;
  self->maxNumberOfSigils = 4;

  SDL_Rect zeroRect;
  zeroRect.x=0;
  zeroRect.y=0;
  zeroRect.w=320;
  zeroRect.h=180;
  self->spriteSheet = loadImage(filename);
  self->bgImage = loadImage("assets/img/backgrounds/loading.gif");
  SDL_BlitSurface(self->spriteSheet, &zeroRect, self->bgImage, &zeroRect);
  self->frameNo = 0;

  return self;
}

void deleteRoom(Room* target)
{
  int i;
  free(target->obstacle);
  target->obstacle = NULL;

  for (i = 0; i < target->numberOfObj; i++)
  {
    SDL_FreeSurface(target->fgObject[i].spriteSheet);
    target->fgObject[i].spriteSheet = NULL;
  }
  free(target->fgObject);
  target->fgObject = NULL;

  free(target->warps);
  target->warps = NULL;

  for (i = 0; i < target->numberOfTriggers; i++)
  {
    deleteHyperKaos(target->eventTriggers[i]);
  }
  free(target->eventTriggers);
  target->eventTriggers = NULL;

  for (i = 0; i < target->numberOfPeople; i++)
  {
    killPlayer(target->people[i]);
  }
  free(target->people);


  SDL_FreeSurface(target->spriteSheet);
  SDL_FreeSurface(target->bgImage);
  target->spriteSheet = NULL;
  target->bgImage = NULL;

  free(target);
}

//
// room bg graphics
//

void changeRSprite(Room* self, SDL_Rect* clip)
{
  SDL_Rect zeroOffset;
  zeroOffset.x = 0;
  zeroOffset.y = 0;
  SDL_BlitSurface(self->spriteSheet, clip, self->bgImage, &zeroOffset);
}

void animate(Room* self)
{
  SDL_Rect animClip;
  animClip.w = 320;
  animClip.h = 180;
  animClip.x = 0;

  if (self->frameNo == 0)
  {
    animClip.y = 180;
    changeRSprite(self, &animClip);
  }
  if (self->frameNo == 10)
  {
    animClip.y = 360;
    changeRSprite(self, &animClip);
  }
  if (self->frameNo == 20)
  {
    animClip.y = 540;
    changeRSprite(self, &animClip);
  }
  if (self->frameNo == 30)
  {
    animClip.y = 360;
    changeRSprite(self, &animClip);
  }
  if (self->frameNo == 40)
  {
    animClip.y = 180;
    changeRSprite(self, &animClip);
  }
  if (self->frameNo == 50)
  {
    animClip.y = 0;
    changeRSprite(self, &animClip);
  }
  self->frameNo++;
  if (self->frameNo == 60) self->frameNo = 0;
}

//
// collision detection
//

int checkCollision(Room* self, Player* player, SDL_Rect* box)
{
  int i;

  for (i = 1; i <= self->numberOfObstacles; i++)
  {
    if (playerIsInRect(player, box))
//    if ( (playerX >= box->x && playerX <= box->x + box->w)
//         && (playerY >= box->y && playerY <= box->y + box->h) )
    {
      return 1;
    }
    box++;
  }
  return 0;
}

int checkWCollision(Room* self, SDL_Rect* player, WarpZone* warpBoxes, int* whichWarp)
{
  int i;
  int playerX = player->x + (player->w)/2;
  int playerY = player->y + (player->h)/2;

  for (i = 1; i <= self->numberOfWarps; i++)
  {
    if ( (playerX >= (warpBoxes->location).x && playerX <= (warpBoxes->location).x + (warpBoxes->location).w)
         && (playerY >= (warpBoxes->location).y && playerY <= (warpBoxes->location).y + (warpBoxes->location).h))
    {
      *whichWarp = i-1;
      return 1;
    }
    warpBoxes++;
  }
  return 0;
}

int checkKCollision(Room* self, SDL_Rect* player, HyperKaos** triggers, int* whichTrigger, int* kType)
{
  int i;
  int playerX = player->x + (player->w)/2;
  int playerY = player->y + (player->h)/2;

  for (i = 1; i <= self->numberOfTriggers; i++)
  {

      if ( (playerX > ((*triggers)->domain).x && playerX < ((*triggers)->domain).x + ((*triggers)->domain).w)
           && (playerY > ((*triggers)->domain).y && playerY < ((*triggers)->domain).y + ((*triggers)->domain).h) )
      {
        if ((*triggers)->eventType == 0)
        {
          *whichTrigger = i-1;
          *kType = 0;
          return 1;
        }
        else
        {
         *whichTrigger = i-1;
         *kType = 1;
         return 1;
        }
      }
    triggers++;
  }
  return 0;
}

//
// obstacles
//

void addObstacle(Room* self, int x, int y, int w, int h)
{
  int i;
  if (self->numberOfObstacles+1 > self->maxNumberOfObstacles)
  {
    self->maxNumberOfObstacles *= 2;
    SDL_Rect* temp = malloc(self->maxNumberOfObstacles*sizeof(SDL_Rect));
    for (i = 0; i < self->numberOfObstacles; i++)
      temp[i] = self->obstacle[i];
    free(self->obstacle);
    self->obstacle = temp;
    temp = NULL;
  }

  self->obstacle[self->numberOfObstacles].x = x;
  self->obstacle[self->numberOfObstacles].y = y;
  self->obstacle[self->numberOfObstacles].w = w;
  self->obstacle[self->numberOfObstacles].h = h;

  self->numberOfObstacles++;
}

void deleteObstacle(Room* self, int i)
{
  int j;
  SDL_Rect* temp = malloc(self->maxNumberOfObstacles*sizeof(SDL_Rect));
  for (j = 0; j < i; j++)
    temp[j] = self->obstacle[j];
  for (j = i + 1; j < self->numberOfObstacles; j++)
    temp[j-1] = self->obstacle[j];
  free(self->obstacle);
  self->obstacle = temp;
  temp = NULL;
  self->numberOfObstacles--;
}

//
// fg objects
//

void addFgObj(Room* self, int x, int y, int w, int h, char* filename, int f, int dual, int alpha)
{
  int i;
  if (self->numberOfObj+1 > self->maxNumberOfObj)
  {
    self->maxNumberOfObj *= 2;
    FGImage* temp = malloc(self->maxNumberOfObj*sizeof(FGImage));;
    for (i = 0; i < self->numberOfObj; i++)
      temp[i] = self->fgObject[i];
    free(self->fgObject);
    self->fgObject = temp;
    temp = NULL;
  }

  self->fgObject[self->numberOfObj].location.x = x;
  self->fgObject[self->numberOfObj].location.y = y;
  self->fgObject[self->numberOfObj].location.w = w;
  self->fgObject[self->numberOfObj].location.h = h;

  self->fgObject[self->numberOfObj].frames = f;
  self->fgObject[self->numberOfObj].frameNow = 0;
  self->fgObject[self->numberOfObj].dualLayer = dual;

  self->fgObject[self->numberOfObj].spriteSheet = loadImage(filename);
  if (alpha != 255)
    SDL_SetAlpha(self->fgObject[self->numberOfObj].spriteSheet, SDL_SRCALPHA|SDL_RLEACCEL, alpha);
  self->numberOfObj++;

}

void deleteFgObj(Room* self, int i)
{
  int j;
  FGImage* temp = malloc(self->maxNumberOfObj*sizeof(FGImage));
  for (j = 0; j < i; j++)
    temp[j] = self->fgObject[j];
  for (j = i + 1; j < self->numberOfObj; j++)
    temp[j-1] = self->fgObject[j];
  SDL_FreeSurface(self->fgObject[i].spriteSheet);
  free(self->fgObject);
  self->fgObject = temp;
  temp = NULL;
  self->numberOfObj--;
}

void drawFgObjects1(Room* self)
{
  int i;
  SDL_Rect clip;
  clip.y = 0;

  if (self->numberOfObj != 0)
  {
    self->objIterator++;

    for (i = 0; i < self->numberOfObj; i++)
    {
      clip.w = self->fgObject[i].location.w;
      clip.x = self->fgObject[i].frameNow*clip.w;
      clip.h = self->fgObject[i].location.h;
      applySurface(self->fgObject[i].location.x, self->fgObject[i].location.y, self->fgObject[i].spriteSheet, screen, &clip );
      if (self->objIterator == self->objSpeed)
        self->fgObject[i].frameNow++;
      if (self->fgObject[i].frameNow == self->fgObject[i].frames)
        self->fgObject[i].frameNow = 0;
    }
    if (self->objIterator == self->objSpeed)
      self->objIterator = 0;
  }
}

void drawFgObjects2(Room* self)
{
  int i;
  SDL_Rect clip;
  clip.y = 0;

  if (self->numberOfObj != 0)
  {
    self->objIterator++;

    for (i = 0; i < self->numberOfObj; i++)
    {
      if (self->fgObject[i].dualLayer)
      {
        clip.w = self->fgObject[i].location.w;
        clip.x = self->fgObject[i].frameNow*clip.w;
        clip.h = self->fgObject[i].location.h;
        clip.y = clip.h;
        applySurface(self->fgObject[i].location.x, self->fgObject[i].location.y, self->fgObject[i].spriteSheet, screen, &clip );
        if (self->objIterator == self->objSpeed)
          self->fgObject[i].frameNow++;
        if (self->fgObject[i].frameNow == self->fgObject[i].frames)
          self->fgObject[i].frameNow = 0;
      }
    }
    if (self->objIterator == self->objSpeed)
      self->objIterator = 0;
  }
}

//
// warps
//

void addWarp(Room* self, int x, int y, int w, int h, enum dataChunks toChunk, int goesTo, int goesX, int goesY)
{
  int i;
  if (self->numberOfWarps+1 > self->maxNumberOfWarps)
  {
    self->maxNumberOfWarps *= 2;
    WarpZone* temp = malloc(self->maxNumberOfWarps*sizeof(WarpZone));
    for (i = 0; i < self->numberOfWarps; i++)
      temp[i] = self->warps[i];
    free(self->warps);
    self->warps = temp;
    temp = NULL;
  }

  self->warps[self->numberOfWarps].x = goesX;
  self->warps[self->numberOfWarps].y = goesY;

  self->warps[self->numberOfWarps].location.x = x;
  self->warps[self->numberOfWarps].location.y = y;
  self->warps[self->numberOfWarps].location.w = w;
  self->warps[self->numberOfWarps].location.h = h;

  self->warps[self->numberOfWarps].chunk = toChunk;
  self->warps[self->numberOfWarps++].destination = goesTo;

}

void deleteWarp(Room* self, int i)
{
  int j;
  WarpZone* temp = malloc(self->maxNumberOfWarps*sizeof(WarpZone));
  for (j = 0; j < i; j++)
    temp[j] = self->warps[j];
  for (j = i + 1; j < self->numberOfWarps; j++)
    temp[j-1] = self->warps[j];
  free(self->warps);
  self->warps = temp;
  temp = NULL;
  self->numberOfWarps--;
}

//
// event triggers
//

void addTrigger(Room* self, HyperKaos* newTrigger)
{
  int i;
  if (self->numberOfTriggers+1 > self->maxNumberOfTriggers)
  {
    self->maxNumberOfTriggers *= 2;
    HyperKaos** temp = malloc(self->maxNumberOfTriggers*sizeof(HyperKaos*));
    for (i = 0; i < self->numberOfTriggers; i++)
      temp[i] = self->eventTriggers[i];
    free(self->eventTriggers);
    self->eventTriggers = temp;
    temp = NULL;
  }

  self->eventTriggers[self->numberOfTriggers++] = newTrigger;
}

void deleteTrigger(Room* self, int i)
{
  int j;
  HyperKaos** temp = malloc(self->maxNumberOfTriggers*sizeof(HyperKaos*));
  for (j = 0; j < i; j++)
    temp[j] = self->eventTriggers[j];
  for (j = i + 1; j < self->numberOfTriggers; j++)
    temp[j-1] = self->eventTriggers[j];
  deleteHyperKaos(self->eventTriggers[i]);
  free(self->eventTriggers);
  self->eventTriggers = temp;
  temp = NULL;
  self->numberOfTriggers--;
}

void addSigil(Room* self, Synergy* newSigil)
{
  int i;
  if (self->numberOfSigils+1 > self->maxNumberOfSigils)
  {
    self->maxNumberOfSigils *= 2;
    Synergy** temp = malloc(self->maxNumberOfSigils*sizeof(Synergy*));
    for (i = 0; i < self->numberOfSigils; i++)
      temp[i] = self->sigils[i];
    free(self->sigils);
    self->sigils = temp;
    temp = NULL;
  }

  self->sigils[self->numberOfSigils++] = newSigil;
}

void deleteSigil(Room* self, int i)
{
  int j;
  Synergy** temp = malloc(self->maxNumberOfSigils*sizeof(Synergy*));
  for (j = 0; j < i; j++)
    temp[j] = self->sigils[j];
  for (j = i + 1; j < self->numberOfSigils; j++)
    temp[j-1] = self->sigils[j];
  deleteSynergy(self->sigils[i]);
  free(self->sigils);
  self->sigils = temp;
  temp = NULL;
  self->numberOfSigils--;
}

void addPerson(Room* self,  Player* newPlayer)
{
  int i;
  if (self->numberOfPeople+1 > self->maxNumberOfPeople)
  {
    self->maxNumberOfPeople *= 2;
    Player** temp = malloc(self->maxNumberOfPeople*sizeof(Player*));
    for (i = 0; i < self->numberOfPeople; i++)
      temp[i] = self->people[i];
    free(self->people);
    self->people = temp;
    temp = NULL;
  }

  self->people[self->numberOfPeople++] = newPlayer;
}

void deletePerson(Room* self, int i)
{
  int j;
  Player** temp = malloc(self->maxNumberOfPeople*sizeof(Player*));
  for (j = 0; j < i; j++)
    temp[j] = self->people[j];
  for (j = i + 1; j < self->numberOfPeople; j++)
    temp[j-1] = self->people[j];
  killPlayer(self->people[i]);
  free(self->people);
  self->people = temp;
  temp = NULL;
  self->numberOfPeople--;
}

void drawPeople(Room* self)
{
  int i;
  for (i = 0; i < self->numberOfPeople; i++)
  {
    drawPlayer(self->people[i]);
  }
}

//
// warp
//

void warpto(Room* destination)
{
  rightHere = destination;
}

