#include "model.h"
#include "arbeitsview.h"

Model::Model()
{}

// Fügt eine View hinzu
void Model::addView( QWidget *v )
{
    views.append( v );
}

// Aktualisiert die Views
void Model::notifyViews()
{
    for( QWidget *v : views )
        v->update();
}

// Entfernt alle Views
void Model::removeViews()
{
    views.clear();
}

// Inhalt der ArbeitsModel Klasse
//--------------------------------

ArbeitsModel::ArbeitsModel( MainWindow *w )
    : f( 0 ),
    deleteField( 0 ),
    mode( MOVE ),
    newPolygon( 0 ),
    window( w ),
    xScaleFactor( 1 ),
    yScaleFactor( 1 ),
    xOffset( 0 ),
    yOffset( 0 ),
    mousePressed( false ),
    rotation( 0 ),
    cutIndex( -1 ),
    showMask( 1 ),
    insertIndex( -1 ),
    moveIndex( -1 ),
    showColors( 0 ),
    showIds( 1 )
{}

ArbeitsModel::~ArbeitsModel()
{
    delete deleteField;
}

// Transformiert einen Punkt von Bildkoordinaten nach Bildschirmkoordinaten
QPoint ArbeitsModel::translate( QPoint p )
{
    return QPoint( (int)((p.x()-xOffset) * xScaleFactor), (int)((p.y()-yOffset) * yScaleFactor) );
}

// Transformiert ein Polygon von Bildkoordinaten nach Bildschirmkoordinaten
QPolygon ArbeitsModel::translatePolygon( QPolygon p )
{
    QPolygon result;
    for( auto point = p.begin(); point != p.end(); point++ )
        result.append( translate( *point ) );
    return result;
}

// Transformiert einen Punkt von Bildschirmkoordinaten nach Bildkoordinaten
QPoint ArbeitsModel::inverseTranslate( QPoint p )
{
    return QPoint( (int)(p.x() / xScaleFactor + xOffset), (int)(p.y() / yScaleFactor + yOffset) );
}

// Setzt das ausgewählte Frame
void ArbeitsModel::setFrame( Frame *frame )
{
    this->f = frame;
    if( f )
    {
        image = f->getImage();
        if( xScaleFactor == INFINITY || yScaleFactor == INFINITY )
            resetZoom();
    }
}

// Setzt den ausgewählten Modus
void ArbeitsModel::setMode( UserMode mode )
{
    moveObject = ObjectPolygon();
    cutObject = ObjectPolygon();
    cutIndex = 0;
    if( mode != PIPETTE_SET )
        copyedObject = ObjectPolygon();
    this->mode = mode;
    if( mode != SELECT && mode != DELETE && deleteField )
    {
        delete deleteField;
        deleteField = 0;
    }
}

// Gibt den ausgewählten Modus zurück
UserMode ArbeitsModel::getMode() const
{
    return mode;
}

// Legt fest, ob die Objekt IDs angezeigt werden sollen
void ArbeitsModel::setShowId( bool sid )
{
   showIds = sid;
}

// Gibt 1 zurück, falls die ObjektIDs angezeigt werden sollen
bool ArbeitsModel::areIdsShown() const
{
    return showIds;
}

// Legt fest, ob die Maske angezeigt werden soll
void ArbeitsModel::setShowMask( bool sm )
{
    showMask = sm;
}

// Gibt 1 zurück, wenn die Maske angezeigt werden soll
bool ArbeitsModel::isMaskShown() const
{
    return showMask;
}

// Legt fest, ob die Objekte eingefärbt werden sollen
void ArbeitsModel::setShowColors( bool sc )
{
    showColors = sc;
}

// Gibt 1 zurück, falls die Objekte eingefärbt werden sollen
bool ArbeitsModel::areColoresShown() const
{
    return showColors;
}

// Setzt das Maskenbild
void ArbeitsModel::setMask( QPixmap m )
{
    this->m = m;
}

// Gibt das Maskenbild zurück
QPixmap ArbeitsModel::getMask() const
{
    return m;
}


// Gibt das ausgewählte Bild zurück
Frame *ArbeitsModel::getFrame() const
{
    return f;
}

// Gibt das Hauptfenster zurück
MainWindow *ArbeitsModel::getWindow() const
{
    return window;
}

// Gibt das angezeigte Bild zurück
QImage ArbeitsModel::getImage() const
{
    return image;
}


// Legt fest, ob die Maus gedrück wird
void ArbeitsModel::setMousePressed( bool pressed )
{
    mousePressed = pressed;
}

// Legt die Maustaste fest
void ArbeitsModel::setMouseButtonPressed( Qt::MouseButton btn, QPoint pos )
{
    mousePressed = true;
    mouseButton = btn;
    mouseStart = pos;
    mousePos = pos;
}

// Setzt die Position der Maus fest
void ArbeitsModel::setMousePoint( QPoint mp )
{
    mousePos = mp;
}

// Gibt 1 zurück, falls die MAus gedrückt wird
bool ArbeitsModel::isMousePressed() const
{
    return mousePressed;
}

// Gibt 1 zurück, falls der angegebene Maus Knopf gedrückt wird
bool ArbeitsModel::isMouseButtonPressed( Qt::MouseButton btn ) const
{
    return mouseButton == btn && mousePressed;
}

// Gibt die Position der Maus zurück, als diese gedrückt wurde
QPoint ArbeitsModel::getMousePressPoint() const
{
    return mouseStart;
}

// Gibt die aktuelle Position der Maus zurück
QPoint ArbeitsModel::getMousePoint() const
{
    return mousePos;
}

// Setzt die Position im Bild, die links oben an der View erscheinen soll
void ArbeitsModel::setOffset( int xo, int yo )
{
    xOffset = xo;
    yOffset = yo;
}

// Setzt den Skallierungsfaktor, mit dem das Bild vergrößert werden soll
void ArbeitsModel::setScaleFactor( float xs, float ys )
{
    xScaleFactor = xs;
    yScaleFactor = ys;
}

// Setzt die Position und die Größe der View auf dem Bildschirm
void ArbeitsModel::setView( QPoint pos, QSize size )
{
    if( viewPos != pos || viewSize != size )
    {
        viewPos = pos;
        viewSize = size;
        resetZoom();
    }
}

// Gibt die Größe der View zurück
QSize ArbeitsModel::getViewSize() const
{
    return viewSize;
}

// Gibt die x Position im Bild zurück, die links an der View erscheinen soll
int ArbeitsModel::getXOffset() const
{
    return xOffset;
}

// Gibt die y Position im Bild zurück, die oben an der View erscheinen soll
int ArbeitsModel::getYOffset() const
{
    return yOffset;
}

// Gibt den Skallierungsfaktor in x Richtung zurück
float ArbeitsModel::getXScaleFactor() const
{
    return xScaleFactor;
}

// Gibt den Skallierungsfaktor in y Richtung zurück
float ArbeitsModel::getYScaleFactor() const
{
    return yScaleFactor;
}

// Gibt die Position der View zurück
QPoint ArbeitsModel::getViewPos() const
{
    return viewPos;
}

// Setzt die Skallierung zurück, so dass wieder alles sichtbar ist
void ArbeitsModel::resetZoom()
{
    QRect imgRect( QPoint( 0, 0 ), viewSize );
    QSize imgS = image.size();
    if( imgS.width() > viewSize.width() )
    {
        imgS.scale( viewSize, Qt::KeepAspectRatio );
        imgRect.setSize( imgS );
    }
    xScaleFactor = imgRect.width() / (float)image.width();
    yScaleFactor = imgRect.height() / (float)image.height();
    xOffset = 0;
    yOffset = 0;
}

// Legt fest, welches Polygon verschoben werden soll
void ArbeitsModel::setMoveObject( ObjectPolygon mo, int pIndex )
{
    moveObject = mo;
    movePolygon = pIndex;
}

// Legt fest, welcher Eckpunkt verschoben werden soll
void ArbeitsModel::setMoveIndex( int index )
{
    moveIndex = index;
}

// Legt fest, an welcher Stelle eine Eckpunkt eingefügt werden soll
void ArbeitsModel::setInsertIndex( int index )
{
    insertIndex = index;
}

// Legt die Position des neuen Eckpunktes fest
void ArbeitsModel::setNewVertex( QPoint vertex )
{
    newVertex = vertex;
}

// Gibt das Objekt zurück, welches verschoben wird
ObjectPolygon ArbeitsModel::getMoveObject() const
{
    return moveObject;
}

// Gibt den Index des Eckpunktes zurück, der verschoben wird
int ArbeitsModel::getMoveIndex() const
{
    return moveIndex;
}

// Gibt den Index des neuen Eckpunktes zurück
int ArbeitsModel::getInsertIndex() const
{
    return insertIndex;
}

// Gibt die Position des neuen Eckpunktes zurück
QPoint ArbeitsModel::getNewVertex() const
{
    return newVertex;
}

// Gibt den Index des Polygons zurück, welches verschoben wird
int ArbeitsModel::getMovePolygon() const
{
    return movePolygon;
}

// Gibt das Objekt zurück, welches zerteilt werden soll
ObjectPolygon ArbeitsModel::getCutObject() const
{
    return cutObject;
}

// Gibt den Index des Eckpunktes zurück, an dem das Objekt zerteilt werden soll
int ArbeitsModel::getCutIndex() const
{
    return cutIndex;
}

// Gibt den Index des Polygons zurück, das zerteilt werden soll
int ArbeitsModel::getCutPolygon() const
{
    return cutPolygon;
}

// Setzt das Polygon, welches zerteilt werden soll
void ArbeitsModel::setCutObject( ObjectPolygon o, int pIndex )
{
    cutObject = o;
    cutPolygon = pIndex;
}

// Setzt den Index des Eckpunktes, an dem das Polygon zerteilt werden soll
void ArbeitsModel::setCutIndex( int index )
{
    cutIndex = index;
}

// Gibt das kopierte Objekt zurück
ObjectPolygon ArbeitsModel::getCopyedObject() const
{
    return copyedObject;
}

// Gibt die Rotierung des kopierten Objektes zurück
float ArbeitsModel::getCopyedRotation() const
{
    return rotation;
}

// Gibt den Mittelpunkt des Kopierten Objektes zurück
QPoint ArbeitsModel::getCopyedCenter() const
{
    return pSCenter;
}

// Setzt das Kopierte Objekt
void ArbeitsModel::setCopyedObject( ObjectPolygon o, QPoint c )
{
    copyedObject = o;
    pSCenter = c;
}

// Setzt die Rotierung des kopierten Objektes
void ArbeitsModel::setCopyedRotation( float r )
{
    rotation = r;
}

// Gibt das neue Polygon zurück, welches mit dem NEW Werkzeug erstellt wird
QPolygon *ArbeitsModel::getNewPolygon() const
{
    return newPolygon;
}

// Setzt das neue Polygon
void ArbeitsModel::setNewPolygon( QPolygon *p )
{
    if( newPolygon )
        delete newPolygon;
    newPolygon = p;
}

// Gibt das Feld zurück, in dem ale Eckpunkte gelöscht werden sollen
QRect *ArbeitsModel::getDeleteField() const
{
    return deleteField;
}

// Setzt das Feld, in dem alle Echpunkte gelöscht werden sollen
void ArbeitsModel::setDeleteField( QRect *f )
{
    deleteField = f;
}
