/*
    Copyright (C) 2003 by Walter Schreppers 
    Copyright (C) 2004 by Cies Breijs                           

    This program is free software; you can redistribute it and/or
    modify it under the terms of version 2 of the GNU General Public
    License as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

// This file is originally written by Walter Scheppers, but almost
// every aspect of it is slightly changed by Cies Breijs.
  
 
#include <unistd.h> // for usleep();
#include <stdlib.h>

#include <tqtimer.h>

#include <tdeapplication.h>
#include <kdebug.h>
#include <tdelocale.h>

#include "executer.h"

// this function is used in executer and canvas:
#define ROUND2INT(x) ( (x) >= 0 ? (int)( (x) + .5 ) : (int)( (x) - .5 ) )


Executer::Executer(TreeNode* tree)
{
	this->tree = tree;
	functionTable.clear();
	bBreak = false;
	bReturn = false;
}

Executer::~Executer()
{
	emit Finished();
}

bool Executer::run()
{
	bBreak = false;
	bReturn = false;
	bPause = false;
	bAbort = false;
	symtable main;
	symbolTables.push(main); // new symbol table for main block
	
	TreeNode::const_iterator i;
	for (i = tree->begin(); i != tree->end(); ++i)
	{
		if (bAbort) return false;
		kapp->processEvents();
		execute(*i);
	
		symbolTables.pop(); //free up stack
	}
	return true;
}

void Executer::slowDown(TreeNode* node)
{
	switch (runSpeed)
	{
		case 1: // slow
			startWaiting(0);
			break;
		
		case 2: // slower
			startWaiting(250);
			break;
		
		case 3: // slowest
			startWaiting(900);
			break;
		
		default:
			kdDebug(0)<<"Executer: Wrong execution speed given"<<endl;
			break;
	}
	Token tok = node->getToken();
	emit setSelection(tok.start.row, tok.start.col, tok.end.row, tok.end.col);
}

void Executer::slotChangeSpeed(int speed)
{
	runSpeed = speed;
}

void Executer::pause()
{
	// The next line is within all loops of the Executer
	//     if (bAbort) return;
	// mostly before
	//     kapp->processEvents();
	// this to keep the GUI of KTurtle accessible while executing the logo code
	// so the Abort button can be clicked, and will function
	bPause = true;
}

void Executer::abort()
{
	// The next line is within all loops of the Executer
	//     if(bAbort) return;
	// mostly before
	//     kapp->processEvents();
	// this to keep the GUI of KTurtle accessible while executing the logo code
	// so the Abort button can be clicked, and will function
	bAbort = true;
}


void Executer::execute(TreeNode* node)
{
	switch ( node->getType() )
	{
		case blockNode          : execBlock(node);          break;
		case forNode            : execFor(node);            break;
		case forEachNode        : execForEach(node);        break;
		case whileNode          : execWhile(node);          break;
		case ifNode             : execIf(node);             break;
		case assignNode         : execAssign(node);         break;
		case expressionNode     : execExpression(/*node*/); break;
		case idNode             : execId(node);             break;
		case constantNode       : execConstant(/*node*/);   break; // does nothing value allready set
		
		case addNode            : execAdd(node);            break;
		case mulNode            : execMul(node);            break;
		case divNode            : execDiv(node);            break;
		case subNode            : execSub(node);            break;
		case minusNode          : execMinus(node);          break;
	
		case nodeGE             : execGE(node);             break; 
		case nodeGT             : execGT(node);             break;
		case nodeLE             : execLE(node);             break;
		case nodeLT             : execLT(node);             break;
		case nodeNE             : execNE(node);             break;
		case nodeEQ             : execEQ(node);             break;
		
		case andNode            : execAnd(node);            break;
		case orNode             : execOr(node);             break;
		case notNode            : execNot(node);            break;
		
		case functionNode       : createFunction(node);     break;
		case functionCallNode   : execFunction(node);       break;
		case funcReturnNode     : execRetFunction(node);    break;
		case returnNode         : execReturn(node);         break;
		case breakNode          : execBreak(/*node*/);      break;
		
		case runNode            : execRun(node);            break;
		
		case ClearNode          : execClear(node);          break;
		case GoNode             : execGo(node);             break;
		case GoXNode            : execGoX(node);            break;
		case GoYNode            : execGoY(node);            break;
		case ForwardNode        : execForward(node);        break;
		case BackwardNode       : execBackward(node);       break;
		case DirectionNode      : execDirection(node);      break;
		case TurnLeftNode       : execTurnLeft(node);       break;
		case TurnRightNode      : execTurnRight(node);      break;
		case CenterNode         : execCenter(node);         break;
		case SetPenWidthNode    : execSetPenWidth(node);    break;
		case PenUpNode          : execPenUp(node);          break;
		case PenDownNode        : execPenDown(node);        break;
		case SetFgColorNode     : execSetFgColor(node);     break;
		case SetBgColorNode     : execSetBgColor(node);     break;
		case ResizeCanvasNode   : execResizeCanvas(node);   break;
		case SpriteShowNode     : execSpriteShow(node);     break;
		case SpriteHideNode     : execSpriteHide(node);     break;
		case SpritePressNode    : execSpritePress(node);    break;
		case SpriteChangeNode   : execSpriteChange(node);   break;

		case MessageNode        : execMessage(node);        break;
		case InputWindowNode    : execInputWindow(node);    break;
		case printNode          : execPrint(node);          break;
		case FontTypeNode       : execFontType(node);       break;
		case FontSizeNode       : execFontSize(node);       break;
		case RepeatNode         : execRepeat(node);         break;
		case RandomNode         : execRandom(node);         break;
		case WaitNode           : execWait(node);           break;
		case WrapOnNode         : execWrapOn(node);         break;
		case WrapOffNode        : execWrapOff(node);        break;
		case ResetNode          : execReset(node);          break;
		
		case EndOfFileNode      : break; // just do nothing is enough
		
		case Unknown            : // dont break but fallthrough to default
		
		default:
			kdDebug(0)<<"Found unsupported node named '"<<node->getLook()<<"' in the tree @ ("<<node->getRow()<<", "<<node->getCol()<<")"<<endl;
			break;
	}  
}


void Executer::createFunction(TreeNode* node)
{
	TQString funcname = node->getLook();
	functionTable[funcname] = node; //store for later use
}


//execute a function
void Executer::execFunction(TreeNode* node)
{
	TQString funcname = node->getLook();

	// locate function node  
	functable::iterator p = functionTable.find(funcname);
	if ( p == functionTable.end() )
	{
		emit ErrorMsg(node->getToken(), i18n("Call to undefined function: %1.").arg(funcname), 5010);
		return;
	}
	
	TreeNode* funcnode   = p->second;
	TreeNode* funcIds    = funcnode->firstChild();
	TreeNode* callparams = node->firstChild();
		
	// check if number of parameters match
	if ( callparams->size() != funcIds->size() )
	{
		emit ErrorMsg(node->getToken(), i18n("Call to function '%1' with wrong number of parameters.").arg(funcname), 5020);
		return;
	}

	// pass parameters to function
	// by adding them to it's symboltable and setting the values
	TreeNode::iterator pfrom, pto = funcIds->begin();
	symtable funcSymTable;
	
	for (pfrom = callparams->begin(); pfrom != callparams->end(); ++pfrom )
	{
		if (bAbort) return;
		if (bPause) startPausing();
		kapp->processEvents();
		
		// execute the parameters which can be expressions
		execute(*pfrom); 
		
		TQString idname = (*pto)->getLook();
		funcSymTable[idname] = (*pfrom)->getValue();
		++pto;
	}
	
	symbolTables.push(funcSymTable); // use new symboltable for current function
	
	// execute function statement block
	bReturn = false; // set to true when return is called
	execute( funcnode->secondChild() );
	bReturn = false; // function execution done
	
	symbolTables.pop(); // release function symboltable    
}


// execute a function and expect and get return 
// value from stack
// first child   = function name
// second child  = parameters
void Executer::execRetFunction(TreeNode* node)
{
	execFunction(node);
	if (runStack.size() == 0)
	{
		emit ErrorMsg(node->getToken(), i18n("Function %1 did not return a value.").arg( node->getLook() ), 5030);
		return;
	}
	node->setValue( runStack.top() ); // set return val
	runStack.pop(); // remove from stack
}


void Executer::execReturn(TreeNode* node)
{
	execute( node->firstChild() ); // execute return expression
	runStack.push( node->firstChild()->getValue() );
	bReturn = true; // notify blocks of return
}


void Executer::execBreak(/*TreeNode* node*/)
{
	bBreak = true; // stops loop block execution
}


void Executer::execBlock(TreeNode* node)
{
	// execute all statements in block
	TreeNode::iterator i;
	for (i = node->begin(); i != node->end(); ++i)
	{
		if (runSpeed != 0) slowDown(*i);
		if (bAbort) return;
		if (bPause) startPausing();
		kapp->processEvents();
		
		execute(*i);
	
		if (bReturn || bBreak) break; //jump out of block		
	}
}


void Executer::execForEach(TreeNode* node)
{
	// sorry, not fully implemented/tested yet
	TreeNode* expr1      = node->firstChild();
	TreeNode* expr2      = node->secondChild();
	TreeNode* statements = node->thirdChild();
	
	execute(expr1);
	execute(expr2);
	
	TQString expStr1 = expr1->getValue().String();
	TQString expStr2 = expr2->getValue().String();
	
	bBreak = false;
	
	int i = expStr2.contains(expStr1, false);
	for ( ; i > 0; i-- )
	{
		if (bAbort) return;
		if (bPause) startPausing();
		kapp->processEvents();
		
		execute(statements);
		if (bBreak || bReturn) break; //jump out loop
	}
	bBreak = false;
}



void Executer::execFor(TreeNode* node)
{
	TreeNode* id = node->firstChild();
	TreeNode* startNode = node->secondChild();
	TreeNode* stopNode = node->thirdChild();
	TreeNode* statements = node->fourthChild();
	
	TQString name = id->getLook();
	
	execute(startNode);
	//assign startval to id
	Value startVal = startNode->getValue();
	( symbolTables.top() )[ name ] = startVal;
	
	
	execute(stopNode);
	Value stopVal = stopNode->getValue();
	
	if(node->size() == 4 ) //for loop without step part
	{
		bBreak = false;
		for (double d = startVal.Number(); d <= stopVal.Number(); d = d + 1)
		{
			if (bAbort) return;
			if (bPause) startPausing();
			kapp->processEvents();
			( symbolTables.top() )[name] = d;
			execute( statements );
			if (bBreak || bReturn) break; //jump out loop
		}
		bBreak = false;
	}
	else //for loop with step part
	{
		TreeNode* step = node->fourthChild();
		statements = node->fifthChild();
		
		execute(step);
		Value stepVal = step->getValue();
		bBreak = false;
		if ( (stepVal.Number() >= 0.0) && (startVal.Number() <= stopVal.Number() ) )
		{
			for ( double d = startVal.Number(); d <= stopVal.Number(); d = d + stepVal.Number() )
			{
				if (bAbort) return;
				if (bPause) startPausing();
				kapp->processEvents();
				
				(symbolTables.top() )[name] = d;
				execute( statements );
				if (bBreak || bReturn) break; //jump out loop
			}
		}
		else if ( (stepVal.Number() < 0.0) && (startVal.Number() >= stopVal.Number() ) )
		{
			for (double d = startVal.Number(); d >= stopVal.Number(); d = d + stepVal.Number() )
			{
				if (bAbort) return;
				if (bPause) startPausing();
				kapp->processEvents();
				
				( symbolTables.top() )[name] = d;
				execute(statements);
				if (bBreak || bReturn) break; //jump out loop
			}
		}
		bBreak = false;
	}
}



void Executer::execRepeat(TreeNode* node)
{
	TreeNode* value = node->firstChild();
	TreeNode* statements = node->secondChild();
	
	bBreak = false;
	execute(value);
	for ( int i = ROUND2INT( value->getValue().Number() ); i > 0; i-- )
	{
		if (bAbort) return;
		if (bPause) startPausing();
		kapp->processEvents();
		
		execute(statements);
		if (bBreak || bReturn) break; //jump out loop
	}
	bBreak = false;
}


void Executer::execWhile(TreeNode* node)
{
	TreeNode* condition = node->firstChild();
	TreeNode* statements = node->secondChild();
	
	bBreak = false;
	execute(condition);
	while (condition->getValue().Number() != 0)
	{
		if (bAbort) return;
		if (bPause) startPausing();
		kapp->processEvents();
		
		execute(statements);
		if (bBreak || bReturn) break; //jump out loop
		execute(condition);
	}
	bBreak = false;
}

     
void Executer::execIf(TreeNode* node)
{
	TreeNode* condition = node->firstChild();
	TreeNode* ifblok = node->secondChild();
	
	//determine if there is an else part
	if (node->size() == 2) // no else
	{
		execute( condition );
		if( condition->getValue().Number() != 0 ) execute(ifblok);   
	}
	else // else part given
	{
		TreeNode* elseblok = node->thirdChild();
		execute( condition );
		if( condition->getValue().Number() != 0 ) execute(ifblok);
		else execute( elseblok );
	}
}



void Executer::execAssign(TreeNode* node)
{
	TreeNode* expr = node->firstChild();

	execute(expr);
	( symbolTables.top() )[ node->getLook() ] = expr->getValue();
}
    
void Executer::execExpression(/*TreeNode* node*/)
{
	// execExpression is not implemented, because it should not be needed!
}

void Executer::execId(TreeNode* node)
{
	node->setValue( ( symbolTables.top() )[ node->getLook() ] );
}

void Executer::execConstant(/*TreeNode* node*/)
{
	// do nothing, value is already set
}

Value Executer::exec2getValue(TreeNode* node)
{
	execute(node);
	return node->getValue();
}

        
void Executer::execAdd(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	if (left.Type() == numberValue && right.Type() == numberValue) node->setValue( left + right );
	else node->setValue( left.String().append( right.String() ) );
}

       
void Executer::execMul(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	if (left.Type() == numberValue && right.Type() == numberValue) node->setValue( left * right );
	else emit ErrorMsg(node->getToken(), i18n("Can only multiply numbers."), 9000);
}

       
void Executer::execDiv(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	if (left.Type() == numberValue && right.Type() == numberValue)
	{
		if (right.Number() == 0) emit ErrorMsg(node->getToken(), i18n("Cannot divide by zero."), 9000);
		else node->setValue( left / right );
	}
	else emit ErrorMsg(node->getToken(), i18n("Can only divide numbers."), 9000);
}

       
void Executer::execSub(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	if (left.Type() == numberValue && right.Type() == numberValue)
		node->setValue( left - right );
	
	else emit ErrorMsg(node->getToken(), i18n("Can only subtract numbers."), 9000);
}


       
void Executer::execLT(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	node->setValue( left < right );
}

void Executer::execLE(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	node->setValue( left <= right );
}

void Executer::execGT(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	node->setValue( left > right );
}

void Executer::execGE(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	node->setValue( left >= right );
}


void Executer::execEQ(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	node->setValue( left == right );
}


void Executer::execNE(TreeNode* node)
{
	Value left( exec2getValue( node->firstChild() ) );
	Value right( exec2getValue( node->secondChild() ) );
	
	node->setValue( left != right );
}


  
void Executer::execAnd(TreeNode* node)
{
	bool nl = exec2getValue( node->firstChild() ).Number() != 0;
	bool nr = exec2getValue( node->secondChild() ).Number() != 0;
	node->setValue( (double) (nl && nr) );
}

       
void Executer::execOr(TreeNode* node)
{
	bool nl = exec2getValue( node->firstChild() ).Number() != 0;
	bool nr = exec2getValue( node->secondChild() ).Number() != 0;
	node->setValue(nl || nr);
}


void Executer::execNot(TreeNode* node)
{
	node->setValue( exec2getValue( node->firstChild() ).Number() == 0 ); 
}


void Executer::execMinus(TreeNode* node)
{
	node->setValue( -exec2getValue( node->firstChild() ).Number() ); 
}


TQString Executer::runCommand(const TQString& command)
{
	FILE *pstream;
	
	if ( ( pstream = popen( command.ascii(), "r" ) ) == NULL ) return ("");
	
	TQString Line;
	char buf[100];
	
	while( fgets(buf, sizeof(buf), pstream) !=NULL) {
		if (bAbort) return ("");
		kapp->processEvents();
		
		Line += buf;
	}
	pclose(pstream);
	return Line;
}


void Executer::execRun(TreeNode* node)
{
	TQString cmd = exec2getValue( node->firstChild() ).String();
	node->setValue( runCommand(cmd) );
}




void Executer::execClear(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit Clear();
}

void Executer::execCenter(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit Center();
}

void Executer::execPenUp(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit PenUp();
}

void Executer::execPenDown(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit PenDown();
}

void Executer::execSpriteShow(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit SpriteShow();
}

void Executer::execSpriteHide(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit SpriteHide();
}

void Executer::execSpritePress(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit SpritePress();
}

void Executer::execWrapOn(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit WrapOn();
}

void Executer::execWrapOff(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit WrapOff();
}

void Executer::execReset(TreeNode* node)
{
	if ( checkParameterQuantity(node, 0, 5060) ) emit Reset();
}

void Executer::execMessage(TreeNode* node)
{
	if ( checkParameterQuantity(node, 1, 5060) && checkParameterType(node, stringValue, 5060) )
		emit MessageDialog( node->firstChild()->getValue().String() );
}






void Executer::execGoX(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit GoX( param1->getValue().Number() );
	}
}

void Executer::execGoY(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit GoY( param1->getValue().Number() );
	}
}

void Executer::execForward(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit Forward( param1->getValue().Number() );
	}
}

void Executer::execBackward(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit Backward( param1->getValue().Number() );
	}
}

void Executer::execDirection(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit Direction( param1->getValue().Number() );
	}
}

void Executer::execTurnLeft(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit TurnLeft( param1->getValue().Number() );
	}
}

void Executer::execTurnRight(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit TurnRight( param1->getValue().Number() );
	}
}

void Executer::execSetPenWidth(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		int x = ROUND2INT( param1->getValue().Number() ); // pull the number value & round it to int
		if (x < 1 || x > 10000)
			emit ErrorMsg(node->getToken(), i18n("The penwidth cannot be set to something smaller than 1, or bigger than 10000."), 6050);
		else
			emit SetPenWidth(x);
	}
}

void Executer::execSpriteChange(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		int x = ROUND2INT( param1->getValue().Number() ); // pull the number value & round it to int
		emit SpriteChange(x);
	}
}

void Executer::execFontSize(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		int x = ROUND2INT( param1->getValue().Number() ); // pull the number value & round it to int
		if ( x < 0 || x > 350 )
			emit ErrorMsg(node->getToken(), i18n("The parameters of function %1 must be within range: 0 to 350.").arg( node->getLook() ), 5065);
		else
			emit FontSize(x);
	}
}






void Executer::execGo(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 2, 5060) ) return;	
	TreeNode* nodeX = node->firstChild(); // getting
	TreeNode* nodeY = node->secondChild();
	execute(nodeX); // executing
	execute(nodeY);
	
	if ( checkParameterType(node, numberValue, 5060) )
	{
		emit Go( nodeX->getValue().Number(), nodeY->getValue().Number() );
	}
}

void Executer::execResizeCanvas(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 2, 5060) ) return;
	TreeNode* nodeX = node->firstChild(); // getting
	TreeNode* nodeY = node->secondChild();
	execute(nodeX); // executing
	execute(nodeY);
	
	if ( checkParameterType(node, numberValue, 5060) )
	{
		int x = ROUND2INT( nodeX->getValue().Number() ); // converting & rounding to int
		int y = ROUND2INT( nodeY->getValue().Number() );
		if ( ( x < 1 || y < 1 ) || ( x > 10000 || y > 10000 ) )
			emit ErrorMsg(node->getToken(), i18n("The parameters of the %1 command must be numbers in the range: 1 to 10000.").arg( node->getLook() ), 7030);
		else
			emit ResizeCanvas(x, y);
	}
}

void Executer::execRandom(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 2, 5060) ) return;
	TreeNode* nodeX = node->firstChild(); // getting
	TreeNode* nodeY = node->secondChild();
	execute(nodeX); // executing
	execute(nodeY);
	
	if ( !checkParameterType(node, numberValue, 5060) ) return;
	double x = nodeX->getValue().Number();
	double y = nodeY->getValue().Number();
	double r = (double)( TDEApplication::random() ) / RAND_MAX;
	node->setValue( r * ( y - x ) + x );
}





void Executer::execSetFgColor(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 3, 5060) ) return;
	TreeNode* nodeR = node->firstChild(); // getting
	TreeNode* nodeG = node->secondChild();
	TreeNode* nodeB = node->thirdChild();
	execute(nodeR); // executing
	execute(nodeG);
	execute(nodeB);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		int r = ROUND2INT( nodeR->getValue().Number() ); // converting & rounding to int
		int g = ROUND2INT( nodeG->getValue().Number() );
		int b = ROUND2INT( nodeB->getValue().Number() );
		if ( ( r < 0 || g < 0 || b < 0 ) || ( r > 255 || g > 255 || b > 255 ) )
			emit ErrorMsg(node->getToken(), i18n("The parameters of the %1 command must be numbers in the range: 0 to 255.").arg( node->getLook() ), 6090);
		else
			emit SetFgColor(r, g, b);
	}
}

void Executer::execSetBgColor(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 3, 5060) ) return;
	TreeNode* nodeR = node->firstChild(); // getting
	TreeNode* nodeG = node->secondChild();
	TreeNode* nodeB = node->thirdChild();
	execute(nodeR); // executing
	execute(nodeG);
	execute(nodeB);
	if ( checkParameterType(node, numberValue, 5060) )
	{
		int r = ROUND2INT( nodeR->getValue().Number() ); // converting & rounding to int
		int g = ROUND2INT( nodeG->getValue().Number() );
		int b = ROUND2INT( nodeB->getValue().Number() );
		if ( ( r < 0 || g < 0 || b < 0 ) || ( r > 255 || g > 255 || b > 255 ) )
			emit ErrorMsg(node->getToken(), i18n("The parameters of the %1 command must be numbers in the range: 0 to 255.").arg( node->getLook() ), 6090);
		else
			emit SetBgColor(r, g, b);
	}
}











void Executer::execInputWindow(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;

	TQString value = node->firstChild()->getValue().String();
	emit InputDialog(value);
	
	node->setType(constantNode);
	if ( value.isEmpty() ) node->getValue().resetValue(); // set value back to empty
	else
	{
		bool ok = true;
		double num = value.toDouble(&ok); // to see if the value from the InpDialog is a float
		if (ok) node->setValue(num);
		else    node->setValue(value);
	}
}

void Executer::execPrint(TreeNode* node)
{
	if (node->size() == 0) 
	{
		emit ErrorMsg(node->getToken(), i18n("The print command needs input"), 5050);
		return;
	}
	TreeNode::iterator i;
	TQString str = "";
	for (i = node->begin(); i != node->end(); ++i)
	{
		execute(*i); // execute expression
		str = str + (*i)->getValue().String();
	}
	emit Print(str);
}

void Executer::execFontType(TreeNode* node)
{
	// if not 2 params go staight to the checkParam, diplay the error, and return to prevent a crash
	if ( !checkParameterQuantity(node, 2, 5060) && !checkParameterType(node, stringValue, 5060) ) return;
	
	TQString extra;
	if (node->size() == 2) TQString extra = node->secondChild()->getValue().String();
	TQString family = node->firstChild()->getValue().String();
	emit FontType(family, extra);
}


void Executer::execWait(TreeNode* node)
{
	if ( !checkParameterQuantity(node, 1, 5060) ) return;
	TreeNode* param1 = node->firstChild();
	execute(param1);
	if ( !checkParameterType(node, numberValue, 5060) ) return;
	int msec = (int)( 1000 * param1->getValue().Number() );
	startWaiting(msec);
}

void Executer::startWaiting(int msec)
{
	bStopWaiting = false;
	// call a timer that sets stopWaiting to true when it runs 
	TQTimer::singleShot( msec, this, TQT_SLOT( slotStopWaiting() ) );
	while (bStopWaiting == false)
	{
		if (bAbort) return; // waits need to be interrupted by the stop action
		if (bPause) startPausing();
		kapp->processEvents();

		// only 10 times per second is enough... else the CPU gets 100% loaded ( not nice :)
		usleep(100000);
	}
}

void Executer::slotStopWaiting()
{
	bStopWaiting = true;
}

void Executer::startPausing()
{
	while (bPause == true)
	{
		if (bAbort) return; // waits need to be interrupted by the stop action
		kapp->processEvents();
		// only 10 times per second is enough... else the CPU gets 100% loaded ( not nice :)
		usleep(100000);
	}
}

void Executer::slotStopPausing()
{
	bPause = false;
}




bool Executer::checkParameterQuantity(TreeNode* node, uint quantity, int errorCode)
{
	if (quantity == 0)
	{
		if (node->size() == 0) return true; // thats easy!
		emit ErrorMsg(node->getToken(), i18n("The %1 command accepts no parameters.").arg( node->getLook() ), errorCode);
		return false;
	}
	
	uint nodeSize = node->size();
	if (nodeSize != 0) // when all parameters are forgotten the parser puts a Unknown/tokEOL param, catch this:
		if (node->firstChild()->getToken().type == tokEOL) nodeSize = 0;
	
	if (nodeSize != quantity)
	{
		if (nodeSize < quantity)
		{
			emit ErrorMsg(node->getToken(), i18n("The %1 command was called with %2 but needs 1 parameter.", "The %1 command was called with %2 but needs %n parameters.", quantity).arg( node->getLook() ).arg(nodeSize), errorCode);
		}
		else
		{
			emit ErrorMsg(node->getToken(), i18n("The %1 command was called with %2 but only accepts 1 parameter.", "The %1 command was called with %2 but only accepts %n parameters.", quantity).arg( node->getLook() ).arg(nodeSize), errorCode);
		}
		return false;
	}
	return true; // if all tests passed
}


bool Executer::checkParameterType(TreeNode* node, int valueType, int errorCode)
{
	uint quantity = node->size();
	uint ii = 1;
	TreeNode::iterator i = node->begin();
	while ( i != node->end() && ii <= quantity )
	{
		if ( (*i)->getValue().Type() != valueType )
		{
			switch (valueType)
			{
				case stringValue:
					if (quantity == 1)
						emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts a string as its parameter.").arg( node->getLook() ), errorCode); 
					else
						emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts strings as its parameters.").arg( node->getLook() ), errorCode);
					break;
				
				case numberValue:
					if (quantity == 1)
						emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts a number as its parameter.").arg( node->getLook() ), errorCode);
					else
						emit ErrorMsg(node->getToken(), i18n("The %1 command only accepts numbers as its parameters.").arg( node->getLook() ), errorCode);
					break;
			}
			return false;
		}
		++i;
		ii++;
	}
	return true; // if all tests passed
}

#include "executer.moc"
