/*
 *  PlotTool.cpp
 *  PlotTool
 *
 *  Created by Assistant on 9/11/06.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


#include "SDL.h"
#include "SDL_OpenGL.h"

#include "LinTool.h"
#include "PlotTool.h"

#include <iostream>
#include <stdlib.h>
#include <ctime> 

using namespace std;



GLboolean should_rotate = GL_TRUE; 
GLboolean adapt_aspect_ratio = GL_TRUE; 

	/* Color depth in bits of our window. */ 
	int bpp = 0; 
	/* Flags we will pass into SDL_SetVideoMode. */ 
	int flags = 0; 



float Width, Height;

float vert_angle = -10.0;
float hor_angle = -75.0;
	
	
	




void quit_tutorial( int code ) 
{ 
	SDL_Quit( ); 
	/* Exit program. */ 
	exit( code ); 
}




void handle_key_down( SDL_keysym* keysym ) 
{ 
	switch( keysym->sym )
	{ 
	case SDLK_ESCAPE: 
		quit_tutorial( 0 ); 
		break; 

	default: 
		break; 
	} 
} 


void resize_window(int height, int width)
{ 
	Width = width;
	Height = height;
	//if( SDL_SetVideoMode(width, height,32,SDL_OPENGL|SDL_HWSURFACE|SDL_RESIZABLE ) ==0)
	if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 )
		{ 
			fprintf( stderr, "Video mode resize failed: %s\n", 
			SDL_GetError( ) ); 
			quit_tutorial( 1 ); 
		} 
	setup_opengl(width, height);
}



void process_events( void ) 
{ 
	/* Our SDL event placeholder. */ 
	SDL_Event event; 

	/* Grab all the events off the queue. */ 
	while( SDL_PollEvent( &event ) )
	{ 
		switch( event.type )
		{ 
		case SDL_KEYDOWN: 
			/* Handle key presses. */ 
			handle_key_down( &event.key.keysym ); 
			break; 
		case SDL_QUIT: 
			/* Handle quit requests (like Ctrl-c). */ 
			quit_tutorial( 0 ); 
			break; 
		case SDL_VIDEORESIZE:
			resize_window(event.resize.h, event.resize.w);
			break;
		} 
	} 
} 


void do_on_keystate()
{
	Uint8 *keystate = SDL_GetKeyState(NULL);
	
	if (keystate[SDLK_UP])	hor_angle -= 0.5;
	if (keystate[SDLK_DOWN])	hor_angle += 0.5;

	if (keystate[SDLK_RIGHT])	vert_angle -= 0.5;
	if (keystate[SDLK_LEFT])	vert_angle += 0.5;

}



void plot2D(LT_matrix *y) 
{
	double yMax, yMin, xMin, xMax;
	int points, p, q;
	
	yMax = y->max();
	yMin = y->min();
	xMax = double(y->Nrows);
	xMin = 0.0;
	
	points = y->Nrows;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And The Depth Buffer
	
	glLoadIdentity();						// Reset The View
	if (adapt_aspect_ratio) glScalef(float(Width)/float(Height),1.0,1.0);
	glTranslatef(-0.5f,-0.5f,-1.5f);
	
	for (q=0; q<y->Ncols; q++)
	{
		glColor3f(0.0f+ float(q)/float(y->Ncols-1),0.0f,1.0f- float(q)/float(y->Ncols-1));
		glBegin(GL_LINE_STRIP);
			for (p=0; p<points; p++) glVertex3f(float(p)/float(points-1), (y->A[p][q] - yMin)/(yMax-yMin) , 0.0f);
		glEnd();
	}
	
	//Axes:
	glBegin(GL_LINES);
	glColor3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(1.0f,0.0f,0.0f);
	
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,1.0f,0.0f);
	glEnd();
	
	SDL_GL_SwapBuffers(); 
}


void plot2D(LT_matrix *x, LT_matrix *y)
{
	double yMax, yMin, xMin, xMax;
	int points, p, q;
	
	yMax = y->max();
	yMin = y->min();
	xMax = x->max();
	xMin = x->min();
	
	if (x->Nrows != y->Nrows || x->Ncols != 1)
	{
		cout<<"First argument must be vector (x values) with same number of rows as second argument (y values)";
	}
	
	points = y->Nrows;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And The Depth Buffer
	
	//glEnable(GL_LINE_SMOOTH);
	
	glLoadIdentity();						// Reset The View
	if (adapt_aspect_ratio) glScalef(float(Width)/float(Height),1.0,1.0);
	glTranslatef(-0.5f,-0.5f,-1.5f);
	
	for (q=0; q<y->Ncols; q++)
	{
		glColor3f(0.0f+ float(q)/float(y->Ncols-1),0.0f,1.0f- float(q)/float(y->Ncols-1));
		glBegin(GL_LINE_STRIP);
			for (p=0; p<points; p++) glVertex3f((x->A[p][0] - xMin)/(xMax-xMin), (y->A[p][q] - yMin)/(yMax-yMin) , 0.0f);
		glEnd();
	}
	
	//Axes:
	glBegin(GL_LINES);
	glColor3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(1.0f,0.0f,0.0f);
	
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,1.0f,0.0f);
	glEnd();
	
	SDL_GL_SwapBuffers(); 
}



void surf(LT_matrix *Z)
{
	double zMax, zMin, yMax, yMin, xMin, xMax, z1, z2;
	int p, q, iR, iC;
	
	zMax = Z->max();
	zMin = Z->min();
	yMax = Z->Ncols-1;
	yMin = 0.0;
	xMax = Z->Nrows-1;
	xMin = 0.0;
	

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And The Depth Buffer
	
	//glEnable(GL_LINE_SMOOTH);
	
	glLoadIdentity();						// Reset The View
	if (adapt_aspect_ratio) glScalef(float(Width)/float(Height),1.0,1.0);
	
	glTranslatef(0.0f,0.0f,-2.5f);
	
	glRotatef(hor_angle, 1.0 , 0.0, 0.0);
	glRotatef(vert_angle, 0.0 , 0.0, 1.0);
	
	glTranslatef(-0.5f,-0.5f,-0.5f);
	
	for (iR=0; iR<Z->Nrows-1 ; iR++)
	{
	glBegin(GL_TRIANGLE_STRIP);
		for (iC=0; iC<Z->Ncols ; iC++)
		{
			z1 = (Z->A[iR][iC] - zMin)/(zMax-zMin);
			z2 = (Z->A[iR+1][iC] - zMin)/(zMax-zMin);
			
			glColor3f(z1,0.0f,1.0-z1);
			glVertex3f(float(iR)/xMax, float(iC)/yMax, z1);
			
			glColor3f(z2,0.0f,1.0-z2);
			glVertex3f(float(iR+1)/xMax, float(iC)/yMax, z2);
		}
	glEnd();
	}
	
	
	//Axes:
	glBegin(GL_LINES);
	glColor3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(1.0f,0.0f,0.0f);
	
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,1.0f,0.0f);
	
	glVertex3f(0.0f,0.0f,0.0f);
	glVertex3f(0.0f,0.0f,1.0f);
	glEnd();
	
	SDL_GL_SwapBuffers(); 
}




void setup_SDL(int width, int height)
{
	Width = width;
	Height = height;
	/* Information about the current video settings. */ 
	const SDL_VideoInfo* info = NULL; 

	/* Color depth in bits of our window. */ 
	//int bpp = 0; 
	/* Flags we will pass into SDL_SetVideoMode. */ 
	//int flags = 0; 
	
	/* First, initialize SDL’s video subsystem. */ 
	if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
	{ 
		/* Failed, exit. */ 
		fprintf( stderr, "Video initialization failed: %s\n", 
		SDL_GetError( ) ); 
		quit_tutorial( 1 ); 
	} 
	
	/* Let’s get some video information. */ 
	info = SDL_GetVideoInfo( ); 
	if( !info )
	{ 
		/* This should probably never happen. */ 
		fprintf( stderr, "Video query failed: %s\n", 
		SDL_GetError( ) ); 
		quit_tutorial( 1 ); 
	} 

	bpp = info->vfmt->BitsPerPixel;
	
	 
	SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); 
	SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); 
	SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); 
	SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); 
	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); 

	
	flags =  SDL_RESIZABLE|SDL_OPENGL;// | SDL_FULLSCREEN;
	
	if( SDL_SetVideoMode( width, height, bpp, SDL_RESIZABLE|SDL_OPENGL ) == 0 )
	{ 
		/* 
		* This could happen for a variety of reasons, 
		* including DISPLAY not being set, the specified 
		* resolution not being available, etc. 
		*/ 
		fprintf( stderr, "Video mode set failed: %s\n", 
		SDL_GetError( ) ); 
		quit_tutorial( 1 ); 
	} 
}





void setup_opengl(int width, int height) {
	Width = width;
	Height = height;
	
        glViewport(0,0,width, height);
        
        //manager=TextureManager::Instance();
        //manager->initTileSet("default");
        
//        glEnable(GL_TEXTURE_2D); //enable texture mapping
        glClearColor(1.0f, 1.0f, 1.0f, 0.0f); //White Background
        glClearDepth(1.0); //enables clearing of deapth buffer
        glDepthFunc(GL_LEQUAL); //type of depth test
        glEnable(GL_DEPTH_TEST); //enables depth testing
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      // Enable Alpha Blending (disable alpha testing)
        glEnable(GL_BLEND);                                     // Enable Blending       (disable alpha testing)
        glShadeModel(GL_SMOOTH); //enables smooth color shading
		
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			// Really Nice Perspective Calculations
        
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity(); //Reset projection matrix
        
        gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 1.0f, 100.0f); //calculate aspect ratio of the window
        glMatrixMode(GL_MODELVIEW);
}