#include "KSGSFunktion.h"
#include "../Leser/KSGSLeser.h"
#include "../Main/KSGScriptObj.h"
#include "../Klassen/KSGSThread.h"
#include "../Error/Error.h"
#include "../Klassen/KSGSTyp.h"
#include <iostream>

using namespace KSGScript;

// Inhalt der KSGSFunktionInstanz Klasse aus KSGSFunktion.h
// Konstruktor
KSGSFunktionInstanz::KSGSFunktionInstanz( RCArray< KSGSBefehl > *ba, int rt, KSGScriptObj *obj, KSGSKlasseInstanz *klasse )
    : Thread()
{
	lokaleVariablen = new RCArray< KSGSVariable >();
	befehle = ba;
	this->klasse = klasse;
	this->obj = obj;
	threadVar = 0;
	returnTyp = rt;
	retVar = 0;
	pausiert = 0;
	beendet = 0;
	breakB = 0;
	continueB = 0;
	scrId = obj->getScriptId();
	ref = 1;
}

// Destruktor
KSGSFunktionInstanz::~KSGSFunktionInstanz()
{
	lokaleVariablen->release();
	befehle->release();
	if( klasse )
	    klasse->release();
	obj->release();
	if( threadVar )
		threadVar->release();
	if( retVar )
		retVar->release();
}

// privat
void KSGSFunktionInstanz::lock()
{
    cs.lock();
}

void KSGSFunktionInstanz::unlock()
{
    cs.unlock();
}

// nicht constant
void KSGSFunktionInstanz::setParameter( Array< KSGSVariableDef* > *zDef, RCArray< KSGSVariable > *vars )
{
	int anz = zDef->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
	{
		int id = zDef->get( i )->id;
		if( vars->z( id ) )
		{
			if( zDef->get( i )->typId != vars->z( id )->getTyp() )
			{
				KSGSVariable *var = vars->z( id )->umwandelnIn( zDef->get( i )->typId );
				if( !var )
					lokaleVariablen->set( KSGSVariable::erstellVariable( obj, zDef->get( i ) ), id );
				else
					lokaleVariablen->set( var, id );
			}
			else
				lokaleVariablen->set( vars->get( id ), id );
		}
		else
			lokaleVariablen->set( KSGSVariable::erstellVariable( obj, zDef->get( i ) ), id );
	}
	vars->release();
}

void KSGSFunktionInstanz::setReturnVariable( KSGSVariable *var )
{
	if( var->getTyp() != returnTyp )
	{
		error( 15, {}, obj );
		KSGSVariable *tmp = var->umwandelnIn( returnTyp );
		var->release();
		var = tmp;
	}
	lock();
	if( retVar )
		retVar->release();
	retVar = var;
	unlock();
}

void KSGSFunktionInstanz::setPause( bool p )
{
	pausiert = p;
}

void KSGSFunktionInstanz::setContinue()
{
	continueB = 1;
}

void KSGSFunktionInstanz::setBreak()
{
	breakB = 0;
}

void KSGSFunktionInstanz::setEnde()
{
	beendet = 1;
}

KSGSVariable *KSGSFunktionInstanz::startFunktion()
{
	if( run )
		return 0;
	if( threadVar )
		threadVar = (KSGSThreadKlasse*)threadVar->release();
	if( retVar )
		retVar = retVar->release();
	if( returnTyp == KSGS_THREAD )
	{
		threadVar = new KSGSThreadKlasse( obj, getThis() );
		start();
		return threadVar->getThis();
	}
	else
	{
		run = 1;
		thread();
		warteAufFunktion( INFINITE );
		return retVar ? retVar->getThis() : 0;
	}
}

void KSGSFunktionInstanz::thread()
{
	getThis();
	int anz = befehle->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
	{
		while( pausiert && !beendet && !obj->istBeendet( scrId ) )
			Sleep( 100 );
		if( obj->istBeendet( scrId ) || beendet )
			break;
		KSGSBefehl *b = befehle->z( i );
		if( b )
		{
			KSGSVariable *var = b->ausf�hren( obj, this, klasse );
			if( var )
				var->release();
		}
	}
	run = 0;
	if( threadVar )
	{
		threadVar->threadEnde();
		threadVar = (KSGSThreadKlasse*)threadVar->release();
	}
	release();
}

int KSGSFunktionInstanz::getStatus()
{
	if( !isRunning() || beendet )
		return 0;
	if( pausiert )
		return 1;
	if( breakB )
	{
		breakB = 0;
		return 2;
	}
	if( continueB )
	{
		continueB = 0;
		return 3;
	}
	return 4;
}

void KSGSFunktionInstanz::setVariable( int id, KSGSVariable *var )
{
	lokaleVariablen->set( var, id );
}

// constant
KSGSVariable *KSGSFunktionInstanz::getVariable( int id ) const
{
	return lokaleVariablen->get( id );
}

int KSGSFunktionInstanz::getReturnTyp() const
{
	return returnTyp;
}

bool KSGSFunktionInstanz::wirdFunktionAusgef�hrt() const
{
	return isRunning();
}

int KSGSFunktionInstanz::warteAufFunktion( int zeit )
{
	if( run )
		return warteAufThread( zeit );
	return 0;
}

bool KSGSFunktionInstanz::wirdAusgef�hrt() const
{
	return isRunning() && !beendet && !pausiert;
}

// Reference Counting
KSGSFunktionInstanz *KSGSFunktionInstanz::getThis()
{
	ref++;
	return this;
}

KSGSFunktionInstanz *KSGSFunktionInstanz::release()
{
	ref--;
	if( !ref )
		delete this;
	return 0;
}


// Inhalt der KSGSFunktion Klasse aus KSGSFunktion.h
// Konstruktor
KSGSFunktion::KSGSFunktion( int id, int sichtbar, int typ )
	: typId( typ ),
	  sichtbar( sichtbar ),
	  id( id ),
	  ref( 1 )
{
	befehle = new RCArray< KSGSBefehl >();
	parameter = new Array< KSGSVariableDef* >();
	name = "";
}

// Destruktor
KSGSFunktion::~KSGSFunktion()
{
	if( befehle )
		befehle->release();
	int anz = parameter->getEintragAnzahl();
	for( int i = 0; i < anz; i++ )
		delete parameter->get( i );
	if( parameter )
		parameter->release();
}

// nicht constant
void KSGSFunktion::setName( const char *txt )
{
	name = txt;
}

void KSGSFunktion::addParameter( KSGSVariableDef *var )
{
	parameter->add( var );
}

void KSGSFunktion::addBefehl( KSGSBefehl *befehl )
{
	befehle->add( befehl );
}

KSGSFunktionInstanz *KSGSFunktion::erstellInstanz( KSGScriptObj *obj, KSGSKlasseInstanz *klasse, RCArray< KSGSVariable > *params )
{
	KSGSFunktionInstanz *inst = new KSGSFunktionInstanz( befehle->getThis(), typId, obj, klasse );
	if( params )
		inst->setParameter( parameter, params );
	return inst;
}

// constant
int KSGSFunktion::getId() const
{
	return id;
}

int KSGSFunktion::getTypId() const
{
	return typId;
}

int KSGSFunktion::getSichtbarkeit() const
{
	return sichtbar;
}

bool KSGSFunktion::hatName( const char *txt ) const
{
	return name.istGleich( txt );
}

// Reference Counting
KSGSFunktion *KSGSFunktion::getThis()
{
	ref++;
	return this;
}

KSGSFunktion *KSGSFunktion::release()
{
	ref--;
	if( !ref )
		delete this;
	return 0;
}