#ifndef DEF_TX_ENGINE
 #define DEF_TX_ENGINE

//------------------------------------------//
//	TKA4 CEngine and basis Graph classes	//
//				26. 10. 2007				//
//------------------------------------------//


//--- Includes
#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 :: AddObject(txObject *new_)
{
	new_ -> prev = final;

	//--- Object Inits
	new_ -> World = World;
	new_ -> color.sh = World->Shaders; 
	new_ -> color.shc = &World->ShadersCount; 
	//=== Object Inits

	final -> next = new_;
	final = new_;
};


//--- txEngine :: txEngine 
txEngine :: txEngine(char *logname)
{ 
	first = new txObject(); 
	first -> dir=d_nothing; 
	final = first; 
	current = first;

	Log = new txErrorFile(logname); 
	World = new txWorld(Log, "");
	
	*Log+txError(0, "txEngine.Constructor", "Done");
};

//--- txEngine :: ~txEngine~ ~~~ 
txEngine :: ~txEngine()
{ 
	//--- Export GL error messages in Log ---
	for ( ; ; ) {
		GLenum  glErr = glGetError ();
		if ( glErr == GL_NO_ERROR ) break;
		*Log+txError(-1, "glError", (char*) gluErrorString (glErr));
	}

	delete Log;
}


//--- txEngine :: SceneResize
void txEngine :: SceneResize(int width, int height)
{
	glViewport ( 0, 0, width, height );

	glMatrixMode(GL_PROJECTION);
	gluPerspective (45.0, (double)width / (double)height, 0.01, 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 : 
				current->Execute_Forward(); 
				break;

			case d_both : 
				current->Execute_Forward(); 
				current->dir = d_back;
				break;
	}

	// Backward -> prev
	for ( current = final; current != NULL; current = current -> prev)
		if (current -> dir == d_back) {
			current->Execute_Backward(); 
			current->dir = d_both;
		} 
	
};


//--- txEngine :: Scene Init
void  txEngine :: SceneInit()
{
	//--- Some Inits
	glEnableClientState (GL_VERTEX_ARRAY);
		
	//--- Blend Inits & Colors
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_LIGHTING);
	glEnable(GL_RESCALE_NORMAL);
	
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);


	//--- World Inits (Lights, Fog, Camera, Shaders)
	World -> Init();
	
	//--- Hints
	glHint( GL_FOG_HINT, GL_NICEST );
	glHint( GL_POLYGON_SMOOTH_HINT,         GL_NICEST );
	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

	//--- Objects Inits
	for (current = first; current != NULL; current = current -> next) 
		current->Execute_Init();
	
	*Log+txError(0, "txEngine.Init", "Done");
};



#endif

