#ifndef FRAME_H
#define FRAME_H

#include <QString>
#include <QPolygon>
#include "object.h"
#include "mask.h"
#include "frametree.h"
#include "opencv2/opencv.hpp"

class Kamera;

/*
 * Verwaltet ein Bild einer Sequenz
 */
class Frame : public FrameTreeNode
{
private:

    QString path; // Der Pfad zum Bild
    QList<ObjectPolygon> objects; // Eine Liste mit Annotierten Objekten
    QString timestamp; // Der Zeitpunkt, zu dem das Bild aufgenommen wurde
    QSize   size; // Die Größe des Bildes
    bool    needAnnotation; // 1, falls das Bild noch nicht vom Nutzer annotiert wurde
    bool    needSave; // 1, falls die Annotationen auf dem Bild seit dem letzten Speichern verändert wurden

public:

    // Erstellt das Bild
    //  imgPath: Der Pfad zu dem Quellbild
    //  timestamp: Der Zeitpunkt der Aufnahme des Bildes
    //  index: Der Index des Bildes in der Liste aller Bilder der Kamera
    //  kam: Die Kamera, die das Bild aufgenommen hat
    //  needAnnotation: true, falls das Bild noch nicht annotiert wurde
    Frame(QString imgPath,
          QString timestamp,
          int     index,
          Kamera *kam,
          bool    needAnnotation);
    ~Frame();

    // Gibt this zurück
    void* getNodeObject() const override;

    // Gibt die Anzahl aller Objekte auf dem Bild zurück
    int   getChildCount() const override;

    // Entfernt alle Eckpunkte in einem Gebit
    //  area: Das Gebiet, in dem die Eckpunkte gelöscht werden sollen
    void removeSelectedVertices(QRect area);

    // Löscht ein bestimmtes Objekt
    //  o: Das Objekt, welches gelöscht werden soll
    void removeObject(ObjectPolygon o);

    // Fügt ein Objekt zu dem Bild hinzu. Das Objekt wird automatisch am
    // Bildrand abgeschnitten
    //  name: Die ID des Objektes
    //  truncated: true, falls das Objekt abgeschnitten ist
    //  po: Eine Liste mit Polygonen, welche die Umrisse des Objektes sind
    void addObject(QString        name,
                   bool           truncated,
                   QList<QPolygon>po);

    // Wendet die Maske auf das Bild an und löscht alle Objekte, welche sich in
    // verbotenen Bereichen befinden
    //  m: die Maske
    void applyMask(Mask& m);

    // Spaltet ein Objekt in zwei Teile
    //  object: Das Objekt welches zerteilt werden soll
    //  beginn: Der Index des Start Eckpunktes
    //  end: Der Index des End Eckpunktes
    //  pIndex: Der Index des Polygons, welches zerteilt werden soll
    void splitObject(ObjectPolygon object,
                     int            begin,
                     int            end,
                     int            pIndex);

    // gibt den Namen des Bildes zurück
    QString                 getName() const;

    // Gibt den Aufnahmezeitpunkt des Bildes zurück
    QString                 getTimestamp() const;

    // Gibt eine Liste mit Objekten zurück, welche sich auf dem Bild befinden
    QList<ObjectPolygon>& getObjects();

    // Setzt die Objekte, welche sich auf dem Bild befinden. Alle vorherigen
    // Objekte werden entfernt.
    //  objects: die Liste mit den neuen Objekten
    void    setObjects(std::vector<std::vector<cv::Point> >objects);

    // Gibt das geladene Bild als Objekt des Qt Frameworks zurück
    QImage  getImage();

    // Gibt das geladene Bild als Objekt der OpenCV Bibliotek zurück
    cv::Mat getImageMatrix() const;

    // Gibt den Bildausschnitt zurück, auf dem ein Objekt komplett sichtbar ist
    //  objectId: die ID des Objektes, welches auf dem Bild sein soll
    QImage getObjectImage(QString objectId);

    // Gibt den Bildausschnitt zurück, auf dem ein Objekt komplett sichtbar ist
    //  object: das Objekt, welches auf dem Bild sein soll
    QImage getObjectImage(ObjectPolygon object);

    // Prüft ob ein Objekt auf dem Bild vorhanden ist
    //  id: Die ID des Objektes
    bool hasObject(QString id);

    // Gibt true zurück, falls kein Fehler in der Annotation des Bildes gefunden
    // wurde
    bool isCorrectAnnotated() const;

    // Gibt true zurück, falls das Bild noch nicht annotiert wurde
    bool isNotAnnotated() const;

    // Gibt das Objekt zurück, welches an einer bestimmten Position im Bild ist.
    //  0 falls an der Stelle kein Objekt ist
    //  pos: die Position, an der ein Objekt gesucht werden soll
    //  pIndex: wird auf den Index des Polygons gesetzt, welches an der Stelle
    // ist, falls dort ein Objekt existiert
    ObjectPolygon getObjectAt(QPoint pos,
                               int  & pIndex) const;

    // Setzt das Objekt an einer bestimmten Position im Bild.
    // Fals an der Position bereits ein Objekt existiert, so wird nur die Objekt
    // ID gesetzt.
    //  pos: die Position
    //  object: Das neue Objekt
    //  center: Der Mittelpunkt des neuen Objektes
    //  rotation: Die Drehung des neuen Objektes um den Mittelpunkt
    void setObjectAt(QPoint pos,
                     ObjectPolygon object,
                     QPoint center = QPoint(0, 0),
                     float rotation = 0);

    // Macht ein Objekt an einer bestimmten Stelle sichtbar oder unsichtbar
    //  pos: Die Position
    void selectObjectAt(QPoint pos);

    // Schneidet ein Polygon am rand des Bildes ab und gibt das Ergebnis zurück
    //  uncliped: Das nicht abgeschnittene Polygon
    QPolygon clipPolygon(QPolygon uncliped) const;

    // Vereiniegt verschiedene Objekte mit der gleichen Objekt ID zu einem
    //  id: Die ID, deren Objekte vereiniegt werden sollen
    void connectObjects(QString id);

    // Zerteilt ein Objekt, welches aus mehreren Polygonen besteht
    //  o: Das Objekt welches zerteilt werden soll
    void disconnectObject( ObjectPolygon o );
    // Gibt 1 zurück, falls die Annotation zu dem Bild gespeichert werden muss
    // und setzt den Flag auf 0, so dass erst nach einer änderung wieder 1 zurückgegeben wird
    bool wasChangedSinceLastSave();
};

#endif // FRAME_H
