#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 "Timer.h"
#include "Kaos.h"
#include "TextBox.h"
#include "Player.h"
#include "Room.h"
#include "HyperKaos.h"
#include "Scene.h"

#include "extern.h"

Kaos* rawKaos()
{
  Kaos* self = malloc(sizeof(Kaos));
  self->next = NULL;
  return self;
}

Kaos* newConversation(int i)
{
  Kaos* core = rawKaos();
  Conversation* self = malloc(sizeof(Conversation));

  self->index = i;

  core->kType = self;
  self->core = core;
  core->run = &runConversation;
  core->destroy = &deleteConversation;
  return core;
}

void runConversation(Kaos* self)
{
  Conversation* kSelf = self->kType;
  displayTextBox(dialogueData[kSelf->index]);
}

void deleteConversation(Kaos* target)
{
  free(target->kType);
  free(target);
}

Kaos* newChoice(char* q, char* a1, char* a2, HyperKaos* p1, HyperKaos* p2)
{
  Kaos* core = rawKaos();
  Choice* self = malloc(sizeof(Choice));

  self->question = TTF_RenderText_Solid(font, q, textColor);
  self->answ1 = TTF_RenderText_Solid(font, a1, textColor);
  self->answ2 = TTF_RenderText_Solid(font, a2, textColor);
  self->path1 = p1;
  self->path2 = p2;

  core->kType = self;
  self->core = core;
  core->run = &runChoice;
  core->destroy = &deleteChoice;
  return core;
}

void runChoice(Kaos* self)
{
  Choice* kSelf = self->kType;
  int choice = 0;
  int textIsRelevent = 1;
  actionbutton = 0;
  while (textIsRelevent)
  {
    timeStart(fps);
    renderBackground();
    renderForeground();

    applySurface(22,73, choiceBox, screen, NULL);
    applySurface(74,76, kSelf->question, screen, NULL);

    applySurface(74,90, kSelf->answ1, screen, NULL);
    applySurface(180,90, kSelf->answ2, screen, NULL);

    switch(choice)
    {
      case 0: applySurface(59,86, selectArrow, screen, NULL); break;
      case 1: applySurface(165,86, selectArrow, screen, NULL); break;
    }

    while (SDL_PollEvent(&event))
    {
      switch (event.type)
      {
        case SDL_QUIT: quit = 1; playing = 0; textIsRelevent = 0; break;
        case SDL_KEYDOWN:
          switch(event.key.keysym.sym)
          {
             case DPAD_LEFT:
             case DPAD_RIGHT:
               if (choice == 0) choice = 1;
               else choice = 0;
               break;
             case A_BUTTON:
               textIsRelevent = 0;
               if (choice == 0) run(kSelf->path1);
               else run(kSelf->path2);
               break;
             case FS_BUTTON:
              toggleFullscreen();
              break;
            default: break;
          }
        default: break;
      }
    }
    SDL_Flip(screen);
    timeDilation();
  }
}

void deleteChoice(Kaos* self)
{
  Choice* kSelf = self->kType;
  SDL_FreeSurface(kSelf->question);
  SDL_FreeSurface(kSelf->answ1);
  SDL_FreeSurface(kSelf->answ2);
  free(self->kType);
  free(self);
}

Kaos* newManip(Player* t, int x, int y)
{
  Kaos* core = rawKaos();
  Manip* self = malloc(sizeof(Manip));

  self->target= t;
  self->xSpd = x;
  self->ySpd = y;

  core->kType = self;
  self->core = core;
  core->run = &runManip;
  core->destroy = &deleteManip;
  return core;
}

void runManip(Kaos* self)
{
  Manip* kSelf = self->kType;
  kSelf->target->bearing.x = kSelf->xSpd;
  kSelf->target->bearing.y = kSelf->ySpd;
}

void deleteManip(Kaos* target)
{
  free(target->kType);
  free(target);
}

Kaos* newLook(Player* t, char d)
{
  Kaos* core = rawKaos();
  Look* self = malloc(sizeof(Look));

  self->target = t;
  self->dir = d;

  self->core = core;
  core->kType = self;
  core->run = &runLook;
  core->destroy = &deleteLook;
  return core;
}

void runLook(Kaos* self)
{
  Look* kSelf = self->kType;
  SDL_Rect playerClip = { 0,0,16,16};
  switch(kSelf->dir)
  {
    case 'n':
      playerClip.x = 96;
      break;
    case 's':
      playerClip.x = 32;
      break;
    case 'e':
      playerClip.x = 64;
      break;
    case 'w':
    default:
      break;
  }
  changeSprite(kSelf->target, &playerClip);
}

void deleteLook(Kaos* target)
{
  free(target->kType);
  free(target);
}

Kaos* newTeleport(Player* p, int x, int y, int o)
{
  Kaos* core = rawKaos();
  Teleport* self = malloc(sizeof(Teleport));

  self->target = p;
  self->x = x;
  self->y = y;
  self->out = o;
  self->aura = loadImage("assets/img/fx/blkthunder.png");

  self->core = core;
  core->kType = self;
  core->run = &runTeleport;
  core->destroy = &deleteTeleport;
  return core;
}

void runTeleport(Kaos* self)
{
  Teleport* kSelf = self->kType;
  int i;
  SDL_Rect clip = {0,0,32,32};
  for (i = 0; i < 16; i++)
  {
    if (i == 11)
    {
      if (kSelf->out)
      {
        kSelf->target->point.x = -16;
        kSelf->target->point.y = -16;
      }
      else
      {
        kSelf->target->point.x = kSelf->x;
        kSelf->target->point.y = kSelf->y;
      }
    }
    clip.x = (i%4)*32;
    timeStart(fps);
    renderBackground();
    renderForeground();
    applySurface(kSelf->x-16, kSelf->y-16, kSelf->aura, screen, &clip);
    SDL_Flip(screen);
    timeDilation();
  }
}

void deleteTeleport(Kaos* target)
{
  Teleport* kSelf = target->kType;
  SDL_FreeSurface(kSelf->aura);
  free(target->kType);
  free(target);
}

Kaos* newFaceEachother(Player* p1, Player* p2)
{
  Kaos* core = rawKaos();
  FaceEachother* self = malloc(sizeof(FaceEachother));

  self->p1 = p1;
  self->p2 = p2;

  core->kType = self;
  self->core = core;
  core->run = &runFaceEachother;
  core->destroy = &deleteFaceEachother;
  return core;
}

void runFaceEachother(Kaos* self)
{
  FaceEachother* kSelf = self->kType;
  SDL_Rect p1Clip = {0,0,16,16};
  SDL_Rect p2Clip = {0,0,16,16};

  if (kSelf->p1->point.x > kSelf->p2->point.x)
    p2Clip.x = 64;

  if (kSelf->p1->point.x < kSelf->p2->point.x)
    p1Clip.x = 64;

  if (kSelf->p1->point.y > kSelf->p2->point.y)
  {
    p1Clip.x = 96;
    p2Clip.x = 32;
  }

  if (kSelf->p1->point.y < kSelf->p2->point.y)
  {
    p1Clip.x = 32;
    p2Clip.x = 96;
  }

  changeSprite(kSelf->p1, &p1Clip);
  changeSprite(kSelf->p2, &p2Clip);
}

void deleteFaceEachother(Kaos* target)
{
  free(target->kType);
  free(target);
}

#ifdef SOUND_ON
Kaos* newPlaySound(int i)
{
  Kaos* core = rawKaos();
  PlaySound* self = malloc(sizeof(PlaySound));

  self->i = i;

  core->kType = self;
  self->core = core;
  core->run = &runPlaySound;
  core->destroy = &deletePlaySound;
  return core;
}

void runPlaySound(Kaos* self)
{
  PlaySound* kSelf = self->kType;
  Mix_PlayChannel(-1, sfxData[kSelf->i], 0);
}

void deletePlaySound(Kaos* target)
{
  free(target->kType);
  free(target);
}
#endif

Kaos* newErase(char t, int i)
{
  Kaos* core = rawKaos();
  Erase* self = malloc(sizeof(Erase));

  self->type = t;
  self->index = i;

  self->core = core;
  core->kType = self;
  core->run = &runErase;
  core->destroy = &deleteErase;
  return core;
}

void runErase(Kaos* self)
{
  Erase* kSelf = self->kType;
  switch (kSelf->type)
  {
    case 'w':
      deleteWarp(rightHere, kSelf->index);
      break;
    case 't':
      deleteTrigger(rightHere, kSelf->index);
      break;
    case 'o':
      deleteObstacle(rightHere, kSelf->index);
      break;
    case 'f':
      deleteFgObj(rightHere, kSelf->index);
      break;
    case 's':
      deleteSigil(rightHere, kSelf->index);
      break;
    default:break;
  }
}

void deleteErase(Kaos* target)
{
  free(target->kType);
  free(target);
}

Kaos* newWait(char t, int i)
{
  Kaos* core = rawKaos();
  Wait* self = malloc(sizeof(Wait));

  self->type = t;
  self->frames = i;

  self->core = core;
  core->kType = self;
  core->run = &runWait;
  core->destroy = &deleteWait;
  return core;
}

void runWait(Kaos* self)
{
  Wait* kSelf = self->kType;
  int i;
  if (kSelf->type == 'f')
    captive = 1;

  for (i = 0; i < kSelf->frames; i++)
  {
    timeStart(fps);
    if (captive)
      interact();
    renderBackground();
    renderForeground();
    SDL_Flip(screen);
    timeDilation();
  }
  captive = 0;
}

void deleteWait(Kaos* target)
{
  free(target->kType);
  free(target);
}

Kaos* newSpell_Beam()
{
  Kaos* core = rawKaos();
  Spell_Beam* self = malloc(sizeof(Spell_Beam));

  self->core = core;
  core->kType = self;

  self->aura = loadImage("assets/img/fx/spellBeam.png");
  SDL_SetAlpha(self->aura, SDL_SRCALPHA|SDL_RLEACCEL, 124);
  core->run = &runSpell_Beam;
  core->destroy = &deleteSpell_Beam;

  return core;
}

void runSpell_Beam(Kaos* self)
{
  int i;
  char facing;
  SDL_Rect offset, clip;
  Spell_Beam* kSelf = self->kType;
  if (playerFaces(hero, 's'))
  {
    facing = 's';
    offset.x = hero->boundBox.x - hero->boundBox.w/2;
    offset.y = hero->boundBox.y + hero->boundBox.h;
    clip.x = 0;
    clip.y = 128;
    clip.w = 32;
    clip.h = 180;
  }
  else if (playerFaces(hero, 'w'))
  {
    facing = 'w';
    offset.x = hero->boundBox.x - SCREEN_WIDTH;
    offset.y = hero->boundBox.y - hero->boundBox.h/2;
    clip.x = 15;
    clip.y = 0;
    clip.w = 320;
    clip.h = 32;
  }
  else if (playerFaces(hero, 'e'))
  {
    facing = 'e';
    offset.x = hero->boundBox.x + hero->boundBox.w;
    offset.y = hero->boundBox.y - hero->boundBox.h/2;
    clip.x = 0;
    clip.y = 0;
    clip.w = 320;
    clip.h = 32;
  }
 else
 {
    facing = 'n';
    offset.x = hero->boundBox.x - hero->boundBox.w/2;
    offset.y =  hero->boundBox.y - SCREEN_HEIGHT;
    clip.x = 128;
    clip.y = 128;
    clip.w = 32;
    clip.h = 180;
  }

  for (i = 0; i < 16; i++)
  {
    timeStart(fps);
    renderBackground();
    renderForeground();
    switch (facing)
    {
      case 'n':
        clip.x = 128 + (i%4)*32;
        applySurface(offset.x, offset.y, kSelf->aura, screen, &clip);
        break;
      case 's':
        clip.x = (i%4)*32;
        applySurface(offset.x, offset.y, kSelf->aura, screen, &clip);
        break;
      case 'w':
      case 'e':
        clip.y = (i%4)*32;
        applySurface(offset.x, offset.y, kSelf->aura, screen, &clip);
       break;
    }
    SDL_Flip(screen);
    timeDilation();
  }
}

void deleteSpell_Beam(Kaos* target)
{
  Spell_Beam* kSelf = target->kType;

  SDL_FreeSurface(kSelf->aura);
  free(kSelf);
  free(target);
}