#include <math.h>
#include <float.h>
#include "reader.hh"

static const struct s_shader_item g_items[] =
{
  { "DUMMY",	shader_dummy	},
  { "ROTATE",	shader_rotate	},
  { "SCROLL",	shader_scroll	},
  { "TURB",	shader_turb	},
  { "WAVE",	shader_wave	},
  { "ROTZOOM",	shader_rotzoom	},
  { "COLOR",	shader_color	},
  { "",		0		}
};

static const struct s_move_item g_mitems[] =
{
  { "DUMMY",            move_dummy	},
  { "CIRCLE",           move_circle	},
  { "DIAGONAL",         move_diagonal	},
  { "HORIZONTAL",	move_horizontal	},
  { "VERTICAL",         move_vertical	},
  { "",                 0		}
};

Reader::Reader (std::string file)
{
  file_ = file;
  fp_.open (file_.c_str());

  if (!fp_.is_open ())
    throw "Could not open file " + file;
}

Reader::~Reader ()
{
  fp_.close ();
}

void
Reader::print (struct s_map& map)
{
  std::cout << "WORLD: " << std::endl;
  std::cout << "\tNUMFACES " << map.world.numFaces << std::endl;
  std::cout << "\tFACES ";
  for (std::vector<int>::iterator i = map.world.faces.begin ();
       i != map.world.faces.end (); ++i)
  {
    std::cout << (*i) << " ";
  }
  std::cout << std::endl;
  std::cout << "\tLIMITS ";
  for (std::vector<float>::iterator i = map.world.limits.begin ();
       i != map.world.limits.end (); ++i)
  {
    std::cout << (*i) << " ";
  }
  std::cout << std::endl;
  std::cout << "END" << std::endl;
  for (std::vector<struct s_block_group>::iterator
         i = map.blockGroups.begin (); i != map.blockGroups.end (); ++i)
  {
    std::cout << "BLOCK GROUP: " << std::endl;
    std::cout << "\tFACES ";
    for (std::vector<int>::iterator j = (*i).faces.begin ();
	 j != (*i).faces.end (); ++j)
    {
      std::cout << (*j) << " ";
    }
    std::cout << std::endl;
    std::cout << "\tBLOCKS " << std::endl;
    for (std::vector<struct s_block>::iterator j = (*i).blocks.begin ();
	 j != (*i).blocks.end (); ++j)
    {
      std::cout << "\t\tBLOCK " << (*j).origin.x << " " << (*j).origin.y
                << " " << (*j).origin.z << std::endl;
    }
    std::cout << "\tEND" << std::endl;
    std::cout << "\tSIZES MIN " << (*i).x1 << " " << (*i).y1 << " "
              << (*i).z1 << std::endl;
    std::cout << "\tSIZES MAX " << (*i).x2 << " " << (*i).y2 << " "
              << (*i).z2 << std::endl;
  }
  for (std::vector<struct s_face>::iterator i = map.faces.begin ();
       i != map.faces.end (); ++i)
  {
    std::cout << "FACE" << std::endl;
    std::cout << "\tID " << (*i).id << std::endl;

    for (std::vector<struct s_point>::iterator j = (*i).vertices.begin ();
	 j != (*i).vertices.end (); ++j)
      std::cout << "\tVERTICE " << (*j).x << " " << (*j).y << " " << (*j).z
		<< std::endl;
    for (std::vector<struct s_point>::iterator j = (*i).curVertices.begin ();
	 j != (*i).curVertices.end (); ++j)
      std::cout << "\tCURVERTICE " << (*j).x << " " << (*j).y << " " << (*j).z
		<< std::endl;
    for (std::vector<struct s_texcoord>::iterator j = (*i).texcoords.begin ();
	 j != (*i).texcoords.end (); ++j)
      std::cout << "\tTEXCOORD " << (*j).u << " " << (*j).v << std::endl;
    for (std::vector<struct s_texcoord>::iterator j =
	   (*i).curTexcoords.begin (); j != (*i).curTexcoords.end (); ++j)
      std::cout << "\tCURTEXCOORD " << (*j).u << " " << (*j).v << std::endl;

    std::cout << "END" << std::endl;
  }
}

void
Reader::readBlocks (struct s_map& map)
{
  struct s_block        block;
  std::string			face;
  struct s_block_group	group;
  std::string		word;

  do
  {
    fp_ >> word;
    if (word == "NUMFACES")
      fp_ >> group.numFaces;
    else if (word == "FACES")
      for (int i = 0; i < group.numFaces; ++i)
      {
	fp_ >> face;
	group.faceIds.push_back (face);
      }
    else if (word == "ORIGIN")
    {
      fp_ >> block.origin.x;
      fp_ >> block.origin.y;
      fp_ >> block.origin.z;
      block.curOrigin.x = block.origin.x;
      block.curOrigin.y = block.origin.y;
      block.curOrigin.z = block.origin.z;
      block.alive = true;
      block.hits = 0;
      group.blocks.push_back (block);
    }
    else if (word == "LIVES")
      fp_ >> group.lives;
    else if (word == "MOVE")
    {
      struct s_move	move;
      float		arg;
      int		args;
      int		i;
      std::string	name;

      fp_ >> name;
      fp_ >> args;
      for (i = 0; i < args; ++i)
      {
	fp_ >> arg;
	move.args.push_back (arg);
      }
      move.move = move_dummy;
      for (i = 0; g_mitems[i].func && g_mitems[i].name != name; ++i)
	;
      move.move = g_mitems[i].func;
      move.reverse = false;
      move.startTime = gl_vertex.time;
      group.moves.push_back (move);
    }
  }
  while (word != "END");
  group.x1 = group.y1 = group.z1 = FLT_MAX;
  group.x2 = group.y2 = group.z2 = FLT_MIN;
  map.blockGroups.push_back (group);
}

void
Reader::readFace (struct s_map& map)
{
  struct s_face		face;
  struct s_texcoord	texcoord;
  std::string	texture;
  struct s_point	vertex;
  std::string		word;

  face.color[0] = 1.0f;
  face.color[1] = 1.0f;
  face.color[2] = 1.0f;
  face.color[3] = 1.0f;

  do
  {
    fp_ >> word;
    if (word == "ID")
      fp_ >> face.id;
    else if (word == "VERTEX")
    {
      fp_ >> vertex.x;
      fp_ >> vertex.y;
      fp_ >> vertex.z;
      face.vertices.push_back (vertex);
      face.curVertices.push_back (vertex);
    }
    else if (word == "TEXCOORD")
    {
      fp_ >> texcoord.u;
      fp_ >> texcoord.v;
      face.texcoords.push_back (texcoord);
      face.curTexcoords.push_back (texcoord);
    }
    else if (word == "TEXTURE")
    {
      fp_ >> texture;
      face.textures.push_back (texture);
    }
    else if (word == "SHADER")
    {
      struct s_shader	shader;
      float		arg;
      int		args;
      int		i;
      std::string	name;

      fp_ >> name;
      fp_ >> args;
      for (i = 0; i < args; ++i)
      {
	fp_ >> arg;
	shader.args.push_back (arg);
      }
      shader.shader = shader_dummy;
      for (i = 0; g_items[i].func && g_items[i].name != name; ++i)
	;
      shader.shader = g_items[i].func;
      face.shaders.push_back (shader);
    }
  }
  while (word != "END");
  map.faces.push_back (face);
  faces_[face.id] = map.faces.size () - 1;
}

void
Reader::readWorld (struct s_map& map)
{
  float         arg;
  std::string	face;
  std::string	word;

  do
  {
    fp_ >> word;
    if (word == "NUMFACES")
      fp_ >> map.world.numFaces;
    else if (word == "FACES")
      for (int i = 0; i < map.world.numFaces; ++i)
      {
	fp_ >> face;
	map.world.faceIds.push_back (face);
      }
    else if (word == "LIMITS")
    {
      fp_ >> arg;
      map.world.limits.push_back (arg);
      fp_ >> arg;
      map.world.limits.push_back (arg);
      fp_ >> arg;
      map.world.limits.push_back (arg);
      fp_ >> arg;
      map.world.limits.push_back (arg);
    }
  }
  while (word != "END");
}

void
Reader::read (struct s_map& map)
{
  std::string	word;

  while (fp_ >> word)
    if (word == "FACE")
      readFace (map);
    else if (word == "BLOCKS")
      readBlocks (map);
    else if (word == "WORLD")
      readWorld (map);
  for (int j = 0; j < map.world.numFaces; ++j)
  	map.world.faces.push_back (faces_[map.world.faceIds[j]]);
  for (std::vector<s_block_group>::iterator i = map.blockGroups.begin ();
       i != map.blockGroups.end (); ++i)
  {
    for (int j = 0; j < i->numFaces; ++j)
      i->faces.push_back (faces_[i->faceIds[j]]);

    for (int j = 0; j < i->numFaces; ++j)
      for (int k = map.faces[i->faces[j]].vertices.size (); k--; )
      {
        if (i->x1 > map.faces[i->faces[j]].vertices[k].x)
          i->x1 = map.faces[i->faces[j]].vertices[k].x;
        if (i->y1 > map.faces[i->faces[j]].vertices[k].y)
          i->y1 = map.faces[i->faces[j]].vertices[k].y;
        if (i->z1 > map.faces[i->faces[j]].vertices[k].z)
          i->z1 = map.faces[i->faces[j]].vertices[k].z;
        if (i->x2 < map.faces[i->faces[j]].vertices[k].x)
          i->x2 = map.faces[i->faces[j]].vertices[k].x;
        if (i->y2 < map.faces[i->faces[j]].vertices[k].y)
          i->y2 = map.faces[i->faces[j]].vertices[k].y;
        if (i->z2 < map.faces[i->faces[j]].vertices[k].z)
          i->z2 = map.faces[i->faces[j]].vertices[k].z;
      }
  }
}
