// Author: Juan Carlos De Abreu (jcabreur@gmail.com)

#include "ModelObj.h"
#include "../Material/MaterialManagement.h"
#include "../base/LogManagement.h"

BEGIN_TEG_NAMESPACE();

ModelObj::ModelObj() {}

ModelObj::ModelObj(const std::tstring& path_) {
	path = path_;
	load(path.c_str());
}

ModelObj::~ModelObj() {
	groupList.clear();
//	materialList.clear();
}

// Method to load a Model of the type Obj
void ModelObj::load(const _TCHAR* lpszPathName) {
  // Try to open the file
  FILE *f = fopen(lpszPathName, "r");
	
  // Check if the file was open
  if (f == NULL) {
    // Report the error in the Log
    PRINT_LOG(TYPE_ERROR, "The file \"%s\" not was found!", lpszPathName);
    return;
  }
	
  const int MAX_LONG  = 200;

  _TCHAR str[MAX_LONG];

  Group g;		// To save the data temporaly of the groups
	
  // To mantain the refences of the model local to each group
  Face refIndex;
  refIndex.normal = 1;
  refIndex.texture = 1;
  refIndex.vertex = 1;


  // Load the data in the file
  while (fgets(str, MAX_LONG, f) != NULL) {
    // Obtain the type of line
    _TCHAR lineType[MAX_LONG];
    sscanf(str, "%s", lineType);
		
    // Check if is a comment line
    if (strcmp(lineType, "#") == 0) {
      // Do anything ...
      // Process the next line
      continue;
    }
		
    // Check if is a begin group line
    if (strcmp(lineType, "g") == 0) {
      // Check if a have a previus group
      if (g.vertexList.size() > 0) {
        // Check if the material was defined to the group
        //if(strcmp(g.mat.name.c_str(), "") == 0) {
        if (g.mat.size() == 0) {
          // Add the last material defined
          g.mat.push_back(MATERIAL(_T("SceneNavigator_Default__")));
          g.matIndex.push_back(0);
        }

        // Add the group to the groupList
        groupList.push_back(g);
        // Update the index reference ...
        refIndex.normal += g.normalList.size();
        refIndex.vertex += g.vertexList.size();
        refIndex.texture += g.textureList.size();
      }

	  g = Group();

      // Process the next line
      continue;
    }

    // Check if is a pathFile of materials
    if (strcmp(lineType, "mtllib") == 0) {
      // Obtain the path of the file that have the mtllib
      sscanf(str, "%*s %s", str);

      // Load the material library
      LOAD_MATERIALS(GetAPathFromOne(lpszPathName, str));
      // Process the next line
      continue;
    }
		
    // Check if is an use of a material
    if (strcmp(lineType, "usemtl") == 0) {
      // Obtain the material name
      sscanf(str, "%*s %s", str);

      g.mat.push_back(MATERIAL(str));
      g.matIndex.push_back(g.faceList.size());

      // Process the next line
      continue;
    }

    // Check if is a definition of a vertex
    if (strcmp(lineType, "v") == 0) {
      // To save the information of the vertex
      Vec3f v;
      // Obtain the definition of a vertex
      sscanf(str, "%*s %f %f %f", &v.x, &v.y, &v.z);
      // Add the vertex to the vertexList
      g.vertexList.push_back(v);
      // Process the next line
      continue;
    }

    // Check if is a definition of a normal of a vextex
    if (strcmp(lineType, "vn") == 0) {
      // To save the information of the normal
      Vec3f v;
      // Obtain the definition of a vertex
      sscanf(str, "%*s %f %f %f", &v.x, &v.y, &v.z);
      // Add the normal to the normalList
      g.normalList.push_back(v);
      // Process the next line
      continue;
    }

    // Check if is a definition of a texture coord of a vextex
    if (strcmp(lineType, "vt") == 0) {
      // To save the information of a texture coord
      Vec2f v;
      // Obtain the definition of a texture coord
      sscanf(str, "%*s %f %f", &v.x, &v.y);
      // Add the texture coord to the textureList
      g.textureList.push_back(v);
      // Process the next line
      continue;
    }

    // Check if is a definition of a face
    if (strcmp(lineType, "f") == 0) {
      // To save the information of the face
      Face f;
			        
      // Determin how many vertex have the face
      int nSlash = 0;
      for (int i = 0; i < (int)strlen(str); ++i)
        if (str[i] == '/') nSlash++;

      // If the face has more than 3 vertex ..
      if (nSlash > 6) {
        Vec3i tmp;
        // Check if have a coord of texture
        if (strstr(str, "//") == NULL) {
          // Obtain the index of the face
          sscanf(str, "%*s %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &f.vertex.x, &f.texture.x, &f.normal.x,
                &f.vertex.y, &f.texture.y, &f.normal.y, &f.vertex.z, &f.texture.z, &f.normal.z, &tmp.x, &tmp.y, &tmp.z);
        } else {
          // Obtain the index of the face
          sscanf(str, "%*s %d//%d %d//%d %d//%d %d//%d", &f.vertex.x, &f.normal.x,
                 &f.vertex.y, &f.normal.y, &f.vertex.z, &f.normal.z, &tmp.x, &tmp.z);	
        }

        // Change the range of the index to [0..n-1]
        f.vertex -= refIndex.vertex;
        f.normal -= refIndex.normal;
        f.texture -= refIndex.texture;
        tmp.x -= refIndex.vertex.x;
        tmp.y -= refIndex.texture.x;
        tmp.z -= refIndex.normal.x;
				
        // Add the face to the faceList
        g.faceList.push_back(f);

        f.vertex.y = f.vertex.z; f.vertex.z = tmp.x;
        f.texture.y = f.texture.z; f.texture.z = tmp.y;
        f.normal.y = f.normal.z; f.normal.z = tmp.z;
        g.faceList.push_back(f);
      } else {
        // Check if have a coord of texture
        if (strstr(str, "//") == NULL) {
          // Obtain the index of the face
          sscanf(str, "%*s %d/%d/%d %d/%d/%d %d/%d/%d", &f.vertex.x, &f.texture.x, &f.normal.x,
                 &f.vertex.y, &f.texture.y, &f.normal.y, &f.vertex.z, &f.texture.z, &f.normal.z);
        } else {
          // Obtain the index of the face
          sscanf(str, "%*s %d//%d %d//%d %d//%d", &f.vertex.x, &f.normal.x,
                 &f.vertex.y, &f.normal.y, &f.vertex.z, &f.normal.z);	
        }

        // Change the range of the index to [0..n-1]
        f.vertex -= refIndex.vertex;
        f.normal -= refIndex.normal;
        f.texture -= refIndex.texture;			
				
        // Add the face to the faceList
        g.faceList.push_back(f);
      }
			
      // Process the next line
      continue;
    }

    // If the line is the unknown type report a warning
    PRINT_LOG(TYPE_WARNING, "The file %s has a unknown line \"%s\"", lpszPathName, str);
  }

  // Check if the material was defined to the group
  if (g.mat.size() == 0) {
    // Add the last material defined
    g.mat.push_back(MATERIAL(_T("SceneNavigator_Default__")));
    g.matIndex.push_back(0);
  }

  // Add the last group to groupList
  groupList.push_back(g);

  // Close th file
  fclose(f);

  // Normalize the model
  process();
}

END_TEG_NAMESPACE();
