#include "Objekt.h"
#include "MausEreignis.h"
#include "TastaturEreignis.h"
#include "Punkt.h"
#include <Windows.h>

using namespace Framework;

// Inhalt der Objekt Klasse aus Objekt.h
// Konstruktor 
Objekt::Objekt()
{
	Mak = 0;
	Tak = 0;
	pos = new Punkt( 0, 0 );
	gr = new Punkt( 0, 0 );
	InitializeCriticalSection( &Thread_Save );
	mausIn = 0;
}

// Destruktor 
Objekt::~Objekt()
{
	pos->release();
	gr->release();
	DeleteCriticalSection( &Thread_Save );
}

// nicht constant 
void Objekt::lockObjekt()
{
	EnterCriticalSection( &Thread_Save );
}

void Objekt::unlockObjekt()
{
	LeaveCriticalSection( &Thread_Save );
}

void Objekt::setMausEreignis( bool (*ak)( void *, MausEreignis ) ) // setzt das Maus Ereignis
{
	lockObjekt();
	Mak = ak;
	unlockObjekt();
}

void Objekt::setTastaturEreignis( bool (*ak)( void *, TastaturEreignis ) ) // setzt das TastaturEreignis
{
	lockObjekt();
	Tak = ak;
	unlockObjekt();
}

void Objekt::doMausEreignis( MausEreignis *me ) // ruft Mak auf
{
	if( me->verarbeitet || ( !( me->mx >= pos->x && me->mx <= pos->x + gr->x && me->my >= pos->y && me->my <= pos->y + gr->y ) && me->id != ME_Verlässt ) )
	{
		if( mausIn )
		{
			mausIn = 0;
			MausEreignis me2;
			me2.id = ME_Verlässt;
			me2.mx = me->mx;
			me2.my = me->my;
			me2.verarbeitet = 0;
			doMausEreignis( &me2 );
		}
		return;
	}
	if( !mausIn && me->id != ME_Verlässt )
	{
		mausIn = 1;
		MausEreignis me2;
		me2.id = ME_Betritt;
		me2.mx = me->mx;
		me2.my = me->my;
		me2.verarbeitet = 0;
		doMausEreignis( &me2 );
	}
	if( Mak != 0 )
	{
		me->verarbeitet |= Mak( this, *me );
		return;
	}
}

void Objekt::doTastaturEreignis( TastaturEreignis *te ) // ruft Tak auf
{
	if( te->verarbeitet )
		return;
	if( Tak != 0 )
	{
		unlockObjekt();
		te->verarbeitet |= Tak( this, *te );
	}
}

void Objekt::setPosition( Punkt *pos ) // setzt die position
{
	lockObjekt();
	this->pos->setP( pos->getX(), pos->getY() );
	pos->release();
	unlockObjekt();
}

void Objekt::setPositionZ( Punkt *pos )
{
	lockObjekt();
	if( this->pos )
		this->pos->release();
	this->pos = pos;
	unlockObjekt();
}

void Objekt::setGröße( Punkt *gr ) // setzt die Größe
{
	lockObjekt();
	this->gr->setP( gr->getX(), gr->getY() );
	gr->release();
	unlockObjekt();
}

void Objekt::setGrößeZ( Punkt *gr )
{
	lockObjekt();
	if( this->gr )
		this->gr->release();
	this->gr = gr;
	unlockObjekt();
}

void Objekt::setPosition( int x, int y ) // setzt die position
{
	lockObjekt();
	this->pos->setP( x, y );
	unlockObjekt();
}

void Objekt::setGröße( int x, int y ) // setzt die Größe
{
	lockObjekt();
	this->gr->setP( x, y );
	unlockObjekt();
}

void Objekt::tick( double tickval )
{

}

void Objekt::render( Bild *rObj )
{

}

void Objekt::render( int xOff, int yOff, int bOff, int hOff, Bild *rObj )
{

}

// constant 
bool Objekt::hatMausEreignis() const // prüft, ob Mak gesetzt ist
{
	return Mak != 0;
}

bool Objekt::hatTastaturEreignis() const // prüft, ob Tak gesetzt ist
{
	return Tak != 0;
}

Punkt *Objekt::getPosition() const // gibt die Position zurück
{
	return pos->getThis();
}

Punkt *Objekt::getGröße() const // gibt die Größe zurück
{
	return gr->getThis();
}

int Objekt::getBreite() const // gibt die Breite zurück
{
	return gr->getX();
}

int Objekt::getHöhe() const // gibt die Höhe zurück
{
	return gr->getY();
}

int Objekt::getX() const // gibt X zurück
{
	return pos->getX();
}

int Objekt::getY() const // gibt Y zurück
{
	return pos->getY();
}

// Inhalt der ObjektArray Klasse aus Objekt.h
// Konstruktor 
ObjektArray::ObjektArray()
{
	next = 0;
	This = 0;
}

// Destruktor 
ObjektArray::~ObjektArray()
{
	if( next )
		delete next;
}

// nicht const 
bool ObjektArray::addObjekt( Objekt *obj ) // Fügt ein Objekt hinzu
{
	if( obj == This )
		return 0;
	if( !This )
	{
		This = obj;
		return 1;
	}
	if( !next )
		next = new ObjektArray();
	return next->addObjekt( obj );
}

bool ObjektArray::removeObjekt( Objekt *obj ) // Entfernt ein Objekt
{
	if( obj == This )
	{
		if( index == 0 )
		{
			if( next )
			{
				This = next->getObjekt();
				ObjektArray *tmp = next->getNext();
				next->setNext0();
				delete next;
				next = tmp;
			}
			else
				This = 0;
			return 0;
		}
		return 1;
	}
	if( !next )
		return 0;
	if( next->removeObjekt( obj ) )
	{
		ObjektArray *tmp = next->getNext();
		next->setNext0();
		delete next;
		next = tmp;
	}
	return 0;
}

bool ObjektArray::removeObjekt( int i ) // Entfernt das von diesem aus i-te Objekt
{
	if( i == index )
	{
		if( index == 0 )
		{
			This = next->getObjekt();
			ObjektArray *tmp = next->getNext();
			next->setNext0();
			delete next;
			next = tmp;
			return 0;
		}
		return 1;
	}
	if( !next )
		return 0;
	if( next->removeObjekt( i ) )
	{
		ObjektArray *tmp = next->getNext();
		next->setNext0();
		delete next;
		next = tmp;
	}
	return 0;
}

void ObjektArray::setNext0() // Setzt das nächste Objekt zu 0
{
	next = 0;
}

void ObjektArray::updateIndex( int i ) // aktualisiert die Index variable
{
	index = i;
	if( next )
		next->updateIndex( i + 1 );
}

// constant 
ObjektArray *ObjektArray::getNext() const // gibt das nächste Objekt zurück
{
	return next;
}

Objekt *ObjektArray::getObjekt( int i ) const // gibt das von diesem aus i-te Objekt zurück
{
	if( i == index )
		return This;
	if( !next )
		return 0;
	return next->getObjekt( i );
}

Objekt *ObjektArray::getObjekt() const // gibt das von diesem aus i-te Objekt zurück
{
	return This;
}

int ObjektArray::getIndex() const // Gibt den Index zurück
{
	return index;
}

void ObjektArray::sendMausAll( MausEreignis *me ) const // sendet me an alle volgenden Objekte
{
	if( next )
		next->sendMausAll( me );
	if( This )
		This->doMausEreignis( me );
}

void ObjektArray::sendTastaturAll( TastaturEreignis *te ) const // sendet te an alle volgenden Objekte
{
	if( next )
		next->sendTastaturAll( te );
	if( This )
		This->doTastaturEreignis( te );
}

void ObjektArray::sendMaus( MausEreignis *me ) const // sendet me an dieses Objekt
{
	This->doMausEreignis( me );
}

void ObjektArray::sendTastatur( TastaturEreignis *te ) const // sendet te an dieses Objekt
{
	This->doTastaturEreignis( te );
}

void ObjektArray::sendMaus( int i, MausEreignis *me ) const // sendet me an das von diesem aus i-te Objekt
{
	if( index == 1 )
	{
		This->doMausEreignis( me );
		return;
	}
	if( next )
		next->sendMaus( i, me );
}

void ObjektArray::sendTastatur( int i, TastaturEreignis *te ) const // sendet te an das von diesem aus i-te Objekt
{
	if( index == 1 )
	{
		This->doTastaturEreignis( te );
		return;
	}
	if( next )
		next->sendTastatur( i, te );
}

void ObjektArray::render( Bild *rObj )
{
	if( This )
		This->render( rObj );
	if( next )
		next->render( rObj );
}

void ObjektArray::render( int xOff, int yOff, int bOff, int hOff, Bild *rObj )
{
	if( This )
		This->render( xOff, yOff, bOff, hOff, rObj );
	if( next )
		next->render( xOff, yOff, bOff, hOff, rObj );
}

void ObjektArray::tick( double tickval )
{
	if( This )
		This->tick( tickval );
	if( next )
		next->tick( tickval );
}