#ifndef MODEL_H
#define MODEL_H

#include <QList>
#include <QWidget>
#include "sequenz.h"
#include "usermode.h"

/*
 * Eine Abstrakte Model Klasse
 */
class Model
{
private:
    QList< QWidget* > views; // Liste mit Views, welche aktualisiert werden sollen, falls sich das Model ändert

public:
    Model();

    // Fügt eine View hinzu
    void addView( QWidget *v );
    // Aktualisiert die Views
    void notifyViews();
    // Entfernt alle Views
    void removeViews();
};

class MainWindow; // aus mainwindow.h

/*
 * Enthält alle Daten, die für die Arbeitsfläche relevant sind
 */
class ArbeitsModel : public Model
{
private:

    Frame  *f; // Einen Zeiger auf das ausgewählte Bild aus der Bildsequenz
    QPixmap m; // Das Maskenbild
    QImage  image; // Das ausgewählte Bild
    bool    showIds; // 1, falls Objekt IDs angezeigt werden sollen
    bool    showMask; // 1, falls das Maskenbild angezeigt werden soll
    bool    showColors; // 1, falls die Objkte eingefärbt werden sollen
    MainWindow *window; // Einen Zeiger auf das Hauptfenster

    // delete
    QRect *deleteField; // Das gebiet, welches zum löschen ausgewählt wird

    // new
    QPolygon *newPolygon; // Das neue Polygon, welches mit dem Werkzeug New erstellt wird

    // copy
    ObjectPolygon copyedObject; // Das copierte Polygon, welches mit dem Kopieren und Einfügen Werkzeug kopiert wurde
    float  rotation; // Die Rotation des kopierten Objektes
    QPoint pSCenter; // Der Mittelpunkt des kopierten Objektes

    // Cut
    ObjectPolygon cutObject; // Das Objekt, welches zerteilt werden soll
    int cutPolygon; // Der Index des Polygons, welches zerteilt werden soll
    int cutIndex; // Der Index des Eckpunktes, an dem das Objekt zerteilt werden soll

    // Move
    ObjectPolygon moveObject; // Das Objekt, wessen Eckpunkt gerade verschoben wird
    int movePolygon; // Der Index des Polygones, dessen Eckpunkt verschoben wird
    QPoint newVertex; // Der Punkt, an dem ein neuer Vertex eingefügt werden würde
    int    insertIndex; // Der Index in dem Polygon, an dem der Eckpunkt eingefügt wird
    int    moveIndex; // Der Index des Eckpunktes, der verschoben werden soll

    // viewport Information
    QPoint viewPos; // Die Position der View auf dem Bildschirm
    QSize  viewSize; // Die Größe der View auf dem Bildschirm
    float  xScaleFactor; // Der x Skallierungsfaktor, mit dem die ansicht vergrößert wird
    float  yScaleFactor; // Der y Skallierungsfaktor, mit dem die ansicht vergrößert wird
    int    xOffset; // Die x Position im Bild, welche links oben an der View gezeichnet wird
    int    yOffset; // Die y Position im Bild, welche links oben an der View gezeichnet wird

    // controller Information
    bool mousePressed; // 1, falls eine Maustaste gedrückt wird
    Qt::MouseButton mouseButton; // Der gedrpckte Mausbutton
    UserMode mode; // Der Modus, in dem sich der Nutzer momentan befindet
    QPoint   mouseStart; // Die Startposition der Maus beim Klicken
    QPoint   mousePos; // Die momentane Mausposition

public:

    ArbeitsModel(MainWindow *w);
    ~ArbeitsModel();

    // Transformiert einen Punkt von Bildkoordinaten nach Bildschirmkoordinaten
    QPoint        translate(QPoint p);
    // Transformiert ein Polygon von Bildkoordinaten nach Bildschirmkoordinaten
    QPolygon      translatePolygon(QPolygon p);
    // Transformiert einen Punkt von Bildschirmkoordinaten nach Bildkoordinaten
    QPoint        inverseTranslate(QPoint p);
    // Setzt das ausgewählte Frame
    void          setFrame(Frame *f);
    // Setzt den ausgewählten Modus
    void          setMode(UserMode mode);
    // Gibt den ausgewählten Modus zurück
    UserMode      getMode() const;
    // Legt fest, ob die Objekt IDs angezeigt werden sollen
    void          setShowId(bool sid);
    // Gibt 1 zurück, falls die ObjektIDs angezeigt werden sollen
    bool          areIdsShown() const;
    // Legt fest, ob die Maske angezeigt werden soll
    void          setShowMask(bool sm);
    // Gibt 1 zurück, wenn die Maske angezeigt werden soll
    bool          isMaskShown() const;
    // Legt fest, ob die Objekte eingefärbt werden sollen
    void          setShowColors(bool sc);
    // Gibt 1 zurück, falls die Objekte eingefärbt werden sollen
    bool          areColoresShown() const;
    // Setzt das Maskenbild
    void          setMask(QPixmap m);
    // Gibt das Maskenbild zurück
    QPixmap       getMask() const;

    // Gibt das ausgewählte Bild zurück
    Frame*        getFrame() const;
    // Gibt das Hauptfenster zurück
    MainWindow*   getWindow() const;
    // Gibt das angezeigte Bild zurück
    QImage        getImage() const;

    // Legt fest, ob die Maus gedrück wird
    void          setMousePressed(bool pressed);
    // Legt die Maustaste fest
    void          setMouseButtonPressed(Qt::MouseButton btn,
                                        QPoint          pos);
    // Setzt die Position der Maus fest
    void          setMousePoint(QPoint mp);
    // Gibt 1 zurück, falls die MAus gedrückt wird
    bool          isMousePressed() const;
    // Gibt 1 zurück, falls der angegebene Maus Knopf gedrückt wird
    bool          isMouseButtonPressed(Qt::MouseButton btn) const;
    // Gibt die Position der Maus zurück, als diese gedrückt wurde
    QPoint        getMousePressPoint() const;
    // Gibt die aktuelle Position der Maus zurück
    QPoint        getMousePoint() const;

    // Setzt die Position im Bild, die links oben an der View erscheinen soll
    void          setOffset(int xo,
                            int yo);
    // Setzt den Skallierungsfaktor, mit dem das Bild vergrößert werden soll
    void          setScaleFactor(float xs,
                                 float ys);
    // Setzt die Position und die Größe der View auf dem Bildschirm
    void          setView(QPoint pos,
                          QSize  size);
    // Gibt die Größe der View zurück
    QSize         getViewSize() const;
    // Gibt die x Position im Bild zurück, die links an der View erscheinen soll
    int           getXOffset() const;
    // Gibt die y Position im Bild zurück, die oben an der View erscheinen soll
    int           getYOffset() const;
    // Gibt den Skallierungsfaktor in x Richtung zurück
    float         getXScaleFactor() const;
    // Gibt den Skallierungsfaktor in y Richtung zurück
    float         getYScaleFactor() const;
    // Gibt die Position der View zurück
    QPoint        getViewPos() const;
    // Setzt die Skallierung zurück, so dass wieder alles sichtbar ist
    void          resetZoom();

    // Legt fest, welches Polygon verschoben werden soll
    void          setMoveObject(ObjectPolygon mo,
                                int           pIndex);
    // Legt fest, welcher Eckpunkt verschoben werden soll
    void          setMoveIndex(int index);
    // Legt fest, an welcher Stelle eine Eckpunkt eingefügt werden soll
    void          setInsertIndex(int index);
    // Legt die Position des neuen Eckpunktes fest
    void          setNewVertex(QPoint vertex);
    // Gibt das Objekt zurück, welches verschoben wird
    ObjectPolygon getMoveObject() const;
    // Gibt den Index des Eckpunktes zurück, der verschoben wird
    int           getMoveIndex() const;
    // Gibt den Index des neuen Eckpunktes zurück
    int           getInsertIndex() const;
    // Gibt die Position des neuen Eckpunktes zurück
    QPoint        getNewVertex() const;
    // Gibt den Index des Polygons zurück, welches verschoben wird
    int           getMovePolygon() const;

    // Gibt das Objekt zurück, welches zerteilt werden soll
    ObjectPolygon getCutObject() const;
    // Gibt den Index des Eckpunktes zurück, an dem das Objekt zerteilt werden soll
    int           getCutIndex() const;
    // Gibt den Index des Polygons zurück, das zerteilt werden soll
    int           getCutPolygon() const;
    // Setzt das Polygon, welches zerteilt werden soll
    void          setCutObject(ObjectPolygon o,
                               int           pIndex);
    // Setzt den Index des Eckpunktes, an dem das Polygon zerteilt werden soll
    void          setCutIndex(int index);

    // Gibt das kopierte Objekt zurück
    ObjectPolygon getCopyedObject() const;
    // Gibt die Rotierung des kopierten Objektes zurück
    float         getCopyedRotation() const;
    // Gibt den Mittelpunkt des Kopierten Objektes zurück
    QPoint        getCopyedCenter() const;
    // Setzt das Kopierte Objekt
    void          setCopyedObject(ObjectPolygon o,
                                  QPoint        c);
    // Setzt die Rotierung des kopierten Objektes
    void          setCopyedRotation(float r);

    // Gibt das neue Polygon zurück, welches mit dem NEW Werkzeug erstellt wird
    QPolygon*     getNewPolygon() const;
    // Setzt das neue Polygon
    void          setNewPolygon(QPolygon *p);

    // Gibt das Feld zurück, in dem ale Eckpunkte gelöscht werden sollen
    QRect*        getDeleteField() const;
    // Setzt das Feld, in dem alle Echpunkte gelöscht werden sollen
    void          setDeleteField(QRect *f);
};

#endif // MODEL_H