#include "ObjMesh.h"
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <math.h>
#include <gl/glfw.h>

bool TriangleIntersectTest(sVector *source, sVector *dest, sVector *vec1, sVector *vec2, sVector *vec3);

CObjMesh::CObjMesh()
{
     pos.x = 0;
     pos.y = 0;
     pos.z = 0;
     
     scale.x = 1.0;
     scale.y = 1.0;
     scale.z = 1.0;
     
     rotation.x = 0;
     rotation.y = 0;
     rotation.z = 0;
     
     smoothRender = false;
}
                  
CObjMesh::~CObjMesh()
{
}          

void CObjMesh::setPos(sVector pos)
{
     this->pos = pos;
}

void CObjMesh::setScale(sVector scale)
{
     this->scale = scale;
}

void CObjMesh::setRotation(sVector rotation)
{
     this->rotation = rotation;
}
       
sVector CObjMesh::getPos()
{
        return this->pos;
}

sVector CObjMesh::getScale()
{
        return this->scale;
}

sVector CObjMesh::getRotation()
{
        return this->rotation;
}     

bool CObjMesh::Collision(sVector source, sVector dest)
{
     int numFaces = faceList.GetNumItems();
     for(int i = 0; i < numFaces; i++)
     {
             
     }
     return true;
}

void CObjMesh::setSmoothRender(bool smooth)
{
     this->smoothRender = smooth;
}

void CObjMesh::LoadObjFile(char *filename)
{
     char buffer[1000];
     char tokenBuffers[8][100];
     char *tokens[8];
     int currentVertexId = -1;
     
     //put NULL characters in our strings
     for(int i = 0; i < 8; i++)
     {
             tokens[i] = tokenBuffers[i];
             tokens[i][0] = '1';
             tokens[i][1] = '\0';
     }
     
     FILE *handle = fopen(filename, "rt");
     
     //this loop tokenizes the info and parses it into our object! yay!
     while(true)
     {
          //get next line. if blank, end this loop
          if(fgets(buffer, 1000, handle) == NULL)
                  break;
                  
          char *newLine = strchr(buffer, '\n');
          *newLine = '\0';
          
          
          int i = 0;
          tokens[0] = strtok(buffer, " ");
          while(tokens[i] != NULL)
          {
                  i++;
                  tokens[i] = strtok(NULL, " ");
          }
                        
          if(strncmp(buffer, "vn", 3) == 0)
          {
                  currentVertexId += 1;
                  sVertex *vertex = (sVertex *)vertexList.GetItem(currentVertexId);
                  vertex->normal.x = atof(tokens[1]);
                  vertex->normal.y = atof(tokens[2]);
                  vertex->normal.z = atof(tokens[3]); 
          }  
          else if(strncmp(buffer, "v", 2) == 0)
          {
                  sVertex *vertex = new sVertex();
                  vertex->pos.x = atof(tokens[1]);
                  vertex->pos.y = atof(tokens[2]);
                  vertex->pos.z = atof(tokens[3]);
                  
                  vertexList.AppendItem(vertex);
          }
          else if(strncmp(buffer, "f", 2) == 0)
          {
                 char vertexBuffer[20];
                 char *vertexId = vertexBuffer;
                 sVertex *vertex[4];
                 
                 sFace *face = new sFace();
                 
                 for(int i = 0; i < 3; i ++)
                 {
                         vertexId = strtok(tokens[i + 1], "/");
                         face->vertex[i] = (sVertex *)vertexList.GetItem(atoi(vertexId) - 1);
                 }
                 
                 sVector vectorOne = face->vertex[0]->pos.Difference(&face->vertex[1]->pos);
                 sVector vectorTwo = face->vertex[0]->pos.Difference(&face->vertex[2]->pos);    
                 face->faceNormal = vectorOne.CrossProduct(&vectorTwo);
                 
                 faceList.AppendItem(face);
                 
                 //check for a 4th vertex
                 if(tokens[4] != NULL)
                 {
                         sFace *face = new sFace();                      
                         vertexId = strtok(tokens[1], "/");
                         face->vertex[0] = (sVertex *)vertexList.GetItem(atoi(vertexId) - 1); 
                         vertexId = strtok(tokens[3], "/");
                         face->vertex[1] = (sVertex *)vertexList.GetItem(atoi(vertexId) - 1);   
                         vertexId = strtok(tokens[4], "/");
                         face->vertex[2] = (sVertex *)vertexList.GetItem(atoi(vertexId) - 1);   
                         
                         sVector vectorOne = face->vertex[0]->pos.Difference(&face->vertex[1]->pos);
                         sVector vectorTwo = face->vertex[0]->pos.Difference(&face->vertex[2]->pos);
                         face->faceNormal = vectorOne.CrossProduct(&vectorTwo);
                         
                         faceList.AppendItem(face);
                 } 
          }
     }
     fclose(handle);
}

void CObjMesh::Render()
{
     int numFaces = faceList.GetNumItems();
     
     glPushMatrix();
     glTranslatef(pos.x, pos.y, pos.z);
     glScalef(scale.x, scale.y, scale.z);
     
     glRotatef(rotation.z, 0, 0, 1.0);
     glRotatef(rotation.x, 1.0, 0, 0);
     glRotatef(rotation.y, 0, 1.0, 0);
     
     if(smoothRender)
     {
         for(int i = 0; i < numFaces; i++)
         {
                 sFace *face = (sFace *)faceList.GetItem(i);
                 
                 glBegin(GL_TRIANGLES);
                 glTexCoord2f(1,1);
                 glNormal3f(face->vertex[0]->normal.x, face->vertex[0]->normal.y, face->vertex[0]->normal.z);
                 glVertex3f(face->vertex[0]->pos.x, face->vertex[0]->pos.y, face->vertex[0]->pos.z);
                 
                 glNormal3f(face->vertex[1]->normal.x, face->vertex[1]->normal.y, face->vertex[1]->normal.z);
                 glVertex3f(face->vertex[1]->pos.x, face->vertex[1]->pos.y, face->vertex[1]->pos.z);
                 
                 glNormal3f(face->vertex[2]->normal.x, face->vertex[2]->normal.y, face->vertex[2]->normal.z);
                 glVertex3f(face->vertex[2]->pos.x, face->vertex[2]->pos.y, face->vertex[2]->pos.z);
                 
                 glEnd();
         }     
     }
     else
     {
         for(int i = 0; i < numFaces; i++)
         {
                 sFace *face = (sFace *)faceList.GetItem(i);
                 
                 glBegin(GL_TRIANGLES);
                 glTexCoord2f(1,1);
                 glNormal3f(face->faceNormal.x, face->faceNormal.y, face->faceNormal.z);
                 
                 glVertex3f(face->vertex[0]->pos.x, face->vertex[0]->pos.y, face->vertex[0]->pos.z);
                 
                 glVertex3f(face->vertex[1]->pos.x, face->vertex[1]->pos.y, face->vertex[1]->pos.z);
                 
                 glVertex3f(face->vertex[2]->pos.x, face->vertex[2]->pos.y, face->vertex[2]->pos.z);
                 
                 glEnd();
         }   
     }
     
     
     
     glPopMatrix();
}

// No description
void CObjMesh::RenderShadowVolume()
{
	/* TODO (#1#): Implement CObjMesh::RenderShadowVolume() */
}
