#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, KSGScriptProcessor *obj, KSGSVariable *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();
}

// 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( KSGSKlasseInstanz::erstellVariable( obj, zDef->get( i ) ), id );
                else
                    lokaleVariablen->set( var, id );
            }
            else
                lokaleVariablen->set( vars->get( id ), id );
        }
        else
            lokaleVariablen->set( KSGSKlasseInstanz::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 = (KSGSVariable *)retVar->release();
    if( returnTyp == KSGS_THREAD )
    {
        threadVar = new KSGSThreadKlasse( obj, (KSGSFunktionInstanz *)getThis() );
        start();
        return (KSGSVariable *)threadVar->getThis();
    }
    else
    {
        run = 1;
        thread();
        warteAufFunktion( INFINITE );
        return retVar ? (KSGSVariable *)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;
}

// Inhalt der KSGSFunktion Klasse aus KSGSFunktion.h
// Konstruktor
KSGSFunktion::KSGSFunktion( int id, int sichtbar, int typ )
    : ReferenceCounter(),
    typId( typ ),
    sichtbar( sichtbar ),
    id( id )
{
    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( KSGScriptProcessor *obj, KSGSVariable *klasse, RCArray< KSGSVariable > *params )
{
    KSGSFunktionInstanz *inst = new KSGSFunktionInstanz( ( RCArray< KSGSBefehl >* )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 );
}