#define Global
#include "object.h"
#include <limits>

Object::Object( QString id, int classId )
    : id( id ),
      classId( classId )
{}

// Setzt die Objekt-ID
void Object::setId( QString id )
{
    this->id = id;
}

// Gibt die Objekt-ID zurück
QString Object::getId() const
{
    return id;
}

// Setzt die ID der Klasse
void Object::setClassId( int id )
{
    classId = id;
}

// Gibt die ID der Klasse zurück
int Object::getClassId() const
{
    return classId;
}

// Vergleicht zwei Objekte anhand ihrer ID
bool operator == (const Object &p1, const Object &p2)
{
    return p1.getId() == p2.getId();
}

// Inhalt der _ObjektPolygon Klasse
//----------------------------------

_ObjectPolygon::_ObjectPolygon( QString id, QPolygon po, bool truncated, int index, FrameTreeNode *parent )
    : FrameTreeNode( index, parent, 2 ),
      id( id ),
      truncated( truncated ),
      selected( 1 ),
      ref( 1 )
{
    polygon.append( po );
}

// Setzt die Objekt-ID
void _ObjectPolygon::setId( QString id )
{
    this->id = id;
}

// Legt fest, ob das Objekt versteckt ist (falls s = 0)
void _ObjectPolygon::setSelected( bool s )
{
    this->selected = s;
}

// Entfernt alle Ecken in einer Region r. Gibt 0 zurück, fall das Objekt komplett entfernt werden soll
bool _ObjectPolygon::removeVertices( QRect r )
{
    for( auto p = polygon.begin(); p != polygon.end(); p++ )
    {
        QPolygon &pol = *p;
        int anz = pol.size();
        for( int i = 0; i < anz; i++ )
        {
            QPoint v = pol.at( i );
            if( r.contains( v ) )
            {
                pol.removeAt( i );
                i--;
                anz--;
            }
        }
    }
    int pAnz = polygon.size();
    for( int j = 0; j < pAnz; j++ )
    {
        int anz = polygon.at( j ).size();
        if( anz < 3 )
        {
            polygon.removeAt( j );
            j--;
            pAnz--;
        }
    }
    return pAnz >= 1;
}

// Verschiebt den intex-ten Vertex aus dem pIndex-ten Polygon auf Position newPos.
//  max: Die maximale Größe des Bildes. Falls newPos außerhalb des Bildes liegt, wird automatisch der nächste Punkt im Bild genommen.
void _ObjectPolygon::moveVertex( int index, QPoint newPos, QSize max, int pIndex )
{
    int pI = 0;
    for( auto p = polygon.begin(); p != polygon.end(); p++ )
    {
        QPolygon &pol = *p;
        if( pI == pIndex )
        {
            int i = 0;
            for( auto point = pol.begin(); point != pol.end(); point++, i++ )
            {
                if( i == index )
                {
                    *point = newPos;
                    if( point->x() < 0 )
                        point->setX( 0 );
                    if( point->y() < 0 )
                        point->setY( 0 );
                    if( point->x() >= max.width() )
                        point->setX( max.width() - 1 );
                    if( point->y() >= max.height() )
                        point->setY( max.height() - 1 );
                }
            }
        }
        pI++;
    }
}

// Fügt an Slette index im pIndexten Polygon den Eckpunkt v ein
void _ObjectPolygon::insertVertex( int index, QPoint v, int pIndex )
{
    int pI = 0;
    for( auto p = polygon.begin(); p != polygon.end(); p++ )
    {
        QPolygon &pol = *p;
        if( pI == pIndex )
            pol.insert( index, v );
        pI++;
    }
}

// Spaltet das pIndexte Polygon indem zwischen dem begin-ten Eckpunkt und dem end-ten Eckpunkt geschnitten wird.
//  Gibt das neu entstandene Polygon zurück (eine hälfte des alten, die aus diesem entfernt wurde)
QPolygon _ObjectPolygon::split( int begin, int end, int pIndex )
{
    int pI = 0;
    for( auto p = polygon.begin(); p != polygon.end(); p++ )
    {
        QPolygon &pol = *p;
        if( pI == pIndex )
        {
            QPolygon newP;
            int size = pol.size();
            for( int i = begin; true; i++ )
            {
                if( i >= size )
                    i = 0;
                newP.append( pol.at( i ) );
                if( i == end )
                    break;
            }
            int removeIndex = begin + 1;
            for( int i = begin + 1; true; i++ )
            {
                if( i >= size )
                {
                    i = 0;
                    removeIndex = 0;
                }
                if( i == end )
                    break;
                pol.removeAt( removeIndex );
            }
            return newP;
        }
    }
}

// Setzt den Truncated Flag
void _ObjectPolygon::setTruncated( bool truncated )
{
    this->truncated = truncated;
}

// Gibt 1 zurück, wenn das Objekt nicht Versteckt ist
bool _ObjectPolygon::isSelected() const
{
    return selected;
}

// Gibt die Bounding Box zurück
QRect _ObjectPolygon::getBoundingBox() const
{
    int minX = INT_MAX, minY = INT_MAX, maxX = 0, maxY = 0;
    for( QPolygon pol : polygon )
    {

        for( QPoint point : pol )
        {
            if( point.x() < minX )
                minX = point.x();
            if( point.y() < minY )
                minY = point.y();
            if( point.x() > maxX )
                maxX = point.x();
            if( point.y() > maxY )
                maxY = point.y();
        }
    }
    return QRect( minX, minY, maxX - minX, maxY - minY );
}

// Gibt this zurück
void *_ObjectPolygon::getNodeObject() const
{
    return (void*)this;
}

// Gibt 1 zurück, falls Truncated gesetzt wurde
bool _ObjectPolygon::isTruncated() const
{
    return truncated;
}

// Gibt die Objekt-ID zurück
QString _ObjectPolygon::getId() const
{
    return id;
}

// Gibt eine Liste mit den Polygonen zurück
QList< QPolygon > &_ObjectPolygon::getPolygonList()
{
    return polygon;
}

// Inhalt der ObjektPolygon Klasse
//---------------------------------

// Erstellt ein auf Null zeigendes ObjektPolygon
ObjectPolygon::ObjectPolygon()
{
    ptr = 0;
}

// Erzeugt ein neues Objekt Polygon, welches auf ein bestimmtes Objekt zeigt
ObjectPolygon::ObjectPolygon( _ObjectPolygon *ptr )
{
    this->ptr = ptr;
    if( this->ptr )
        this->ptr->ref++;
}

// Erzeugt ein neues Objekt Polygon mit neuem Objekt
//  id: Die Objekt ID
//  po: Das Polygon
//  truncated: 1, falls das Objekt abgeschnitten ist
//  parent: Der Elternknoten im Baum der Sequenz (das Bild zu dem das Objekt gehört)
ObjectPolygon::ObjectPolygon( QString id, QPolygon po, bool truncated, int index, FrameTreeNode *parent )
{
    ptr = new _ObjectPolygon( id, po, truncated, index, parent );
    numObjects++;
}

// Copy Constructor
ObjectPolygon::ObjectPolygon( const ObjectPolygon &op )
    : ObjectPolygon( op.ptr )
{}

ObjectPolygon::~ObjectPolygon()
{
    if( ptr && !--ptr->ref )
    {
        delete ptr;
        numObjects--;
    }
}

// Operator um auf das unterliegende _ObjectPolygon zuzugreifen
_ObjectPolygon *ObjectPolygon::operator->() const
{
    return ptr;
}

// Gibt 1 zurück, falls auf das gleiche Objekt verwiesen wird
bool ObjectPolygon::operator==( const ObjectPolygon &op ) const
{
    return ptr == op.ptr;
}

// Gibt 1 zurück, falls nicht auf das gleiche Objekt verwiesen wird
bool ObjectPolygon::operator!=( const ObjectPolygon &op ) const
{
    return ptr != op.ptr;
}

// Setzt den Zeiger auf das _ObjectPolygon Objekt
bool ObjectPolygon::operator=( const ObjectPolygon &op )
{
    if( ptr && !--ptr->ref )
    {
        delete ptr;
        numObjects--;
    }
    ptr = op.ptr;
    if( ptr )
        ptr->ref++;
}

// Gibt 1 zurück, falls der Zeiger nicht inizialisiert wurde
bool ObjectPolygon::isNull() const
{
    return ptr == 0;
}
