#include<windows.h>
#include<tchar.h>


#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include <iostream>

#include <IL/il.h>
#include "MyImage.h"
#include "ImProcessor.h"
#include <map>
#include <string>

using namespace std;


/* GLUT callback Handlers */


map<string, MyImage*> imCollection;



void renderBitmapString(
		float x,
		float y,
		float z,
		void *font,
		char *string) {

  char *c;
  glRasterPos3f(x, y,z);
  for (c=string; *c != '\0'; c++) {
    glutBitmapCharacter(font, *c);
  }
}

static void resize(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, 0, height, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

static void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3d(1.0,0.0,0.0);
	int w = imCollection.at("original")->getWidth();
	int h = imCollection.at("original")->getHeight();

	glRasterPos2i(0,0);
	glDrawPixels(imCollection.at("original")->getWidth(),imCollection.at("original")->getHeight(),
				 GL_RGBA,GL_UNSIGNED_BYTE,imCollection.at("original")->data);

	glColor3f(0.0,1.0,0.0);
	renderBitmapString(0.0f,5.0f,0.0f,GLUT_BITMAP_9_BY_15, "Original");

	glRasterPos2i(w,0);
	glDrawPixels(imCollection.at("blurred")->getWidth(),imCollection.at("blurred")->getHeight(),
			 GL_RGBA,GL_UNSIGNED_BYTE,imCollection.at("blurred")->data);

	glColor3f(0.0,1.0,0.0);
	renderBitmapString(w,5.0f,0.0f,GLUT_BITMAP_9_BY_15, "Blurred");

	glRasterPos2i(2*w,0);
	glDrawPixels(imCollection.at("gaussianBlurred")->getWidth(),imCollection.at("gaussianBlurred")->getHeight(),
			 GL_RGBA,GL_UNSIGNED_BYTE,imCollection.at("gaussianBlurred")->data);

	glColor3f(0.0,1.0,0.0);
	renderBitmapString(2*w,5.0f,0.0f,GLUT_BITMAP_9_BY_15, "Gaussian Blurred");

	glRasterPos2i(0,h);
	glDrawPixels(imCollection.at("grayScale")->getWidth(),imCollection.at("grayScale")->getHeight(),
			 GL_RGBA,GL_UNSIGNED_BYTE,imCollection.at("grayScale")->data);

	glColor3f(0.0,1.0,0.0);
	renderBitmapString(0.0,h+5.0f,0.0f,GLUT_BITMAP_9_BY_15, "Gray Scale");

	glRasterPos2i(w,h);
	glDrawPixels(imCollection.at("laplacian")->getWidth(),imCollection.at("laplacian")->getHeight(),
			 GL_RGBA,GL_UNSIGNED_BYTE,imCollection.at("laplacian")->data);

	glColor3f(0.0,1.0,0.0);
	renderBitmapString(w,h+5.0f,0.0f,GLUT_BITMAP_9_BY_15, "Laplacian");

	glRasterPos2i(2*w,h);
	glDrawPixels(imCollection.at("edges")->getWidth(),imCollection.at("edges")->getHeight(),
			 GL_RGBA,GL_UNSIGNED_BYTE,imCollection.at("edges")->data);

	glColor3f(0.0,1.0,0.0);
	renderBitmapString(2*w,h+5.0f,0.0f,GLUT_BITMAP_9_BY_15, "Edges");
	
    glutSwapBuffers();
}


static void key(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;


    }

    glutPostRedisplay();
}

static void idle(void)
{
    glutPostRedisplay();
}

static int init(void){
	/* First we initialize the library. */
	/*Do not forget that... */
	ILubyte * data = NULL;
	ILuint handle, w, h;
	ilInit();
	/* We want all images to be loaded in a consistent manner */
	ilEnable(IL_ORIGIN_SET);
	/* In the next section, we load one image */
	ilGenImages(1, & handle);
	ilBindImage(handle);
	const char * fileName = ".\\len_std.jpg";
	ILboolean loaded = ilLoadImage((const wchar_t*)fileName);
	if (loaded == IL_FALSE){
		printf("Image not found\n");
		exit(-1); /* error encountered during loading */
	}
	/* Let’s spy on it a little bit */
	w = ilGetInteger(IL_IMAGE_WIDTH); // getting image width
	h = ilGetInteger(IL_IMAGE_HEIGHT); // and height
	printf("Our image resolution: %dx%d\n", w, h);
	/* how much memory will we need? */

	MyImage * myImage = new MyImage(w,h,MyImage::RGBA);
	ilCopyPixels(0, 0, 0, w, h, 1, IL_RGBA, IL_UNSIGNED_BYTE, myImage->data);
	imCollection.insert(pair<string,MyImage*>("original",myImage));
	imCollection.insert(pair<string,MyImage*>("grayScale",new MyImage(*myImage)));
	imCollection.insert(pair<string,MyImage*>("blurred",new MyImage(*myImage)));
	imCollection.insert(pair<string,MyImage*>("gaussianBlurred",new MyImage(*myImage)));


	ilCopyPixels(0, 0, 0, w, h, 1, IL_RGBA, IL_UNSIGNED_BYTE, imCollection.at("original")->data);

	ImProcessor::toGrayScale(*imCollection.at("grayScale"));
	ImProcessor::blur(*(imCollection.at("blurred")));
	ImProcessor::gaussianBlur5Sigma1_0(*(imCollection.at("gaussianBlurred")));

	imCollection.insert(pair<string,MyImage*>("laplacian",new MyImage(*imCollection.at("grayScale"))));
	imCollection.insert(pair<string,MyImage*>("edges",new MyImage(*imCollection.at("grayScale"))));

	ImProcessor::laplacian(*(imCollection.at("laplacian")),0);
	ImProcessor::edgeDetector(*(imCollection.at("edges")),0);

	return 0;


}

void finish(void){
	//delete(myImage);
}

int main(int argc, char *argv[])
{
	init();
    glutInit(&argc, argv);
	glutInitWindowSize(3*imCollection.at("original")->getWidth(),2*imCollection.at("original")->getHeight());
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("GLUT Image");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
    glutMainLoop();
	finish();

    return EXIT_SUCCESS;
}
