#include "Spieler.h"

#include "Team.h"
#include "Laser.h"
#include "Karte.h"
#include "SSKlient.h"
#include <iostream>

// Inhalt der Spieler Klasse aus Spieler.h
// Konstruktor
Spieler::Spieler( SpielerStr *zStr )
    : Model2DObject()
{
    accountId = 0;
    sNum = zStr->id;
    farbe = 0;
    team = 0;
    klient = 0;
    for( int i = 0; i < T_MAX; i++ )
        tastatur[ i ] = 0;
    amLeben = 1;
    schussAbk = 0;
    energieAbk = 0;
    repAbk = 0;
    reinkAbk = 0;
    maxReinkAbk = 5;
    startPos = zStr->pos;
    setPosition( startPos );
    setDrehung( (float)zStr->rot );
    beschleunigung = zStr->beschleunigung;
    beschleunigungStart = zStr->beschleunigung;
    energie = zStr->maxEnergie;
    stability = zStr->maxStability;
    reparatur = zStr->reparatur;
    laserIntensity = zStr->laserIntensity;
    laserEffizienz = zStr->laserEffizienz;
    akkuLeistung = zStr->akkuLeistung;
    akkuLeistungStart = zStr->akkuLeistung;
    maxEnergie = zStr->maxEnergie;
    maxStability = zStr->maxStability;
    laserTempo = zStr->laserTempo;
    netzwerk = zStr->netzwerk;
    wendigkeit = zStr->wendigkeit;
    wendigkeitStart = zStr->wendigkeit;
    antriebEffizienz = zStr->antriebEffizienz;
    energieSchild = zStr->energieSchild;
    energieSchildEffizienz = zStr->energieSchild;
    skillPunkte = zStr->skillPunkte;
    schadenBekommen = 0;
    schadenGemacht = 0;
    treibstoffVerbraucht = 0;
    shots = 0;
    treffer = 0;
    punkte = 0;
    kills = 0;
    tode = 0;
    zeitAmLeben = 0;
    zeitTod = 0;
    needWiederbelebung = 0;
}

// Destruktor
Spieler::~Spieler()
{
    if( team )
        team->release();
    if( klient )
        klient->release();
}

// nicht constant
void Spieler::offline()
{
    klient->offline();
}

void Spieler::online( SSKlientV *zKlient )
{
    klient->online( zKlient );
}

void Spieler::setModelData( Model2DData *data )
{
    for( auto i = data->polygons->getIterator(); i; i++ )
    {
        if( i._.name->istGleich( "engine_l" ) )
        {
            stL = *i._.schwerpunkt;
            Vertex l, r;
            for( int j = 0; j < 4; j++ )
            {
                if( i._.tKordinaten->get( j ).y == 1.f )
                {
                    if( i._.tKordinaten->get( j ).x == 0.f )
                        l = i._.vertex->get( j );
                    if( i._.tKordinaten->get( j ).x == 1.f )
                        r = i._.vertex->get( j );
                }
            }
            kL = ( ( l + ( r - l ) * 0.5 ) - stL );
        }
        if( i._.name->istGleich( "engine_r" ) )
        {
            stR = *i._.schwerpunkt;
            Vertex l, r;
            for( int j = 0; j < 4; j++ )
            {
                if( i._.tKordinaten->get( j ).y == 1.f )
                {
                    if( i._.tKordinaten->get( j ).x == 0.f )
                        l = i._.vertex->get( j );
                    if( i._.tKordinaten->get( j ).x == 1.f )
                        r = i._.vertex->get( j );
                }
            }
            kR = ( ( l + ( r - l ) * 0.5 ) - stR );
        }
        if( i._.name->istGleich( "engine_m" ) )
        {
            stM = *i._.schwerpunkt;
            Vertex l, r;
            for( int j = 0; j < 4; j++ )
            {
                if( i._.tKordinaten->get( j ).y == 1.f )
                {
                    if( i._.tKordinaten->get( j ).x == 0.f )
                        l = i._.vertex->get( j );
                    if( i._.tKordinaten->get( j ).x == 1.f )
                        r = i._.vertex->get( j );
                }
            }
            kM = ( ( l + ( r - l ) * 0.5 ) - stM );
        }
    }
    kL.normalize();
    kR.normalize();
    kM.normalize();
    setModel( data );
}

void Spieler::setAccountId( int id )
{
    accountId = id;
}

void Spieler::setTeam( Team *team )
{
    if( this->team )
        this->team->release();
    this->team = team;
}

void Spieler::setSpielerFarbe( int farbe )
{
    this->farbe = farbe;
}

void Spieler::setKlient( Klient *klient )
{
    if( this->klient )
        this->klient->release();
    this->klient = klient;
}

bool Spieler::setTastataturStatus( TastaturStatus ts, bool aktiv )
{
    if( tastatur[ ts ] == aktiv || !amLeben )
        return 0;
    tastatur[ ts ] = aktiv;
    return 1;
}

bool Spieler::tick( const WeltInfo& info, double zeit )
{
    if( !team )
        return 0;
    reinkAbk -= zeit;
    if( reinkAbk < 0 )
        reinkAbk = 0;
    if( !reinkAbk && !amLeben )
    { // Wiederbelebung
        needWiederbelebung = 1;
        return 0;
    }
    if( amLeben )
    {
        schussAbk -= zeit;
        energieAbk -= zeit;
        if( schussAbk < 0 )
            schussAbk = 0;
        if( energieAbk < 0 )
            energieAbk = 0;
        repAbk -= zeit;
        if( repAbk < 0 )
            repAbk = 0;
        if( tastatur[ T_GAS ] )
        {
            double treibstoff = 0.5 * ( ( beschleunigung + team->beschleunigung ) / 5 )
                * zeit * ( 100 / ( antriebEffizienz + team->antriebEffizienz ) );
            treibstoffVerbraucht += treibstoff;
            float factor = 1;
            if( treibstoff > energie )
                factor = (float)(energie / treibstoff);
            impuls( getWorldPos( stM ), getWorldDir( kM ) * (float)zeit * (float)( beschleunigung + team->beschleunigung ) * factor );
            energie -= treibstoff * factor;
        }
        if( tastatur[ T_ROT_R ] )
        {
            double treibstoff = 0.25 * ( ( wendigkeit + team->wendigkeit ) / 5 )
                * zeit * ( 100 / ( antriebEffizienz + team->antriebEffizienz ) );
            treibstoffVerbraucht += treibstoff;
            float factor = 1;
            if( treibstoff > energie )
                factor = (float)( energie / treibstoff );
            impuls( getWorldPos( stL ), getWorldDir( kL ) * (float)zeit * (float)( wendigkeit + team->wendigkeit ) * factor );
            energie -= treibstoff * factor;
        }
        if( tastatur[ T_ROT_L ] )
        {
            double treibstoff = 0.25 * ( ( wendigkeit + team->wendigkeit ) / 5 )
                * zeit * ( 100 / ( antriebEffizienz + team->antriebEffizienz ) );
            treibstoffVerbraucht += treibstoff;
            float factor = 1;
            if( treibstoff > energie )
                factor = (float)( energie / treibstoff );
            impuls( getWorldPos( stR ), getWorldDir( kR ) * (float)zeit * (float)( wendigkeit + team->wendigkeit ) * factor );
            energie -= treibstoff * factor;
        }
        Model2DObject::tick( info, zeit );
        if( !energieAbk )
        {
            energie += ( akkuLeistung + team->akkuLeistung ) * zeit;
            if( energie > ( maxEnergie + team->maxEnergie ) )
                energie = ( maxEnergie + team->maxEnergie );
        }
        if( !repAbk )
        {
            stability += ( reparatur + team->reparatur ) * zeit;
            if( stability > ( maxStability + team->maxStability ) )
                stability = ( maxStability + team->maxStability );
        }
        zeitAmLeben += zeit;
    }
    else
        zeitTod += zeit;
    return 0;
}

bool Spieler::setSkill( int art )
{
    if( !skillPunkte )
        return 0;
    skillPunkte--;
    switch( art )
    {
    case 0: // Max Stabilität
        maxStability += 10;
        stability += 10;
        team->maxStability = team->getMaxStabilityBonus();
        break;
    case 1: // Max Energie
        maxEnergie += 10;
        team->maxEnergie = team->getMaxEnergieBonus();
        break;
    case 2: // Reparatur
        reparatur += 0.15;
        team->reparatur = team->getReperaturBonus();
        break;
    case 3: // Laser Intensität
        laserIntensity += 3;
        team->laserIntensity = team->getLaserIntensityBonus();
        break;
    case 4: // Laser Effizienz
        laserEffizienz += 1;
        team->laserEffizienz = team->getLaserEffizienzBonus();
        break;
    case 5: // Laser Tempo
        laserTempo += 20;
        team->laserTempo = team->getLaserTempoBonus();
        break;
    case 6: // Beschleunigung
        beschleunigung += 1.75;
        team->beschleunigung = team->getBeschleunigungBonus();
        break;
    case 7: // Wendigkeit
        wendigkeit += 2.5;
        team->wendigkeit = team->getWendigkeitBonus();
        break;
    case 8: // Netzwerk
        netzwerk += 1;
        team->maxStability = team->getMaxStabilityBonus();
        team->maxEnergie = team->getMaxEnergieBonus();
        team->reparatur = team->getReperaturBonus();
        team->laserIntensity = team->getLaserIntensityBonus();
        team->laserEffizienz = team->getLaserEffizienzBonus();
        team->laserTempo = team->getLaserTempoBonus();
        team->beschleunigung = team->getBeschleunigungBonus();
        team->wendigkeit = team->getWendigkeitBonus();
        team->akkuLeistung = team->getAkkuLeistungBonus();
        team->antriebEffizienz = team->getAntriebEffizienzBonus();
        team->energieSchild = team->getEnergieSchildBonus();
        team->energieSchildEffizienz = team->getEnergieSchildEffizienzBonus();
        break;
    case 9: // Akkuleistung
        akkuLeistung += 0.12;
        team->akkuLeistung = team->getAkkuLeistungBonus();
        break;
    case 10: // Akkuleistung
        antriebEffizienz += 10;
        team->antriebEffizienz = team->getAntriebEffizienzBonus();
        break;
    case 11: // Energie Schild
        energieSchild += 1;
        team->energieSchild = team->getEnergieSchildBonus();
        break;
    case 12: // Energie Schild Effizienz
        energieSchildEffizienz += 2;
        team->energieSchildEffizienz = team->getEnergieSchildEffizienzBonus();
        break;
    }
    return 1;
}

Laser *Spieler::getLaser( int sId )
{
    if( !amLeben || !tastatur[ T_FEUER ] || schussAbk || !team )
        return 0;
    double kosten = ( ( laserIntensity + team->laserIntensity ) / 2 + ( laserTempo + team->laserTempo ) / 13 ) * ( 1 / ( ( laserEffizienz + team->laserEffizienz ) / 25 ) );
    if( kosten < 1 )
        kosten = 1;
    if( kosten > energie )
        return 0;
    energie -= kosten;
    schussAbk = 1;
    energieAbk = 1.5;
    shots++;
    Vec2< double > sSpeed = ( Vec2<double>( cos( rotation ), sin( rotation ) ) * ( laserTempo + team->laserTempo ) );
    sSpeed += speed;
    return new Laser( sId, getPosition(), sSpeed, sNum, laserIntensity + team->laserIntensity );
}

bool Spieler::nimmSchaden( double &intensity )
{
    double schieldVal = intensity / 100 * energieSchild;
    double schieldEVal = schieldVal - schieldVal / 100 * energieSchildEffizienz;
    if( schieldEVal > energie )
    {
        schieldEVal = energie;
        schieldVal = schieldEVal / ( 1 - ( energieSchildEffizienz / 100 ) );
    }
    intensity -= schieldVal;
    std::cout << "Schaden: " << intensity << " ";
    energie -= schieldEVal;
    stability -= intensity;
    std::cout << "Stabilität: " << stability << "\n";
    schadenBekommen += intensity;
    repAbk = 2;
    if( stability <= 0 )
    {
        amLeben = 0;
        tode++;
        stability = 0;
        reinkAbk += maxReinkAbk;
        maxReinkAbk++;
        punkte--;
    }
    return stability == 0;
}

void Spieler::machSchaden( double intensity, bool kill )
{
    schadenGemacht += intensity;
    treffer++;
    if( kill )
    {
        skillPunkte += 2;
        kills++;
        punkte++;
        maxReinkAbk--;
        if( maxReinkAbk < 5 )
            maxReinkAbk = 5;
    }
}

void Spieler::wiederbeleben()
{
    setPosition( startPos );
    reinkAbk = maxReinkAbk * 2;
    energie = maxEnergie + team->maxEnergie;
    stability = maxStability + team->maxStability;
    schussAbk = 0;
    energieAbk = 0;
    repAbk = 0;
    setSpeed( 0, 0 );
    setDrehung( 0 );
    setDrehungSpeed( 0 );
    for( int i = 0; i < T_MAX; i++ )
        tastatur[ i ] = 0;
    amLeben = 1;
}

// constant
int Spieler::getAccountId() const
{
    return accountId;
}

bool Spieler::istOnline() const
{
    return klient ? klient->istOnline() : 0;
}

Klient *Spieler::zKlient() const
{
    return klient;
}

bool Spieler::istTreffer( Vec2< float > pos ) const
{
    if( !amLeben )
        return 0;
    return istPunktInnen( pos );
}

// Raumschiff Eigenschaften
double Spieler::getTeamMaxEnergieBonus() const
{
    return maxEnergie / 100 * netzwerk;
}

double Spieler::getTeamMaxStabilityBonus() const
{
    return maxStability / 100 * netzwerk;
}

double Spieler::getTeamReparaturBonus() const
{
    return reparatur / 100 * netzwerk;
}

double Spieler::getTeamLaserIntensityBonus() const
{
    return laserIntensity / 100 * netzwerk;
}

double Spieler::getTeamLaserEffizienzBonus() const
{
    return laserEffizienz / 100 * netzwerk;
}

double Spieler::getTeamAkkuLeistungBonus() const
{
    return akkuLeistung / 100 * netzwerk;
}

double Spieler::getTeamLaserTempoBonus() const
{
    return laserTempo / 100 * netzwerk;
}

double Spieler::getTeamBeschleunigungBonus() const
{
    return beschleunigung / 100 * netzwerk;
}

double Spieler::getTeamWendigkeitBonus() const
{
    return wendigkeit / 100 * netzwerk;
}

double Spieler::getTeamAntriebEffizienzBonus() const
{
    return antriebEffizienz / 100 * netzwerk;
}

double Spieler::getTeamEnergieSchildBonus() const
{
    return energieSchild / 100 * netzwerk;
}

double Spieler::getTeamEnergieSchildEffizienzBonus() const
{
    return energieSchildEffizienz / 100 * netzwerk;
}

bool Spieler::istAmLeben() const
{
    return amLeben;
}

// Statistik Werte
int Spieler::getSpielerNummer() const
{
    return sNum;
}

Team *Spieler::zTeam() const
{
    return team;
}

int Spieler::getSpielerFarbe() const
{
    return farbe;
}

int Spieler::getSchadenBekommen() const
{
    return (int)schadenBekommen;
}

int Spieler::getSchadenGemacht() const
{
    return (int)schadenGemacht;
}

int Spieler::getTreibstoffVerbraucht() const
{
    return (int)treibstoffVerbraucht;
}

int Spieler::getShots() const
{
    return shots;
}

int Spieler::getTreffer() const
{
    return treffer;
}

int Spieler::getPunkte() const
{
    return punkte;
}

int Spieler::getKills() const
{
    return kills;
}

int Spieler::getTode() const
{
    return tode;
}

int Spieler::getZeitAmLeben() const
{
    return (int)zeitAmLeben;
}

int Spieler::getZeitTod() const
{
    return (int)zeitTod;
}

bool Spieler::doNeedWiederbelebung() const
{
    return needWiederbelebung;
}

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

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