#include <graphics.h>  // getpixel m.f
#include <stdlib.h>    // NULL, div_t
#include <ctype.h>     // toupper
#include <dos.h>       // sound, nosound
#include "worm.hpp"

WormPoint::WormPoint(int initX, int initY, int initColor) :
           Point(initX, initY, initColor)
{
  Next = Prev = NULL;
}

Worm::Worm()
{
  dead   = false;
  buried = false;

  Head = Tail = NULL;    // Det finns ingen mask fr†n start
}

void Worm::Setup( int InitX, int InitY,             // Initialisering
                  Direction InitDir, int InitColor,
                  char InitKeyR, char InitKeyL, char InitKeyT )
{
  dir       = InitDir;     // Initiera allm„nna data om spelaren
  key_right = InitKeyR;
  key_left  = InitKeyL;
  key_tail  = InitKeyT;
  dead      = false;
  buried    = false;
  grow      = true;
  color     = InitColor;
  length    = 0;
  cntr      = 0;
  score     = 0;
  head_x    = InitX;
  head_y    = InitY;
  Head = new WormPoint(2+InitX*5, 2+InitY*5, InitColor);
  Tail = Head;
}

void Worm::AddPoint(void)
{
  if (!grow || dead) // Hoppa ur om den ej skall v„xa
    return;          // eller om den „r d”d

  // Den nya noden skall ligga sist i listan ovanp† den sista noden
  WormPoint *N = new WormPoint(Tail->GetX(), Tail->GetY(), color);
  Tail->Next = N;
  N->Prev = Tail;
  Tail = N;

  length++;
  grow = false;
}

void Worm::RemovePoint()
{
  WormPoint *N = Head;
  Head = Head->Next;
  Head->Prev = NULL;
  delete(N);           // Ta bort punktens nod ifr†n listan

  if (length-- == 0)
    buried = true;
}

int Worm::Kollision(int c1, int c2, int c3, int c4, int c5)
{
  if (dead)
    return false; // Hoppa ur om masken „r d”d

  int c = getpixel(2+head_x*5, 2+head_y*5);
  return (c==c1 || c==c2 || c==c3 || c==c4 || c==c5);
}

void Worm::CheckKeys(char Ch)
{
  if (dead)
    return; // Hoppa ur om masken „r d”d

  Ch = toupper(Ch);
  if (Ch == key_right)   // Medurs
    switch (dir)
    {
      case up: dir = right; break;
      case right: dir = down; break;
      case down: dir = left; break;
      case left: dir = up; break;
    }

  if (Ch == key_left)    // Moturs
    switch (dir)
    {
      case up: dir = left; break;
      case left: dir = down; break;
      case down: dir = right; break;
      case right: dir = up; break;
    }

  if (Ch == key_tail)              // ™ka svansl„ngd
    grow = true;
}

void Worm::CalcNewPos()
{
  if (dead)
    return; // Hoppa ur om masken „r d”d

  switch (dir) {
    case right : head_x++; break;
    case down  : head_y++; break;
    case left  : head_x--; break;
    case up    : head_y--; break;
  }
}

void Worm::WormMove()
{
  if (dead)
    return; // Hoppa ur om masken „r d”d

  Tail->MoveTo(2 + head_x*5, 2 + head_y*5);

  if (Head != Tail) {
    Tail->Next = Head;
    Head->Prev = Tail;

    if (Head->Next == Tail) {   // Om det endast finns tv† punkter
      WormPoint* TempPtr = Head;
      Head = Tail;
      Tail = TempPtr;
    }
    else {
      Tail = Tail->Prev;
      Head = Head->Prev;
    }

    Head->Prev = NULL;
    Tail->Next = NULL;
  }
}

Boolean Worm::Bury(Boolean make_noice)
{
  if (!dead || buried)
    return false; // Hoppa ur om masken inte „r d”d eller redan begravd

  // Pip och blinka med maskens huvud ett par g†nger...
  if (++cntr < 40)
    switch (cntr % 6)
    {
      case 0:
        Head->Show(WHITE);
        if (make_noice)
          sound(200);
        break;

      case 3:
        Head->Show(color);
        if (make_noice)
          sound(400);
        break;
    }
  else { // ...och begrav sedan masken med en punkt per anrop
    if (Head) {
      RemovePoint(); // Ta bort huvudet (den f”rsta punkten)

      if (make_noice)
        if (length % 2 == 0)
          sound(800);
        else
          nosound();
    }
    else
      nosound();
  }
  return buried;
}
