#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;
	
	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;

	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));
	}
	
	//--- Deleting of txObjects ---
	/*
	for (current = first->next; current->next!=NULL; current=current->next)
		delete current->prev;
	*/

	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);
	//gluOrtho2D(-100,100,-100,100); 

	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;

		/*	case d_for_super : 
				current->Execute_Forward(); 
				break;

			case d_both_super : 
				current->Execute_Forward(); 
				current->dir = d_back_super;
				break;  */
		};

	// Backward -> prev
	for ( current = final ; current != NULL; current = current -> prev)
	{
		if (current -> dir == d_back) {
			current->Execute_Backward(); 
			current->dir = d_both;
		} else
		
		if (current -> dir == d_back_super) {
			current->Execute_Backward(); 
			current->dir = d_both_super;
		};
	};
};


//--- txEngine :: Scene Init
void  txEngine :: SceneInit()
{
	//--- Some Inits
	glEnableClientState (GL_VERTEX_ARRAY);
	glEnable(GL_DEPTH_TEST);
	
	//--- Cull backs of polygons
    glCullFace(GL_BACK);
    glFrontFace(GL_CCW);
    glEnable(GL_CULL_FACE);


	//--- Blend Inits
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	//--- World Inits (Lights, ...)
	World -> Init();

	//--- Light and color Inits
	glEnable(GL_LIGHTING);

	glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glMateriali(GL_FRONT, GL_SHININESS, 128);

	//--- GLEW Inits
	if ( glewInit () != GLEW_OK )
		*Log+txError(0, "glewInit()", "Error");
	else *Log+txError(0, "glewInit()", "Ok");


	//--- Objects Inits
	for (current = first; current != NULL; current = current -> next) 
		current->Execute_Init();
	
	*Log+txError(0, "txEngine.Init", "Done");
};



#endif

