#include "KarteAuswahl.h"
#include <Text.h>
#include <Rahmen.h>
#include <Punkt.h>
#include <Schrift.h>
#include <AlphaFeld.h>
#include <TextFeld.h>
#include <Datei.h>
#include <DateiSystem.h>
#include "..\..\..\Global\Initialisierung.h"
#include <MausEreignis.h>
#include "..\..\..\Global\Variablen.h"
#include "..\..\..\Leser\KartenLeser.h"

void KarteAuswahlKSGSAktion( void *p, RCArray< KSGSVariable > *parameter, KSGSVariable **retVal )
{
    if( !p )
        return;
    ( (KarteDaten*)p )->ksgsAktion( parameter, retVal );
}

// Inhalt der KarteDaten Klasse aus KarteAuswahl.h
// Konstruktor
KarteDaten::KarteDaten( Schrift *zSchrift, int id )
{
    hintergrund = 0;
    beschreibung = 0;
    ksgs = 0;
    rahmen = new LRahmen();
    rahmen->setFarbe( 0xFFFFFFFF );
    rahmen->setRamenBreite( 1 );
    tickVal = 0;
    animation = 0;
    ausgewählt = 0;
    pos = Punkt( 0, 500 );
    gr = Punkt( 200, 100 );
    schrift = zSchrift->getThis();
    karteId = id;
    aktion = 1;
    geladen = 0;
    auswahl = new AlphaFeld();
    auswahl->setFarbe( 0x0000FF00 );
    auswahl->setStärke( 8 );
    auswahl->setGröße( 200, 100 );
    auswAlpha = 0;
    rend = 0;
    erlaubt = 0;
    tAlpha = 0;
    alpha = 0;
    ref = 1;
    start();
}

// Destruktor
KarteDaten::~KarteDaten()
{
    if( run )
        this->warteAufThread( 5000 );
    if( run )
        ende();
    if( schrift )
        schrift->release();
    if( hintergrund )
        hintergrund->release();
    if( beschreibung )
    {
        beschreibung->zurücksetzen();
        beschreibung->release();
    }
    if( ksgs )
    {
        dllDateien->releaseDLL( "KSGScript.dll" );
        ksgs = 0;
    }
    rahmen->release();
    auswahl->release();
}

// nicht constant
void KarteDaten::thread()
{
    if( !aktion )
    {
        geladen = 0;
        if( hintergrund )
            hintergrund = hintergrund->release();
        if( beschreibung )
        {
            beschreibung->zurücksetzen();
            beschreibung = beschreibung->release();
        }
        rend = 1;
        if( ksgs )
        {
            dllDateien->releaseDLL( "KSGScript.dll" );
            ksgs = 0;
        }
    }
    else
    {
        KartenLeser *mapReader = new KartenLeser();
        mapReader->setKarteId( karteId );
        if( !hintergrund )
            hintergrund = mapReader->getKartenTitelBild( schrift );
        if( !geladen )
            geladen = 1;
        rend = 1;
        if( aktion == 2 )
        {
            if( !mapReader->getKartenBeschreibung() )
                nachLogin->zNachrichtenListe()->addNachricht( new Text( "Fehler" ), new Text( "Beschreibung nicht gefunden." ), new Text( "Ok" ) );
            if( beschreibung )
            {
                beschreibung->zurücksetzen();
                beschreibung = beschreibung->release();
            }
            if( !ksgs )
                ksgs = dllDateien->ladeDLL( "KSGScript.dll", "data/bin/KSGScript.dll" );
            if( ksgs )
            {
                KSGSGetZeichnung getKSGScript = (KSGSGetZeichnung)GetProcAddress( ksgs, KSGS_START_FUNKTION );
                if( getKSGScript )
                {
                    beschreibung = getKSGScript();
                    beschreibung->setBildschirmZ( hauptScreen->getThis() );
                    beschreibung->setSchriftZ( schrift->getThis() );
                    beschreibung->setGröße( 578, 428 );
                    beschreibung->setRückrufParam( this );
                    beschreibung->setRückrufFunktion( KarteAuswahlKSGSAktion );
                    Text *pf = mapReader->getKartePfad();
                    *pf += "beschreibung.ksgs";
                    beschreibung->setScriptDatei( pf );
                }
                else
                {
                    nachLogin->zNachrichtenListe()->addNachricht( new Text( "Fehler" ),
                                                                  new Text( "Der Einstiegspunkt '" KSGS_START_FUNKTION "' in der DLL-Datei "
                                                                  "'data/bin/KSGScript.dll' konnte nicht gefunden werden." ),
                                                                  new Text( "Ok" ), 0, NachrichtType::nachricht, 0 );
                }
            }
            else
            {
                nachLogin->zNachrichtenListe()->addNachricht( new Text( "Fehler" ),
                                                              new Text( "Die DLL-Datei 'data/bin/KSGScript.dll' konnte nicht geladen werden." ),
                                                              new Text( "Ok" ), 0, NachrichtType::nachricht, 0 );
            }
            if( beschreibung )
                geladen = 2;
            rend = 1;
        }
        mapReader->release();
    }
    aktion = 0;
    if( !erlaubt )
        updateErlaubt();
    run = 0;
    rend = 1;
}

void KarteDaten::updateErlaubt()
{
    if( geladen != 2 )
        return;
    bool update = erlaubt;
    erlaubt = infoKlient->istKarteErlaubt( karteId );
    if( update != erlaubt && beschreibung && ksgs )
    {
        KSGSGetVariable getKSGSVar = (KSGSGetVariable)GetProcAddress( ksgs, KSGS_VARIABLE_FUNKTION );
        RCArray< KSGSVariable > *params = new RCArray< KSGSVariable >();
        KSGSVariableDef p1;
        p1.typId = KSGS_BOOL;
        p1.wert = (int)erlaubt;
        params->add( getKSGSVar( beschreibung, &p1 ) );
        KSGSVariable *var = beschreibung->startFunktion( beschreibung->getFunktionId( "_set_Erlaubt" ), params );
        if( var )
            var->release();
    }
}

void KarteDaten::ksgsAktion( RCArray< KSGSVariable > *parameter, KSGSVariable **retVal )
{
    if( parameter && parameter->getEintragAnzahl() > 0 )
    {
        Text *txt = parameter->z( 0 )->getText();
        if( erlaubt && txt->istGleich( "anmelden" ) )
        {
            if( nachLogin && nachLogin->zSpielenFenster() )
                nachLogin->zSpielenFenster()->anmelden( karteId );
        }
        if( erlaubt && txt->istGleich( "gruppeErstellen" ) )
        {
            int ret = anmeldungKlient->gruppeErstellen( karteId );
            if( !ret )
            {
                nachLogin->zNachrichtenListe()->addNachricht( new Text( "Fehler" ), new Text( anmeldungKlient->getLetzterFehler() ),
                                                              new Text( "Ok" ), 0, NachrichtType::nachricht, 0 );
            }
            else
                nachLogin->zSpielenFenster()->gruppeBetreten( ret );
        }
        txt->release();
    }
}

void KarteDaten::setSichtbar( bool sichtbar )
{
    if( sichtbar )
        animation |= 0x1;
    else
    {
        animation &= ~0x1;
        setAuswahl( 0 );
    }
    if( sichtbar )
    {
        warteAufThread( 1000 );
        aktion = 2;
        start();
    }
    rend = 1;
}

void KarteDaten::setSichtbar()
{
    animation |= 0x1;
    if( ausgewählt && geladen == 2 )
    {
        animation |= 0x4;
        beschreibung->setPosition( beschreibung->getX(), 0 );
    }
    if( geladen != 2 )
    {
        warteAufThread( 1000 );
        aktion = 2;
        start();
    }
    rend = 1;
}

void KarteDaten::setAuswahl( bool auswahl )
{
    if( ausgewählt == auswahl )
        return;
    ausgewählt = auswahl;
    if( auswahl )
    {
        animation |= 0x4;
        if( beschreibung && ksgs )
        {
            beschreibung->neuLaden();
            KSGSGetVariable getKSGSVar = (KSGSGetVariable)GetProcAddress( ksgs, KSGS_VARIABLE_FUNKTION );
            RCArray< KSGSVariable > *params = new RCArray< KSGSVariable >();
            KSGSVariableDef p1;
            p1.typId = KSGS_BOOL;
            p1.wert = (int)erlaubt;
            params->add( getKSGSVar( beschreibung, &p1 ) );
            KSGSVariable *var = beschreibung->startFunktion( beschreibung->getFunktionId( "_set_Erlaubt" ), params );
            if( var )
                var->release();
        }
    }
    else
        animation &= ~0x4;
    rend = 1;
}

void KarteDaten::setPosition( int lPos )
{
    pos.y = lPos * 100;
    rend = 1;
}

bool KarteDaten::tick( double tickVal )
{
    if( beschreibung )
        rend |= beschreibung->tick( tickVal );
    this->tickVal += tickVal * 500;
    int val = ( int ) this->tickVal;
    if( val < 1 )
    {
        bool ret = rend;
        rend = 0;
        return ret;
    }
    if( val > 17 )
        val = 17;
    this->tickVal -= val;
    if( ausgewählt )
    {
        if( auswAlpha != 0xF0 )
        {
            auswAlpha += val;
            if( auswAlpha > 0xF0 )
                auswAlpha = 0xF0;
            rend = 1;
        }
    }
    else
    {
        if( auswAlpha != 0 )
        {
            auswAlpha -= val;
            if( auswAlpha > 0xF0 )
                auswAlpha = 0;
            rend = 1;
        }
    }
    if( ( animation | 0x1 ) == animation ) // sichtbar
    {
        if( tAlpha != 255 )
        {
            if( tAlpha + val > 255 )
                tAlpha = 255;
            else
                tAlpha += val;
            rend = 1;
        }
    }
    else // unsichtbar
    {
        if( tAlpha != 0 )
        {
            if( tAlpha - val < 0 )
                tAlpha = 0;
            else
                tAlpha -= val;
            rend = 1;
        }
    }
    if( ( animation | 0x4 ) == animation ) // auswählen
    {
        if( beschreibung )
        {
            if( alpha != 255 )
            {
                if( alpha + val < 255 )
                    alpha += val;
                else
                    alpha = 255;
                rend = 1;
            }
        }
    }
    else // abwählen
    {
        int a = ( auswahl->getFarbe() >> 24 ) & 0xFF;
        if( a != 0 )
        {
            a -= val;
            if( a < 0 )
                a = 0;
            auswahl->setFarbe( ( ( a << 24 ) & 0xFF000000 ) | ( auswahl->getFarbe() & 0xFFFFFF ) );
            rend = 1;
        }
        if( beschreibung )
        {
            if( alpha != 0 )
            {
                if( alpha - val > 0 )
                    alpha -= val;
                else
                    alpha = 0;
                rend = 1;
            }
        }
    }
    bool ret = rend;
    rend = 0;
    return ret;
}

void KarteDaten::doMausEreignis( MausEreignis &me )
{
    me.mx -= gr.x;
    if( beschreibung )
        beschreibung->doMausEreignis( me );
    me.mx += gr.x;
}

void KarteDaten::render( Bild &zRObj )
{
    int x = pos.x;
    int y = pos.y;
    int br = gr.x;
    int hö = gr.y;
    if( !zRObj.setDrawOptions( x, y, br, hö ) )
        return;
    zRObj.setAlpha( tAlpha );
    rahmen->setGröße( br, hö );
    rahmen->render( zRObj );
    int rbr = rahmen->getRBreite();
    if( geladen && hintergrund )
        zRObj.drawBild( rbr, rbr, br - rbr * 2, hö - rbr * 2, *hintergrund );
    if( auswAlpha && auswahl )
    {
        auswahl->setFarbe( ( auswahl->getFarbe() & 0x00FFFFFF ) | ( auswAlpha << 24 ) );
        auswahl->setPosition( rbr, rbr );
        auswahl->setGröße( br - rbr * 2, hö - rbr * 2 );
        auswahl->render( zRObj );
    }
    zRObj.releaseDrawOptions();
    x = br;
    y = 0;
    br = 580;
    hö = 480;
    if( !zRObj.setDrawOptions( x, y, br, hö ) )
    {
        zRObj.releaseAlpha();
        return;
    }
    if( geladen == 2 )
    {
        zRObj.setAlpha( alpha );
        if( beschreibung )
            beschreibung->render( zRObj );
        zRObj.releaseAlpha();
    }
    zRObj.releaseDrawOptions();
    zRObj.releaseAlpha();
}

// constant
int KarteDaten::getKarteId() const
{
    return karteId;
}

bool KarteDaten::istausgewählt() const
{
    return ausgewählt;
}

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

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

// Inhalt der KarteAuswahlFenster Klasse aus KarteAuswahl.h
// Konstruktor
KarteAuswahlFenster::KarteAuswahlFenster( Schrift *zSchrift )
{
    schrift = zSchrift->getThis();
    rahmen = new LRahmen();
    rahmen->setFarbe( 0xFFFFFFFF );
    rahmen->setRamenBreite( 1 );
    rahmen->setGröße( 760, 500 );
    members = new RCArray< KarteDaten >();
    anzahl = 0;
    animation = 0;
    auswahl = -1;
    tickVal = 0;
    seite = 0;
    pos = Punkt( 10, 10 );
    gr = Punkt( 780, 430 );
    spielId = 0;
    rend = 0;
    alpha = 0;
    ref = 1;
}

// Destruktor
KarteAuswahlFenster::~KarteAuswahlFenster()
{
    if( schrift )
        schrift->release();
    if( rahmen )
        rahmen->release();
    if( members )
        members->release();
}

// nicht constant
void KarteAuswahlFenster::setSpielId( int id )
{
    spielId = id;
    members->leeren();
    anzahl = 0;
    start();
}

void KarteAuswahlFenster::setSichtbar( bool sichtbar )
{
    if( sichtbar )
    {
        animation |= 0x1;
        start();
    }
    else
    {
        auswahl = -1;
        for( int i = seite * 4; i >= 0 && i < anzahl && i < seite * 4 + 4; i++ )
            members->z( i )->setSichtbar( 0 );
        animation &= ~0x1;
    }
    rend = 1;
}

void KarteAuswahlFenster::blättern( bool oben )
{
    for( int i = seite * 4; i >= 0 && i < anzahl && i < seite * 4 + 4; i++ )
        members->z( i )->setSichtbar( 0 );
    seite += oben ? 1 : -1;
    for( int i = seite * 4; i >= 0 && i < anzahl && i < seite * 4 + 4; i++ )
    {
        members->z( i )->setPosition( i % 4 );
        members->z( i )->setSichtbar( 1 );
    }
    auswahl = -1;
    rend = 1;
}

void KarteAuswahlFenster::updateListe()
{
    if( run )
        return;
    start();
}

void KarteAuswahlFenster::thread()
{
    Array< int > *liste = infoKlient->getAccountKarteListe( spielId );
    if( !liste )
    {
        nachLogin->zNachrichtenListe()->addNachricht( new Text( "Fehler" ), new Text( infoKlient->getLetzterFehler() ),
                                                      new Text( "Ok" ), 0, NachrichtType::nachricht, 0 );
        run = 0;
        return;
    }
    int anz = liste->getEintragAnzahl();
    for( int i = 0; i < anz; i++ )
    {
        bool gefunden = 0;
        for( int j = 0; j < anzahl; j++ )
        {
            KarteDaten *tmp = members->z( j );
            if( liste->hat( i ) && tmp->getKarteId() == liste->get( i ) )
            {
                gefunden = 1;
                break;
            }
        }
        if( !gefunden )
        {
            KarteDaten *tmp = new KarteDaten( schrift, liste->hat( i ) ? liste->get( i ) : 0 );
            members->add( tmp, anzahl );
            anzahl++;
        }
    }
    if( liste )
        liste->release();
    for( int i = 0; i < anzahl; i++ )
        members->z( i )->updateErlaubt();
    for( int i = seite * 4; i < anzahl && i >= 0 && i < seite * 4 + 4; i++ )
    {
        members->z( i )->setPosition( i % 4 );
        members->z( i )->setSichtbar();
    }
    rend = 1;
    run = 0;
}

bool KarteAuswahlFenster::tick( double tickVal )
{
    for( int i = 0; i < anzahl; i++ )
        rend |= members->z( i )->tick( tickVal );
    this->tickVal += tickVal * 750;
    int val = ( int )this->tickVal;
    if( val < 1 )
    {
        bool ret = rend;
        rend = 0;
        return ret;
    }
    if( val > 25 )
        val = 25;
    this->tickVal -= val;
    if( ( animation | 0x1 ) == animation ) // sichtbar
    {
        if( alpha < 255 )
        {
            if( alpha + val >= 255 )
            {
                alpha = 255;
                for( int i = seite * 4; i < anzahl && i >= 0 && i < seite * 4 + 4; i++ )
                {
                    members->z( i )->setPosition( i % 4 );
                    members->z( i )->setSichtbar( 1 );
                }
            }
            else
                alpha += val;
            rend = 1;
        }
    }
    else // unsichtbar
    {
        if( alpha > 0 )
        {
            if( alpha - val < 0 )
                alpha = 0;
            else
                alpha -= val;
            rend = 1;
        }
    }
    bool ret = rend;
    rend = 0;
    return ret;
}

void KarteAuswahlFenster::doMausEreignis( MausEreignis &me )
{
    if( !members )
        return;
    if( pos.x != 10 )
        return;
    me.mx -= pos.x;
    me.my -= pos.y;
    for( int i = 0; i < anzahl; i++ )
        members->z( i )->doMausEreignis( me );
    if( me.mx < 0 || me.my < 0 )
    {
        me.mx += pos.x;
        me.my += pos.y;
        return;
    }
    if( me.mx > 200 || me.my > getAnzahlAufSeite() * 100 )
    {
        me.mx += pos.x;
        me.my += pos.y;
        return;
    }
    if( me.id == ME_RLinks )
    {
        int treffer = me.my / 100 + seite * 4;
        if( treffer >= anzahl )
        {
            me.mx += pos.x;
            me.my += pos.y;
            return;
        }
        if( treffer == auswahl )
        {
            me.mx += pos.x;
            me.my += pos.y;
            return;
        }
        if( auswahl >= 0 )
            members->z( auswahl )->setAuswahl( 0 );
        members->z( treffer )->setAuswahl( 1 );
        auswahl = treffer;
        rend = 1;
    }
    me.mx += pos.x;
    me.my += pos.y;
}

void KarteAuswahlFenster::render( Bild &zrObj )
{
    int x = pos.x;
    int y = pos.y;
    int br = gr.x;
    int hö = gr.y;
    if( !zrObj.setDrawOptions( x, y, br, hö ) )
        return;
    zrObj.setAlpha( alpha );
    rahmen->setGröße( br, hö );
    rahmen->render( zrObj );
    int rbr = rahmen->getRBreite();
    if( !zrObj.setDrawOptions( rbr, rbr, br - rbr * 2, hö - rbr * 2 ) )
    {
        zrObj.releaseDrawOptions();
        zrObj.releaseAlpha();
        return;
    }
    for( int i = seite * 4; i >= 0 && i < anzahl && i < seite * 4 + 4; i++ )
        members->z( i )->render( zrObj );
    zrObj.releaseDrawOptions();
    if( !anzahl )
    {
        Text t = "Dieser Account besitzt momentan noch keine Karten für dieses Spiel.\nBesuche den Shop um neue Karten zu erwerben!";
        schrift->lock();
        schrift->setDrawPosition( 10, 10 );
        schrift->setSchriftGröße( 12 );
        schrift->renderText( &t, zrObj, 0xFFFFFFFF );
        schrift->unlock();
    }
    zrObj.releaseDrawOptions();
    zrObj.releaseAlpha();
}

// constant
int KarteAuswahlFenster::getAnzahl() const
{
    return anzahl;
}

int KarteAuswahlFenster::getSeiteAnzahl() const
{
    return ( anzahl / 4.0 == anzahl / 4 ) ? ( anzahl / 4 ) : ( anzahl / 4 + 1 );
}

int KarteAuswahlFenster::getSeite() const
{
    return seite;
}

int KarteAuswahlFenster::getAnzahlAufSeite() const
{
    return ( anzahl < seite * 4 + 4 ) ? ( anzahl - seite * 4 ) : 4;
}

bool KarteAuswahlFenster::hatAuswahl() const
{
    return auswahl != -1;
}

KarteDaten *KarteAuswahlFenster::getAuswahl() const
{
    return members->get( auswahl );
}

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

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