/*
 * \file ImageLabeler.h
 *
 *  Created on: Oct 4, 2011
 *      Author: Gapchich Vladislav
 */

#ifndef __IMAGELABELER_H__
#define __IMAGELABELER_H__

#include "ImageHolder.h"
#include "LineEditForm.h"
#include "OptionsForm.h"

#include <QMainWindow>
#include <QDir>

#include "ui_ImageLabeler.h"

/* forward declarations */
class QMenuBar;
class QMenu;
class QAction;
class QHBoxLayout;
class QVBoxLayout;
class QGridLayout;
class QPushButton;
class QPixmap;
class QLabel;
class QScrollArea;
class QFrame;
class QListWidget;
class QListWidgetItem;
class QButtonGroup;
class QDomDocument;
class QDomElement;
class QSettings;

//! Structure keeps path to the image and it's flags
/*
 * \see loadInfo(QString filename)
 * \see loadPascalFile(QString aFilename, QString aPath)
 *
 * Image could be labeled before so you can load all the info about it
 * using loadInfo(QString filename)
 * pas_ means it was loaded from the file with PASCAL format
 */
struct Image {
	QString image_;
	bool labeled_;
	bool pas_;
};

//! \brief Main widget which contains all GUI elements
//! and connect them with each other.
/*
 * \\see ImageHolder
 */
class ImageLabeler : public QMainWindow, public Ui::ImageLabelerGui
{
	Q_OBJECT
protected:
	/* events */
	void resizeEvent(QResizeEvent *anEvent);
	void mousePressEvent(QMouseEvent *anEvent);
	void wheelEvent(QWheelEvent *anEvent);
	void keyPressEvent(QKeyEvent *anEvent);
	void keyReleaseEvent(QKeyEvent *anEvent);
	void closeEvent(QCloseEvent *anEvent);

	bool readSettings(QSettings *aSettings);
	bool writeSettings(QSettings *aSettings);
	void getImagesFromDir(const QDir &dir);
	void showWarning(const QString &text);
	bool askForUnsavedData();
    bool askForKeepingAnnotations();
	void loadLegendFromNode(QDomElement *anElement);
	void addLabel(
		int aLabelID,
		bool isMain,
		QString aLabel
		);
	void addPoly(Polygon *poly);
	void addBBox(BoundingBox *bbox);
	void addPolyFromData(
		QString *aPolyData,
		int *labelID
		);
	void addBBoxFromData(
		QString *aBBoxData,
		int *labelID
		);
	Polygon polyFromData(
		QString *aPolyData
		);
	Polygon	polyFromListItemText(
		QString *aString,
		int *oldID
		);
    bool BBoxFromData(const QString *aBBoxData, BoundingBox &p_BBox);
	BoundingBox	BBoxFromListItemText(
		QString *aString,
		int *oldID
		);
	void addBBoxArea(
		int anID,
		BoundingBox aBBox,
		int itemID = -1
		);
	void addPolyArea(
		int aPolyID,
		Polygon aPoly,
		int itemID = -1
		);
	bool deleteArea(QListWidgetItem *anItem);
	bool toggleLabelPriority(QListWidgetItem *anItem);
	void enableTools();
	void disableTools();
	void legendToXml(QDomDocument *aDoc, QDomElement *aRoot);
	void objectsToXml(QDomDocument *aDoc, QDomElement *aRoot);
	void addImage(Image *anImage);
	bool loadInfo(QString filename);
	bool loadPascalFile(QString aFilename, QString aPath = QString());
	bool loadPascalPolys(QString aFilename);
	bool selectImage(int anImageID);
	void setLabelColor(int anID, QColor aColor);

public:
	ImageLabeler(QWidget *aParent = 0, QString aSettingsPath = QString());
	virtual ~ImageLabeler();

public slots:
	void addLabel();
	void editLabel(QListWidgetItem *anItem);
	void removeLabel();
	void removeLabel(int aLabelID);
	void setLabelID(QListWidgetItem *anItem);
	void toggleLabelPriority();

	void focusOnArea();
	void editArea();
	void deleteArea();

	void saveAllInfo();
	void saveSegmentedPicture();
	void saveLegend();
	void loadImage();
	void loadImages();
	void loadInfo();
	void loadPascalFile();
	void loadPascalPolys();
	void loadLegendFromFile();
	/*! \brief Presents the next image of the list of images.
	 * 
	 * Depending on the step the next image (default) or an arbituary next image is shown. 
	 * Example: using keyboard short cut Ctrl + LeftKey presents the next (+1) image,
	 * and keyboard short cut Ctrl + UpKey presents the fifth next (+5) image.
	 * 
	 * \param iImageStep incremental step for the next image to show (default is 1)
	 * 
	 */
	void nextImage(int iImageStep = 1);
	/*! \brief Presents the previous image of the list of images.
	 * 
	 * Depending on the step the previous image (default) or an arbituary previous image is shown.
	 * Example: using keyboard short cut Ctrl + RightKey presents the previous (-1) image,
	 * and keyboard short cut Ctrl + DownKey presents the fifth previous (-5) image.
	 * 
	 * \param iImageStep incremental step for the previous image to show (default is 1)
	 * 
	 */
	void prevImage(int iImageStep = 1);
	void setBoundingBoxTool(bool aButtonPressed);
	void setPolygonTool(bool aButtonPressed);
	void generateColors();
	void confirmSelection();
	void clearAll();
	void clearAllTool();
	void clearLabelList();
	void clearLabelColorList();
	void areaListPopupMenu(const QPoint &aPos);
	void labelListPopupMenu(const QPoint &aPos);
	void imageListPopupMenu(const QPoint &);
	void setDataFromForm(QString aData);
	void onSelectionStarted();
	void onAreaItemChange(QListWidgetItem *);
	void onAreaEdit();
	void setPureData();
	void setLabelColor();
	void viewNormal();
	void viewSegmented();
	void interruptSearch();
	void selectImage(QListWidgetItem *);
	void removeImage();
	void writeSettings();
	void readSettings();

private:

    /* popup menu */
    //! \brief popup menu for area_list_
    //! \see list_areas_
    QMenu *popup_area_list_;

    //! \see deleteArea()
    QAction *action_delete_area_;

    //! \see editArea()
    QAction *action_edit_area_;

    //! \brief popup menu for list_label_
    //! \see list_label_
    QMenu *popup_label_list_;

    //! \see toggleLabelPriority()
    QAction *action_toggle_priority_;

    //! \see setLabelColor(int anID, QColor aColor)
    QAction *action_set_color_;

    //! \see removeLabel()
    QAction *action_delete_label_;

    //! \brief popup menu for list_images_
    //! \see list_images
    QMenu *popup_images_list_;

    //! \see removeImage()
    QAction *action_remove_image_;

    //! \brief object containing current loaded image
    //! \see image_holder_
    QPixmap *image_;

    //! widget containing the image_(inherited from QLabel)
    ImageHolder *image_holder_;

    //! \brief widget for editing tags and image description
    //! \see tags_
    //! \see image_description_
    LineEditForm line_edit_form_;

    //! widget containing possible options
    OptionsForm options_form_;


	/* variables */
	//! keeps current keyboard modifier(like ctrl, shift, alt etc)
	Qt::KeyboardModifiers keyboard_modifier_;

	//! number of the main label
	int main_label_;

	//! \brief 2d array for the segmented image
	//! \see setPureData()
	int **pure_data_;

	//! \brief number of selected label in the list_label_
	//! \see list_label_
	int label_ID_;

	//! \brief number of current image in the list_images_
	//! \see list_images_
	int image_ID_;

	//! contains current image description
	QString image_description_;

	//! contains tags for the current image
	QString tags_;

	//! "root" path to the directory where all the PASCAL data is located
	QString PASCALpath_;

	//! path to the currenlty loaded image
	QString current_image_;

	//! path to the segmented image
	QString segmented_image_;

	//! \brief list of all selected and confirmed rectangular areas
	//! \see addBBox(BoundingBox *bbox)
	QList< BoundingBox * > list_bounding_box_;

	//! \brief list of all selected and confirmed polygon areas
	//! \see addPoly(Polygon *poly)
	QList< Polygon * > list_polygon_;

	//! contains the paths for all loaded images
	QList< Image > *list_images_;

	//! list of label colors
	QList< uint > list_label_colors_;

	//! \brief buffer for manual list_areas_ items editing
	//! \see onAreaItemChange(QListWidgetItem *anItem)
	QString old_area_string_;

	/* options */
	//! enables/disables automatic color generation before image segmenting
	bool auto_color_generation_;

	/* flags */
	//! \brief flag used to interrupt recursive search of the images
	//! \see interruptSearch()
	//! \see loadImages()
	//! \see getImagesFromDir(const QDir &dir)
	bool interrupt_search_;

	//! flag indicating whether there is an unsaved data or not
	bool unsaved_data_;

	//! pointer to object used to read and write application settings
	QSettings *settings_;
};

#endif /* __IMAGELABELER_H__ */

/*
 *
 */
