#include "viewport.h"
#include "room.h"

#include <QPainter>
#include <QPaintEvent>
#include <QImage>
#include <QFile>
#include <QMenu>

#include "blkhandler.h"
#include "roommanager.h"

ViewPort::ViewPort(QWidget *parent)
	: QWidget(parent)
{
	image = NULL;
	mousex = mousey = 0;
	mode = CreateRooms;
	trackingmetasize = false;
	manager = new RoomManager;
	setMouseTracking(true);
	setFocusPolicy(Qt::ClickFocus);
}

ViewPort::~ViewPort()
{ /* noop */ }

void ViewPort::setImage(QImage *_image)
{
	if (image) delete image;
	image = new QPixmap(QPixmap::fromImage(*_image));
	setMinimumSize(image->width(), image->height());
	roomwidth = image->width();
	roomheight = image->height();
	update();
}

void ViewPort::openBLK(const QString filename)
{
	blkname = filename;
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly))
		return;
	
	BLKImageHandler handler;
	handler.setFormat("blk");
	handler.setDevice(&file);
	QImage *img = new QImage;
	handler.read(img);

	setImage(img);
}

void ViewPort::setModeCreateRooms()
{
	mode = CreateRooms;
	update();
}

void ViewPort::setModeEditRooms()
{
	mode = EditRooms;
	update();
}

void ViewPort::paintEvent(QPaintEvent * /* event */)
{
	if (image) {
		QPainter painter(this);
		// draw background
		painter.drawPixmap(QPoint(0,0), *image);

		// delegate to the RoomManager to draw the rooms
		manager->draw(&painter, mousex, mousey);

		if (mode == CreateRooms || mode == EditRooms) {
			// draw crosshair
			QPoint snappedmouse = manager->snap(mousex, mousey);
			painter.setPen(QColor(255, 0, 0, 127));
			painter.drawLine(QLine(snappedmouse.x(), 0, snappedmouse.x(), image->height()-1));
			painter.drawLine(QLine(0, snappedmouse.y(), image->width()-1, snappedmouse.y()));
		}

		unsigned int w = roomwidth, h = roomheight;
		if (trackingmetasize) {
			w = mousex;
			h = mousey;
		}
		painter.setPen(QColor(0, 255, 0, 255));
		painter.drawLine(QLine(0, 0, w, 0));
		painter.drawLine(QLine(0, 0, 0, h));
		painter.drawLine(QLine(w, 0, w, h));
		painter.drawLine(QLine(0, h, w, h));
	}
}

void ViewPort::mousePressEvent(QMouseEvent *event)
{
	if (event->button() == Qt::LeftButton &&
	    abs(event->x() - roomwidth) < 10 && abs(event->y() - roomheight) < 10) {
		trackingmetasize = true;
		update();
	}
}

void ViewPort::mouseReleaseEvent(QMouseEvent *event)
{
	if (!image) return; // don't want to add points when there's no image.
	if (trackingmetasize) {
		trackingmetasize = false;
		roomwidth = event->x();
		roomheight = event->y();
		return;
	}
	if (event->button() == Qt::LeftButton) {
		switch (mode) {
			case CreateRooms:
				manager->addpoint(event->x(), event->y());
				break;
			case EditRooms:
				manager->editpoint(event->x(), event->y());
				break;
			default:
				break;
		}
		update();
	}
}

void ViewPort::keyPressEvent(QKeyEvent *event) {
	if (event->key() == Qt::Key_Escape) {
		manager->cancel();
		update();
	}
	QWidget::keyPressEvent(event);
}

void ViewPort::mouseMoveEvent(QMouseEvent *event)
{
	mousex = event->x();
	mousey = event->y();
	if (image && abs(event->x() - roomwidth) < 10 && abs(event->y() - roomheight) < 10) {
		setCursor(Qt::SizeFDiagCursor);
	} else {
		setCursor(Qt::ArrowCursor);
	}
	update();
}

void ViewPort::contextMenuEvent(QContextMenuEvent *e)
{
	Room *r = NULL;
	if ((r = manager->roomAt(e->pos()))) {
		QMenu menu(this);

		QMenu roomtype(tr("&Type"), &menu);
		menu.addMenu(&roomtype);
		QAction *water = new QAction(tr("Water"), &roomtype);
		water->setData(0);
		connect(water, SIGNAL(triggered()), r, SLOT(changeType()));
		roomtype.addAction(water);
		QAction *air = new QAction(tr("Air"), &roomtype);
		air->setData(1);
		connect(air, SIGNAL(triggered()), r, SLOT(changeType()));
		roomtype.addAction(air);

		QAction *del = new QAction(tr("Delete"), &menu);
		del->setData(e->pos());
		connect(del, SIGNAL(triggered()), this, SLOT(deleteRoom()));
		menu.addAction(del);

		menu.exec(e->globalPos());
	}
}

void ViewPort::deleteRoom() {
	Room *victim = manager->roomAt(((QAction*)sender())->data().toPoint());
	manager->deleteRoom(victim);
}

void ViewPort::saveMap(const QString filename)
{
	if (!image) return; // XXX throw error
	QFile file(filename);
	if (!file.open(QIODevice::WriteOnly)) {
		printf("um broken? couldn't open for write.\n");
		return; // XXX throw error
	}
	QDataStream out(&file);
	out << blkname;
	out << roomwidth;
	out << roomheight;
	out << *manager;
	file.close();
}

void ViewPort::loadMap(const QString filename)
{
	QFile file(filename);
	if (!file.open(QIODevice::ReadOnly)) {
		printf("couldn't open for read.\n");
		return; // XXX error dialog plx
	}
	QDataStream in(&file);
	in >> blkname;
	openBLK(blkname);
	in >> roomwidth;
	in >> roomheight;
	in >> *manager;
	file.close();
}

void ViewPort::exportMap(const QString filename)
{
	QFile file(filename);
	if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
		printf("could not open file for writing\n");
		return; // XXX error dialog
	}
	QTextStream out(&file);

	out << "brmi " << 0 << " " << 0 << endl; // XXX needs fixing
	out << "mapd 10000 10000" << endl;
	out << "addm " << 0 << " " << 0 << " "
	    << roomwidth << " " << roomheight << " "
	    << "\"" << blkname << "\"" << endl;
	out << *manager;
	file.close();
}
