//mostly all stolen from the Graphics Town project base code, (c) Michael Gleicher

#include <time.h>
#include <iostream>
#include <Fl/fl.h>
//#include <math.h>

#include "BetterCamera.h"

int betterCamCount = 0;

BetterCamera::BetterCamera() : direction(0), pitch(0), posX(0), posY(10), posZ(0), lastUItime(0)
{

}

// build the transformation
// C = T Ry Rx
void BetterCamera::getCamera(Matrix camera)
{
	Matrix tmp1,  tmp2,  tmp3;//, tmp4, tmp5;
	
	transMatrix(tmp1, -posX, -posY, -posZ);
	rotMatrix(tmp2,'Y',-direction);
	multMatrix(tmp1, tmp2, tmp3);
	
	rotMatrix(tmp1,'X',-pitch);
	multMatrix(tmp3,tmp1,camera);

}

int BetterCamera::handle(int e)
{
	static int stX=0, stY=0;
	static int lX=0, lY=0;

	switch(e) {
	case FL_PUSH:
		lX = stX = Fl::event_x();
		lY = stY = Fl::event_y();
		buttonDown = Fl::event_button();
		return 1;
	case FL_RELEASE:
		buttonDown = 0;
		return 1;
	case FL_FOCUS:
		return 1;
	case FL_KEYBOARD:
		switch(Fl::event_key()) 
		{
		case 'z':
			break;
		//print out current location of camera
		case 'p':
			printf("%f, %f, %f\n", posX, posY, posZ);
			break;
		};
		return 1;
	case FL_DRAG:          
		int mX = Fl::event_x();
		int mY = Fl::event_y();
		if (buttonDown) {
			switch(Fl::event_button()) {
				
			case 2:			
	        case 1:
			case 3:
				float dx = static_cast<float>(mX - lX);
				float dy = static_cast<float>(mY - lY);
				if (fabs(dx) > fabs(dy)) {
					direction -=  0.01f * dx;												
				} else {										
					pitch += 0.01f * dy;
				}
				//dir = direction;
				break;
			
			}
		}
		
		buttonDown = Fl::event_button();

		lX = mX; lY = mY;
		return 1;
	};
	return 0;
}

// to go forward, we need to now what the "forward" direction
// is - to find it out, look at the Z axis of the camera transform
void BetterCamera::forward(float a)
{
	Matrix cam;
	getCamera(cam);

	posX -= a*cam[0][2];
	posY -= a*cam[1][2];
	posZ -= a*cam[2][2];
}

// move the position in the LOCAL coordinates
// use the transform to know what that is
// but the transform really isn't used, so we have to get the camera
void BetterCamera::localTrans(float x,float y,float z)
{
	Matrix cam;
	getCamera(cam);

	posX -= x*cam[0][0] + y*cam[0][1] + z*cam[0][2];
	posY -= x*cam[1][0] + y*cam[1][1] + z*cam[1][2];	
	posZ -= x*cam[2][0] + y*cam[2][1] + z*cam[2][2];
}

bool BetterCamera::uiStep()
{
	unsigned long uitime = clock();
	unsigned long te = uitime-lastUItime;
	lastUItime = uitime;

	float u = ((float) te) / 30.f;

	bool didSomething = false;
	//switched to == 1 so cory would stop whining :p
	//if (buttonDown>1) {
	if (buttonDown == 1) {
	forward(3 * u); didSomething = true; }

	if (Fl::get_key(FL_Left)) {
	direction += .1f * u; didSomething = true; }
	if (Fl::get_key(FL_Right)) {
	direction -= .1f * u; didSomething = true; }
	if (Fl::get_key(FL_Up)) {
	pitch -= .1f * u; didSomething = true; }
	if (Fl::get_key(FL_Down)) {
	pitch += .1f * u; didSomething = true; }
	if (Fl::get_key(' ')) {
	forward(3 * u); didSomething = true; }
	if (Fl::get_key('x')) {
	forward(-3 * u); didSomething = true; }
	if (Fl::get_key(FL_KP+'8')) {
	localTrans(0,-u,0); didSomething = true; }
	if (Fl::get_key(FL_KP+'2')) {
	localTrans(0,u,0); didSomething = true; }
	if (Fl::get_key(FL_KP+'4')) {
	localTrans(u,0,0); didSomething = true; }
	if (Fl::get_key(FL_KP+'6')) {
	localTrans(-u,0,0); didSomething = true; }
	if (Fl::get_key(FL_KP+'5')) {
	localTrans(0,0,u); didSomething = true; }
	if (Fl::get_key(FL_KP+'0')) {
	localTrans(0,0,-u); didSomething = true; }

	if (Fl::get_key('d')) {
	localTrans(-u,0,0); didSomething = true; }
	if (Fl::get_key('a')) {
	localTrans(u,0,0); didSomething = true; } 
	if (Fl::get_key('s')) {
	forward(-3 * u); didSomething = true; }
	if (Fl::get_key('w')) {
	forward(3 * u); didSomething = true; }

	if (Fl::get_key('e')) {
	localTrans(0,-u,0); didSomething = true; }
	if (Fl::get_key('q')) {
	localTrans(0,u,0); didSomething = true; }
	
	if(Fl::get_key('p'))
	{
		printf("%f, %f, %f\n", posX, posY, posZ);
	}

	return didSomething;
}