#include "trolledit.h"
#include <getopt.h>

#define FANWOR_WALL  1
#define FANWOR_WATER 2

#define FANWOR_MONSTER 1
#define FANWOR_DOOR    2
#define FANWOR_ITEM    4

#define FANWOR_SPRITE_GEM 15

class FanworThing;

class FanworScreen
{
 public:
  FanworScreen(char *fname);
  ~FanworScreen();

  IUShort width, height;
  IUByte *background;
  IUByte *passability;
  IUShort thingNum;
  FanworThing **things;
};

class FanworThing
{
 public:
  FanworThing(BinaryReadFile &f);
  ~FanworThing();

  IUByte type;
  IUByte info; /* Sprite for monsters and Destination level for doors. */
  IUByte x, y;
  IUByte screenX, screenY;
  IUByte special1, special2;
};

FanworScreen::FanworScreen(char *fname)
{
 IULong magic;
 BinaryReadFile f(fname);
 f.readULong(magic);
 if (0x4641574FL/*'FAWO*/ == magic)
 {
  // Correct
 }
 else if (0x4F574146L/*'FAWO*/ == magic)
 {
  f.setSwap(true);
 }
 f.seek(38);
 f.readUShort(thingNum);
 f.readUShort(width);
 f.readUShort(height);
 background = new IUByte[width * height];
 f.readUByteArray(width * height, background);
 passability = new IUByte[width * height];
 f.readUByteArray(width * height, passability);
 things = new (FanworThing *)[thingNum];
 for (int i = 0; i < thingNum; i++)
 {
  things[i] = new FanworThing(f);
 }
}

FanworScreen::~FanworScreen()
{
 delete [] background;
 delete [] passability;
 for (int i = 0; i < thingNum; i++)
 {
  delete things[i];
 }
 delete [] things;
}

FanworThing::FanworThing(BinaryReadFile &f)
{
 f.readUByte(type);
 f.readUByte(info);
 f.readUByte(x);
 f.readUByte(y);
 f.readUByte(screenX);
 f.readUByte(screenY);
 f.readUByte(special1);
 f.readUByte(special2);
}

FanworThing::~FanworThing()
{
}

void ConvertFanworToTroll(TrollEditScreen &trollScreen, const FanworScreen &fanworScreen)
{
 int x, y;
 int i, k;
 char *levelName;
 IUShort num;

 trollScreen.clear();
 /* Background squares */
 for (y = 0; y < TROLL_SCREEN_Y; y++)
 {
  for (x = 0; x < TROLL_SCREEN_X; x++)
  {
   trollScreen.backgroundPics[x][y] =
     fanworScreen.background[x + y * fanworScreen.width] + TROLL_SPRITE_CLEAR;
  }
 }
 /* Passibility information */
 for (y = 0; y < TROLL_SCREEN_Y; y++)
 {
  for (x = 0; x < TROLL_SCREEN_X; x++)
  {
   if (fanworScreen.passability[x + y * fanworScreen.width] & FANWOR_WATER)
   {
    trollScreen.passability[x][y] = TROLL_WATER;
   }
   else if (fanworScreen.passability[x + y * fanworScreen.width] & FANWOR_WALL)
   {
    trollScreen.passability[x][y] = TROLL_BLOCKED;
   }
  }
 }

 trollScreen.exitNum = 0;
 for (i = 0; i < fanworScreen.thingNum; i++)
 {
  switch (fanworScreen.things[i]->type)
  {
   case FANWOR_DOOR:
    trollScreen.exitNum++;
    break;
   default:
    break;
  }
 }

 /* Exit conversion rules:
  1. When going to the overworld, entrance the above the destination square
  2. Otherwise convert destination to the lowest three rows go to the
    bottom square
  3. All others go to the destination square
 */
 trollScreen.exits = (TrollExit **)realloc(trollScreen.exits, trollScreen.exitNum * sizeof(TrollExit *));
 for (i = k = 0; i < fanworScreen.thingNum; i++)
 {
  if (FANWOR_DOOR == fanworScreen.things[i]->type)
  {
   x = TROLL_CALCULATE_X_POS(fanworScreen.things[i]->x);
   if (fanworScreen.things[i]->y < TROLL_SCREEN_Y)
   {
    y = TROLL_CALCULATE_Y_POS(fanworScreen.things[i]->y);
   }
   else
   {
    y = TROLL_CALCULATE_Y_POS(TROLL_SCREEN_Y - 1);
   }
   levelName = strdup("level0.trb");
   levelName[5] = '0' + fanworScreen.things[i]->info;
   trollScreen.exits[k] = new TrollExit(x, y, levelName,
     fanworScreen.things[i]->special1 >> 4,
     fanworScreen.things[i]->special1 & 0x0F);
   free(levelName);
   trollScreen.exits[k]->setNewX(TROLL_CALCULATE_X_POS(fanworScreen.things[i]->screenX));
   if (fanworScreen.things[i]->info == 0)
   {
    trollScreen.exits[k]->setNewY(TROLL_CALCULATE_Y_POS(fanworScreen.things[i]->screenY - 1) + (TROLL_SQUARE_Y / 4));
   }
   else if (fanworScreen.things[i]->screenY >= TROLL_SCREEN_Y - 1)
   {
    trollScreen.exits[k]->setNewY(TROLL_CALCULATE_Y_POS(TROLL_SCREEN_Y - 1) - (TROLL_SQUARE_Y / 4));
   }
   else
   {
    trollScreen.exits[k]->setNewY(TROLL_CALCULATE_Y_POS(fanworScreen.things[i]->screenY));
   }
   k++;
  }
 }

 /* Expand exits next to one another (does not check above and below yet) */
 num = trollScreen.exitNum;
 for (i = 0; i < num; i++)
 {
  for (k = i + 1; k < num; k++)
  {
   if (trollScreen.exits[i]->getY() == trollScreen.exits[k]->getY())
   {
    if (trollScreen.exits[i]->getX() == trollScreen.exits[k]->getX() + TROLL_SQUARE_X)
    {
     trollScreen.exits = (TrollExit **)realloc(trollScreen.exits, (trollScreen.exitNum + 3) * sizeof(TrollExit *));
     for (x = trollScreen.exits[k]->getX() + TROLL_SQUARE_X / 4;
       x < trollScreen.exits[i]->getX(); x += TROLL_SQUARE_X / 4)
     {
      trollScreen.exits[trollScreen.exitNum] = new TrollExit(x,
        trollScreen.exits[k]->getY(), trollScreen.exits[k]->getLevelName(),
        trollScreen.exits[k]->getNewScreenX(),
        trollScreen.exits[k]->getNewScreenY(),
        trollScreen.exits[k]->getNewX(),
        trollScreen.exits[k]->getNewY());
      trollScreen.exitNum++;
     }
    }
    else if (trollScreen.exits[i]->getX() + TROLL_SQUARE_X == trollScreen.exits[k]->getX())
    {
     trollScreen.exits = (TrollExit **)realloc(trollScreen.exits, (trollScreen.exitNum + 3) * sizeof(TrollExit *));
     for (x = trollScreen.exits[i]->getX() + TROLL_SQUARE_X / 4;
       x < trollScreen.exits[k]->getX(); x += TROLL_SQUARE_X / 4)
     {
      trollScreen.exits[trollScreen.exitNum] = new TrollExit(x,
        trollScreen.exits[i]->getY(), trollScreen.exits[i]->getLevelName(),
        trollScreen.exits[i]->getNewScreenX(),
        trollScreen.exits[i]->getNewScreenY(),
        trollScreen.exits[i]->getNewX(),
        trollScreen.exits[i]->getNewY());
      trollScreen.exitNum++;
     }
    }
   }
  }
 }

 /* Item conversion */
 for (i = 0; i < fanworScreen.thingNum; i++)
 {
  switch (fanworScreen.things[i]->type)
  {
   case FANWOR_ITEM:
   {
    trollScreen.secrets = (TrollEditSecret **)realloc(trollScreen.secrets, (trollScreen.secretNum + 1) * sizeof(TrollEditSecret *));
    trollScreen.secrets[trollScreen.secretNum] = new TrollEditSecret;
    trollScreen.secrets[trollScreen.secretNum]->secretNum = fanworScreen.things[i]->info - FANWOR_SPRITE_GEM;
    trollScreen.secrets[trollScreen.secretNum]->unsetScriptSize = 10;
    trollScreen.secrets[trollScreen.secretNum]->unsetScript = (IUByte *)realloc(trollScreen.secrets[trollScreen.secretNum]->unsetScript, trollScreen.secrets[trollScreen.secretNum]->unsetScriptSize * sizeof(IUByte));
    trollScreen.secrets[trollScreen.secretNum]->unsetScript[0] = 0x02;
    trollScreen.secrets[trollScreen.secretNum]->unsetScript[1] = fanworScreen.things[i]->info - FANWOR_SPRITE_GEM;
    trollScreen.secrets[trollScreen.secretNum]->unsetScript[2] = 0x00;
    num = TROLL_CALCULATE_X_POS(fanworScreen.things[i]->x);
    IMemcpy(trollScreen.secrets[trollScreen.secretNum]->unsetScript + 3, &num, sizeof(IUShort));
    num = TROLL_CALCULATE_Y_POS(fanworScreen.things[i]->y);
    IMemcpy(trollScreen.secrets[trollScreen.secretNum]->unsetScript + 5, &num, sizeof(IUShort));
    trollScreen.secrets[trollScreen.secretNum]->unsetScript[7] = fanworScreen.things[i]->info - FANWOR_SPRITE_GEM;
    trollScreen.secrets[trollScreen.secretNum]->unsetScript[8] = 0x00;
    trollScreen.secrets[trollScreen.secretNum]->unsetScript[9] = 0x00;
    trollScreen.secrets[trollScreen.secretNum]->setScriptSize = 1;
    trollScreen.secrets[trollScreen.secretNum]->setScript = (IUByte *)realloc(trollScreen.secrets[trollScreen.secretNum]->setScript, trollScreen.secrets[trollScreen.secretNum]->setScriptSize * sizeof(IUByte));
    trollScreen.secrets[trollScreen.secretNum]->setScript[0] = 0x00;
    trollScreen.secretNum++;
   }
  }
 }
}

void ParseCommandLine(int argc, char *argv[], char *inname, char *outname);

int main(int argc, char *argv[])
{
 char inname[255];
 char outname[255];

 ParseCommandLine(argc, argv, inname, outname);
 FanworScreen fanworScreen(inname);
 TrollEditScreen trollScreen;
 ConvertFanworToTroll(trollScreen, fanworScreen);
 trollScreen.filename = strdup(outname);
 trollScreen.save();
 return 0;
}

void ParseCommandLine(int argc, char *argv[], char *inname, char *outname)
{
 char opt;
 int i;
 char *defpal;
 static struct option long_options[] =
 {
  {0, 0, 0, 0}
 };

 while ((opt = getopt_long(argc, argv,"h?", long_options, NULL))!=EOF)
 {
  switch (opt)
  {
   case 'h':
   case '?':
    printf("\
Converts a Fanwor room file into a Troll Bridge scr file\n\
\n\
room2scr inname [outname[.scr]]\n\
\n\
  inname           Name of input file\n\
  [outname[.scr]]  Name of output file (defaults to input file name)\n\
");
    exit(0);
    break;
   default:
    break;
  }
 }
 if ((argc - optind < 1) || (argc - optind > 2))
 {
  printf("Incorrect number of parameters\n");
  exit(4);
 }
 strcpy(inname, argv[optind]);
 if (argc - optind == 2)
 {
  strcpy(outname, argv[optind + 1]);
  if (strcmp(outname + strlen(outname) - 4, ".scr") != 0)
  {
   strcat(inname, ".scr");
  }
 }
 else
 {
  strcpy(outname, inname);
  strcat(outname, ".scr");
 }
}

