#include <GL/glut.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <values.h>

#include "defs.h"
#include "array.h"
#include "main.h"
#include "texture.h"
#include "mesh.h"
#include "warp.h"
#include "itemBuffer.h"

float depth[WindowSize*WindowSize];

void outputImage (char *name, int *inp, int ex)
{
    FILE *image = fopen (name, "w");    
    int *p = inp;
    
    fputs ("P6\n", image);
    fprintf (image,"%d %d\n",WindowSize,WindowSize);
    fputs ("255\n",image);
    
    for (int k=0; k<WindowSize*WindowSize; k++)
    {
	for (int l = 0; l < 3; l++)
	    putc( (unsigned char) floor (255*(*p++/(float)MAXINT)), image );
      
    }
    fclose (image); 
    
    if (ex)
	exit(0);

    
}

void outputItem (int *inp, int base, int ex)
{
    FILE *image = fopen ("item.ppm", "w");
    int *p = inp;

    fputs ("P6\n", image);
    fprintf (image,"%d %d\n",WindowSize,WindowSize);
    fprintf (image,"%d\n",base-1);
    
    for (int k=0; k<WindowSize*WindowSize; k++)
    {
	int r = (*p/(base*base))%base;
	int g = (*p/base)%base;
	int b = (*p%base);
	putc ((unsigned char) r,image);
	putc ((unsigned char) g,image);
	putc ((unsigned char) b,image);
	p++;
    }

    fclose(image);

    if (ex)
	exit (0);
}

void outputItem2 (int *inp, int numfaces, int ex)
{
    FILE *image = fopen ("item.ppm", "w");
    int *p = inp;

    fputs ("P2\n", image);
    fprintf (image,"%d %d\n",WindowSize,WindowSize);
    fprintf (image,"%d\n",numfaces);

    for (int k=0; k<WindowSize; k++)
    {
	for (int j =0; j < WindowSize; j++)
	    fprintf (image,"%d ", *p++);
	fprintf (image,"\n");
    }

    fclose(image);

    if (ex)
	exit (0);
}




int round (int n1, float n2)
{
    float r = (float) n1 / n2;
    int floor = (int) r; 

    if (r - (float) floor > 0.5)
	return (floor+1);
    else
	return floor;
}


int RGBToIdent (int *p, int base)
{

    float step = MAXINT/ (float)(base-1);
    
    int bident = round (p[2],step);
    int gident = round (p[1],step);
    int rident = round (p[0],step);
    //int alpha = round (p[3], step); 

    /*
    if (alpha != base - 1)
    {
	printf ("alpha: %d\n", alpha);
	exit(0);
    }
    */
    if (rident == base-1 && gident == base-1 && bident == base-1) 
	return -1;

    return (base*base*rident + base*gident + bident);
}


void drawFlatTerrain (int x0, int y0, int x1, int y1, int base)
{

    int ident = 0;
    
    for (int i = x0; i < x1; i++)
    {
	for (int j = y0; j < y1; j++)
	{
	    
	    int bcolor = ident % base;
	    int gcolor = (ident / base) % base;
	    int rcolor = (ident / (base*base)) % base;
	    //int alpha = (ident / (base*base*base)) % base;

	    /*
	    if (ident == 30)
	    {
		printf ("r: %d, g: %d, b: %d\n", rcolor, gcolor, bcolor);
		printf ("MAXINT: %d\n", MAXINT);
	    }
	    */
		
	    float div = (float) base-1;
	    
	    glColor3f (1.0*rcolor/div, 1.0*gcolor/div, 1.0*bcolor/div);
	    //glColor3f (0.5,0.5,0.5);
	    glBegin (GL_POLYGON);  
	    glVertex3f ((float) i, (float) j, smooth_heights->data[i][j]);
	    glVertex3f ((float) i, (float) j+1, smooth_heights->data[i][j+1]);
	    glVertex3f ((float) i+1, (float) j, smooth_heights->data[i+1][j]);
	    glEnd();

	    ident++;
	    
	    bcolor = ident % base;
	    gcolor = (ident / base) % base;
	    rcolor = (ident / (base*base)) % base;
	    //alpha = (ident / (base*base*base)) % base;
	    
	    glColor3f (1.0*rcolor/div, 1.0*gcolor/div, 1.0*bcolor/div);
	    //glColor3f (0.5,0.5,0.5);
	    glBegin (GL_POLYGON);  
	    glVertex3f ((float) i+1, (float) j, smooth_heights->data[i+1][j]);
	    glVertex3f ((float) i+1, (float) j+1, smooth_heights->data[i+1][j+1]);
	    glVertex3f ((float) i, (float) j+1, smooth_heights->data[i][j+1]);
	    glEnd();

	    ident++;
	}
  
    }
    printf ("IDENT: %d, %d, %d, %d, %d, \n", ident, x0, x1, y0, y1);
    glutSwapBuffers();
    //int blah;
    //scanf ("%d",&blah);
}


void drawDepthSets (int index, int base)
{
    int i = 0;
    float worldcd0[3], worldcd1[3], worldcd2[3];
 
    while (sFaces[index][i] != -1)
    {
	int vindex0 = Dfaces[index][sFaces[index][i]].vertices[0];
	int vindex1 = Dfaces[index][sFaces[index][i]].vertices[1];
	int vindex2 = Dfaces[index][sFaces[index][i]].vertices[2];
	
	Vertex v0 = verts[index][vindex0];
	Vertex v1 = verts[index][vindex1];
	Vertex v2 = verts[index][vindex2];

	worldcd0[0] = v0.world[0];
	worldcd0[1] = v0.world[1];
	worldcd0[2] = v0.world[2];
	
	worldcd1[0] = v1.world[0];
	worldcd1[1] = v1.world[1];
	worldcd1[2] = v1.world[2];
	
	worldcd2[0] = v2.world[0];
	worldcd2[1] = v2.world[1];
	worldcd2[2] = v2.world[2];

	int c = Dfaces[index][sFaces[index][i]].nearestPeakDepth;
	
	int bcolor = c % base;
	int gcolor = (c / base) % base;
	int rcolor = (c / base*base) % base;

	float div = (float)(base-1);
	
	glColor3f (rcolor/div, gcolor/div, bcolor/div);
	//glColor3f (c/100.0, c/100.0, c/100.0);
	
	glBegin (GL_POLYGON);
	glVertex3fv (worldcd0);
	glVertex3fv (worldcd1);
	glVertex3fv (worldcd2);
	glEnd();

	i++;

    }
    glutSwapBuffers();
}


void drawMesh (int index, int base)
{
    int i = 0;
    float worldcd0[3], worldcd1[3], worldcd2[3];
 
    while (sFaces[index][i] != -1)
    {
	int vindex0 = Dfaces[index][sFaces[index][i]].vertices[0];
	int vindex1 = Dfaces[index][sFaces[index][i]].vertices[1];
	int vindex2 = Dfaces[index][sFaces[index][i]].vertices[2];
	
	Vertex v0 = verts[index][vindex0];
	Vertex v1 = verts[index][vindex1];
	Vertex v2 = verts[index][vindex2];

	worldcd0[0] = v0.world[0];
	worldcd0[1] = v0.world[1];
	worldcd0[2] = v0.world[2];
	
	worldcd1[0] = v1.world[0];
	worldcd1[1] = v1.world[1];
	worldcd1[2] = v1.world[2];
	
	worldcd2[0] = v2.world[0];
	worldcd2[1] = v2.world[1];
	worldcd2[2] = v2.world[2];
	
	int c = sFaces[index][i];

	int bcolor = c % base;
	int gcolor = (c / base) % base;
	int rcolor = (c / base*base) % base;

	float div = (float)(base-1);
	
	glColor3f (rcolor/div, gcolor/div, bcolor/div);
	glBegin (GL_POLYGON);
	glVertex3fv (worldcd0);
	glVertex3fv (worldcd1);
	glVertex3fv (worldcd2);
	glEnd();
	
	i++;
	
    }
    glutSwapBuffers();
    
}

	
void itemize (int index, int mode, int *item, int x0, int y0, int x1, int y1)
{
    int base = 17;
    int *buffer;

    glEnable (GL_DEPTH_TEST);
    glClearColor (1.0, 1.0, 1.0, 1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glFlush();
    
    glPolygonMode( GL_FRONT, GL_FILL );
    glShadeModel( GL_FLAT );
    glDisable ( GL_DITHER );

    // draw the triangles into the buffer, with each being flat-shaded
    // with a unique colour determined by the order of the triangles

    if (mode == 0)
	drawFlatTerrain (x0, y0, x1, y1, base);
    else if (mode == 1)
	drawDepthSets (index, base);
    else if (mode == 2)
	drawMesh (index, base);
    
    buffer = (int *) malloc ( WindowSize * WindowSize * 3 * sizeof(int) );
    glReadPixels( 0, 0, WindowSize, WindowSize, GL_RGB, GL_INT, buffer );

    int *p = buffer;
    for (int l = 0; l<WindowSize*WindowSize; l++)
    {
	item[l] = RGBToIdent (p, base);
	//if (itemized[l] == -1) itemized[l] = 0;
	p += 3;
    }

    int check;
    int found;
    int notfound = 0;
    scanf ("%d",&check);
    //if (check)
    //{
    /*
	for (int m = 0; m < 198702; m++)
	{
	    found = 0;
	    for (int n = 0; n < WindowSize*WindowSize; n++)
	    {
		if (item[n] == m)
		{
		    found = 1;
		    break;
		}
	    }
	    if (found == 0) printf ("not found: %d\n", m);
	}
    */
	//printf ("not found: %d\n", notfound);
    //exit (0);
    //if (mode == 0)
    //outputItem (item, base, 1);
	//outputImage ("flat.ppm",buffer, 1);
	//}

    free (buffer);
    
    glClearColor( R/255.0, G/255.0, B/255.0, 0.0 );

    glShadeModel (GL_SMOOTH);
    glEnable ( GL_DITHER );

}

















