/*
 * ImageHolder.cpp
 *
 *  Created on: Oct 5, 2011
 *      Author: gapchich
 */

#include "ImageHolder.h"
#include "functions.h"

#include <QKeyEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QListWidgetItem>
#include <QDebug>

ImageHolder::ImageHolder(QWidget *aParent)
	: QLabel(aParent)
{
	repaint_needed_ = 0;
	tool_ = NoTool;
	state_ = StandBy;
	keyboard_modifier_ = Qt::NoModifier;

	focused_selection_ = -1;
	focused_selection_type_ = NoTool;

	list_bounding_box_ = 0;
	main_label_ = 0;
	//list_bounding_box_ = new QList< QRect >;

	scale_ = 1;

	setScaledContents(true);
}

ImageHolder::~ImageHolder()
{
	//list_bounding_box_->clear();
	//delete list_bounding_box_;
}

void
ImageHolder::paintEvent(QPaintEvent *anEvent)
{
	QLabel::paintEvent(anEvent);

	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing);
	//painter.setRenderHint(QPainter::SmoothPixmapTransform);
	QPen pen;

	if (NoTool != tool_) {
		pen.setWidth(1);
		pen.setColor(QColor(Qt::black));
		pen.setStyle(Qt::DashLine);
		painter.setPen(pen);
		switch(tool_) {
		case BoundingBoxTool:
			painter.drawRect(bounding_box_.rect);
			break;
		case PolygonTool:
			painter.drawPolygon(polygon_.poly);
			break;
		default:
			break;
		}

	}

	/* drawing bounding boxes */
	drawBoundingBoxes(&painter, &pen);
	drawPolygons(&painter, &pen);
}

void
ImageHolder::drawBoundingBoxes(
	QPainter *aPainter,
	QPen *aPen
)
{
	/* FIXME: hardcoded colors */
	if (0 == list_bounding_box_)
	{
		return;
		/* NOTREACHED */
	}

	Qt::PenStyle penStyle = Qt::SolidLine;
	int width = 1;
	/* confirmed boxes */
	for (int i = 0; i < list_bounding_box_->size(); i++) {
		int labelID = list_bounding_box_->at(i).label_ID_;

		if (labelID < list_label_color_->count())
			aPen->setColor(QColor(list_label_color_->at(labelID)));
		else
			aPen->setColor(QColor(Qt::white));

		/* checking whether labeled area is of main object or not */
		if (labelID == *main_label_)
			width = 3;
		else
			width = 1;

		if (BoundingBoxTool == focused_selection_type_ &&
			focused_selection_ == i) {
			penStyle = Qt::DotLine;
			width = 2;
		}

		aPen->setWidth(width);
		aPen->setStyle(penStyle);
		aPainter->setPen(*aPen);
		aPainter->drawRect(list_bounding_box_->at(i).rect);
		/* drawing label ids of these boxes */
		QString labelIDText =
			QString("%1").arg(labelID);
		QRect rect = list_bounding_box_->at(i).rect.normalized();

		aPainter->drawText(
			rect.left() + 5,
			rect.top() + 5,
			20,
			20,
			Qt::AlignLeft,
			labelIDText
			);
	}

}

void
ImageHolder::drawPolygons(
	QPainter *aPainter,
	QPen *aPen
)
{
	/* FIXME: hardcoded colors */
	if (0 == list_polygon_)
	{
		return;
		/* NOTREACHED */
	}

	Qt::PenStyle penStyle = Qt::SolidLine;
	int width = 1;
	/* confirmed polygons */
	for (int i = 0; i < list_polygon_->size(); i++) {
		penStyle = Qt::SolidLine;
		int labelID = list_polygon_->at(i).label_ID_;

		aPen->setColor(QColor(list_label_color_->at(labelID)));

		/* checking whether labeled area is of main object or not */
		if (labelID == *main_label_)
			width = 3;
		else
			width = 1;

		if (PolygonTool == focused_selection_type_ &&
			focused_selection_ == i) {
			penStyle = Qt::DotLine;
			width = 2;
		}


		aPen->setWidth(width);
		aPen->setStyle(penStyle);
		aPainter->setPen(*aPen);
		aPainter->drawPolygon(list_polygon_->at(i).poly);
		/* drawing label ids of these polys */
		QString labelIDText =
			QString("%1").arg(labelID);
		QRect rect = list_polygon_->at(i).poly.boundingRect();
		int x = rect.center().x();
		int y = rect.center().y();

		aPainter->drawText(
			x,
			y,
			20,
			20,
			Qt::AlignHCenter,
			labelIDText
			);
	}

}

void
ImageHolder::triggerBoundBox(
	const QPoint &aNewPos,
	const QPoint &anOldPos,
	QRect *aNewRect
	)
{
	aNewRect->setCoords(
			 anOldPos.x(),
			 anOldPos.y(),
			 aNewPos.x(),
			 aNewPos.y()
	);

	state_ = NewSelection;
	repaint_needed_ = 1;
}

void
ImageHolder::triggerPolygon(
	const QPoint &aPoint,
	QPolygon *aNewPoly
	)
{
	*aNewPoly << aPoint;

	repaint_needed_ = 1;
}

void
ImageHolder::focusOnArea(QListWidgetItem *anItem)
{
	QString text = anItem->text();

	Tool tool = NoTool;
	if (-1 != text.indexOf("BBox"))
		tool = BoundingBoxTool;
	else if (-1 != text.indexOf("Poly"))
		tool = PolygonTool;

	/* looking for a number of selected area */
	if (NoTool != tool) {
		bool ok = 0;
		focused_selection_ = getNumFromString(&text, "#", ";", &ok);

		if (!ok) {
			focused_selection_ = -1;
			focused_selection_type_ = NoTool;
			return;
			/* NOTREACHED */
		}

		switch (tool) {
		case BoundingBoxTool:
			focused_selection_type_ = BoundingBoxTool;
			break;
		case PolygonTool:
			focused_selection_type_ = PolygonTool;
			break;
		default:
			focused_selection_type_ = NoTool;
			break;
		}

	}
	update();
}

void
ImageHolder::scaleImage(
	ZoomDirection aDirection,
	double scaleFactor
)
{
	QSize size = pixmap()->size();

	/* zoomin */
	if (ZoomIn == aDirection) {
		size *= scaleFactor;
		scale_ *= scaleFactor;
	}
	/* zoomout */
	else if (ZoomOut == aDirection) {
		size /= scaleFactor;
		scale_ /= scaleFactor;
	}

	setPixmap(
		pixmap()->scaled(
			size,
			Qt::IgnoreAspectRatio,
			Qt::SmoothTransformation
			)
		);


	//resize(scaleFactor * pixmap()->size());
	//emit imageScaled();
}

void
ImageHolder::clearFocusOnArea()
{
	focused_selection_ = -1;
	focused_selection_type_ = NoTool;
}

void
ImageHolder::setTool(Tool aTool)
{
	switch(aTool) {
	case BoundingBoxTool:
		tool_ = BoundingBoxTool;
		break;
	case PolygonTool:
		tool_ = PolygonTool;
		break;
	case TaggingTool:
		tool_ = TaggingTool;
		break;
	default:
		tool_ = NoTool;
		break;
	}
}

void
ImageHolder::setBoundingBoxList(QList< BoundingBox > *aBBoxList)
{
	if (0 == aBBoxList) {
		return;
		/* NOTREACHED */
	}

	list_bounding_box_ = aBBoxList;
}

void
ImageHolder::setPolygonList(QList< Polygon > *aPolygonList)
{
	if (0 == aPolygonList) {
		return;
		/* NOTREACHED */
	}

	list_polygon_ = aPolygonList;
}

void
ImageHolder::setLabelColorList(QList< uint > *aLabelColorList)
{
	if (0 == aLabelColorList) {
		return;
		/* NOTREACHED */
	}

	list_label_color_ = aLabelColorList;
}

void
ImageHolder::setMainLabelNum(int *aNum)
{
	if (0 == aNum) {
		return;
		/* NOTREACHED */
	}

	main_label_ = aNum;
}

void
ImageHolder::clearAll()
{
	//list_bounding_box_->clear();
	bounding_box_.rect.setRect(-1, -1, 0, 0);
	//list_polygon_->clear();
	polygon_.poly.clear();
	clearFocusOnArea();
	state_ = StandBy;

	update();
}

void
ImageHolder::clearLast()
{
	switch (tool_) {
	case BoundingBoxTool:
		bounding_box_.rect.setRect(-1, -1, 0, 0);
		break;
	case PolygonTool:
		polygon_.poly.clear();
		break;
	case TaggingTool:
		break;
	default:
		break;
	}
	bounding_box_.rect.setRect(-1, -1, 0, 0);

	state_ = StandBy;
	update();
}

void
ImageHolder::confirmSelection()
{
	if (NewSelection != state_ || NoTool == tool_) {
		return;
		/* NOTREACHED */
	}

	switch (tool_) {
	case BoundingBoxTool:
		list_bounding_box_->append(bounding_box_);
		bounding_box_.rect.setRect(-1, -1, 0, 0);
		break;
	case PolygonTool:
		list_polygon_->append(polygon_);
		polygon_.poly.clear();
		break;
	default:
		tool_ = NoTool;
		break;
	}

	state_ = StandBy;
	update();
}

ImageHolder::State
ImageHolder::state()
{
	return state_;
}

ImageHolder::Tool
ImageHolder::tool()
{
	return tool_;
}

void
ImageHolder::keyPressEvent(QKeyEvent *anEvent)
{
	QLabel::keyPressEvent(anEvent);

	//keyboard_modifier_ = anEvent->modifiers();

	if (repaint_needed_) {
		update();
		repaint_needed_ = 0;
	}
}

void
ImageHolder::mouseMoveEvent(QMouseEvent *anEvent)
{
	QPoint pos = anEvent->pos();
	if (anEvent->pos().x() < 0)
		pos.setX(0);

	if (width() < anEvent->pos().x())
		pos.setX(width() - 1);

	if (anEvent->pos().y() < 0)
		pos.setY(0);


	if (height() < anEvent->pos().y())
		pos.setY(height() - 1);


	if ((anEvent->buttons() & Qt::LeftButton) &&
		BoundingBoxTool == tool_ &&
		NewSelection == state_ &&
		Qt::NoModifier == keyboard_modifier_)
	{
		triggerBoundBox(pos, prev_cursor_pos_, &(bounding_box_.rect));
	}

	if (PolygonTool == tool_ &&
		NewSelection == state_) {
		polygon_.poly.setPoint(polygon_.poly.count() - 1, pos);
		repaint_needed_ = 1;
	}

	if (repaint_needed_) {
		update();
		repaint_needed_ = 0;
	}
}

void
ImageHolder::mousePressEvent(QMouseEvent *anEvent)
{
	/* remembering coordinates of the click */
	if ((anEvent->buttons() & Qt::LeftButton) ||
		(anEvent->buttons() & Qt::RightButton))
	{
		prev_cursor_pos_ = anEvent->pos();
	}

	if (anEvent->buttons() & Qt::LeftButton) {
		/* clearing the selected area if it is not confirmed */
		if (NewSelection == state_ && BoundingBoxTool == tool_) {
			bounding_box_.rect.setRect(-1, -1, 0, 0);
			state_ = StandBy;
		}

		/* making new points for poly */
		if (PolygonTool == tool_ &&
			NewSelection == state_ &&
			Qt::NoModifier == keyboard_modifier_)
		{
			triggerPolygon(anEvent->pos(), &(polygon_.poly));
		}

		/* starting new selection by click */
		if (StandBy == state_ && NoTool != tool_) {
			state_ = NewSelection;
			emit selectionStarted();

			polygon_.poly.clear();
			if (PolygonTool == tool_) {
				polygon_.poly << prev_cursor_pos_;
			}
		}
	}

	if (repaint_needed_) {
		update();
		repaint_needed_ = 0;
	}
}

void
ImageHolder::mouseReleaseEvent(QMouseEvent *anEvent)
{
	Q_UNUSED(anEvent)
}

/*
 *
 */