#ifndef DEF_TX_ENGINE
 #define DEF_TX_ENGINE

//------------------------------------------//
//	TKA4 CEngine and basis Graph classes	//
//				26. 10. 2007				//
//------------------------------------------//


//--- Pragma 
#pragma comment (lib, "opengl32.lib")  
#pragma comment (lib, "glu32.lib")     
//=== Pragma 


//--- Includes
#include <GL/gl.h>
#include <GL/glu.h>

#include "TX_Object.h"
#include "TX_World.h"

#include "../IsSupported/IsSupported.h"
#include "../GLTools/GLTools.h"
//=== Includes 



//---  Class Engine TX  ---//
/*	Make a processing of 
	 graph TX_Objects.	 */
class txEngine {
	protected:
		txObject *first, *final;
		txObject *current;
	
	public:
		txWorld *World;
		txErrorFile *Log;

	public:
		txEngine(char *logname);
		~txEngine();

		inline virtual void  AddObject(txObject *new_);

		//--- Events ---
		inline virtual void  SceneInit();
		inline virtual void  SceneGo();
		inline virtual void  SceneResize(int width, int height);
};


//------------------------- :: Functions :: ---------------------------

//--- txEngine :: Add TX_Object 
void  txEngine :: SceneInit()
{
	glEnableClientState (GL_VERTEX_ARRAY);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	gltInitFrame(&World -> Camera);

	*Log+txError(0, "txEngine.Init", "Done");

	for (current = first; current != NULL; current = current -> next) 
		current->Execute_Init();
};


//--- txEngine :: Add TX_Object 
void  txEngine :: AddObject(txObject *new_)
{
	new_ -> prev = final;
	
	new_ -> world = World;

	final -> next = new_;
	final = new_;
};


//--- txEngine :: txEngine 
txEngine :: txEngine(char *logname)
{ 
	first = new txObject(); 
	first -> dir=d_nothing; 
	final = first; 
	current = first;

	World = new txWorld(0);
	Log = new txErrorFile(logname); 
	World -> Log = Log;

	*Log+txError(0, "txEngine.Constructor", "Done");
};

//--- txEngine :: ~txEngine~ ~~~ 
txEngine :: ~txEngine()
{ 
	if (first != NULL) delete first; 
	delete Log;
}


//--- txEngine :: SceneResize
void txEngine :: SceneResize(int width, int height)
{
	glViewport ( 0, 0, width, height );

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective (45.0, (double)width / (double)height, 1.0, MAX_VIEW_AREA);
	
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity();

	World -> Screen_Width = width; 
	World -> Screen_Height = height;
}


//--- txEngine :: Go Drawing
void  txEngine :: SceneGo()
{
	// Forward & Both -> next
	for (current = first; current != NULL; current = current -> next)
		switch (current -> GetDirection()) {
			case d_for : 
				glPushMatrix();
				current->Zoom();
				current->Execute_Forward(); 
				glPopMatrix();
				break;

			case d_both : 
				glPushMatrix();
				current->Zoom();
				current->Execute_Forward(); 
				current->dir = d_back;
				glPopMatrix();
				break;

			case d_for_super : 
				current->Zoom();
				current->Execute_Forward(); 
				break;

			case d_both_super : 
				current->Zoom();
				current->Execute_Forward(); 
				current->dir = d_back_super;
				break;
		};

	// Backward -> prev
	for ( current = final ; current != NULL; current = current -> prev)
	{
		if (current -> dir == d_back) {
			glPushMatrix();
			current->Execute_Backward(); 
			current->dir = d_both;
			glPopMatrix();
		};
		
		if (current -> dir == d_back_super) {
			current->Execute_Backward(); 
			current->dir = d_both_super;
		};
	};
};


#endif

