#include "cddirectk.h"
#include "ui_cddirectk_type_dialog.h"
#include "cdutils_core.h"
#include "cdutils_k.h"
#include "qcd_core.h"
#include "qcd_model.h"
#include "graphic.h"
#include "piqt.h"
#include "qvariantedit.h"
#include <QFormLayout>
#include <QMimeData>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMainWindow>
#include <QDockWidget>
#include <QInputDialog>

using namespace CDUtils;


KDockWidget::KDockWidget(QString title, QMainWindow * p): QDockWidget(title, p) {
	da = p;
	menu = new QMenu(this);
	QAction * a = new QAction(QIcon(":/icons/document-edit.png"), "Rename ...", this);
	connect(a, SIGNAL(triggered(bool)), this, SLOT(rename()));
	dactions << a;
	a = new QAction(QIcon(":/icons/edit-delete.png"), "Remove", this);
	connect(a, SIGNAL(triggered(bool)), this, SIGNAL(removeRequest()));
	dactions << a;
	menu_k = new QMenu(this);
	menu_k->setTitle(tr("Remove K"));
	lay = new QFormLayout();
	lay->setContentsMargins(0, qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin), 0, 0);
	lay->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);
	QWidget * w = new QWidget();
	w->setAcceptDrops(true);
	w->installEventFilter(this);
	w->setLayout(lay);
	setWidget(w);
	type_dialog = new CDDirectKTypeDialog();
}


void KDockWidget::addK(const CDType & t, CDDirectKTypeDialog::TypeInfo ti) {
	if (t.cd_type() != CDType::cdK) return;
	PIDeque<int> xp = t.path();
	if (k_list.contains(xp)) return;
	k_list << xp;
	info_list << ti;
	//piCout << "add" << xp;
	QWidget * ve = ti.create();
	//qDebug() << "add" << ve;
	lay->addRow(PI2QString(t.pathString().join(".")) + ":", ve);
	QCDCore::instance()->bindWidget(ve, t);
	//ve->setValue();
}


QByteArray KDockWidget::save() const {
	ChunkStream cs;
	cs.add(1, windowTitle())
	  .add(2, getList(k_list))
	  .add(3, info_list);
	return cs.data();
}


void KDockWidget::load(QByteArray ba) {
	clear();
	if (ba.isEmpty()) return;
	ChunkStream cs(ba);
	PIVector<PIDeque<int> > list;
	QVector<CDDirectKTypeDialog::TypeInfo> ilist;
	while (!cs.atEnd()) {
		switch (cs.read()) {
		case 1: setWindowTitle(cs.getData<QString>()); break;
		case 2: list = setList(cs.getData<QStringList>()); break;
		case 3: ilist = cs.getData<QVector<CDDirectKTypeDialog::TypeInfo> >(); break;
		default: break;
		}
	}
	ilist.resize(list.size());
	for (int i = 0; i < list.size_s(); ++i) {
		addK(K[list[i]], ilist[i]);
	}
}


void KDockWidget::clear() {
	while (lay->rowCount() > 0)
		removeRow(0);
	k_list.clear();
	info_list.clear();
}


void KDockWidget::changedGlobal() {
	//piCout << "changedGlobal ..." << k_list.size_s() << info_list.size() << lay->count() << lay->rowCount();
	for (int i = 0; i < k_list.size_s(); ++i) {
		//piCout << "update" << i << "0";
		if (!K.exists(k_list[i])) {
			k_list.remove(i);
			info_list.remove(i);
			removeRow(i);
			--i;
			continue;
		}
		//piCout << "update" << i << "1";
		QLabel * lbl = qobject_cast<QLabel*>(lay->itemAt(i, QFormLayout::LabelRole)->widget());
		//piCout << "update" << i << "2";
		if (lbl) lbl->setText(PI2QString(K[k_list[i]].pathString().join(".")) + ":");
		//piCout << "update" << i << "3";
	}
	//piCout << "changedGlobal ok";
}


bool KDockWidget::eventFilter(QObject * o, QEvent * e) {
	//if (o == graphic->viewport()) {
		switch (e->type()) {
		case QEvent::DragMove:  {
			QDragMoveEvent * de = (QDragMoveEvent*)e;
			const QMimeData * mime = de->mimeData();
			if (!mime) break;
			if (!mime->text().startsWith("k")) break;
			de->setDropAction(Qt::CopyAction);
			de->accept();
			return true;
			} break;
		case QEvent::DragEnter: {
			QDragEnterEvent * de = (QDragEnterEvent*)e;
			const QMimeData * mime = de->mimeData();
			if (!mime) break;
			if (!mime->text().startsWith("k")) break;
			de->setDropAction(Qt::CopyAction);
			de->accept();
			return true;
			} break;
		case QEvent::Drop: {
			QDropEvent * de = (QDropEvent*)e;
			const QMimeData * mime = de->mimeData();
			if (!mime) break;
			//qDebug() << "drop" << mime->text();
			if (!mime->text().startsWith("k")) break;
			CDDirectKTypeDialog::TypeInfo ti;
			CDType & k(K[CDCore::stringToPath(Q2PIString(mime->text().mid(1)))]);
			if (k.type().left(1) == "n" || k.type().left(1) == "f") {
				if (type_dialog->exec() == QDialog::Accepted)
					ti = type_dialog->getType();
				else
					return true;
			}
			addK(k, ti);
			de->accept();
			return true;
		} break;
		default: break;
		}
	//}
	return QWidget::eventFilter(o, e);
}


void KDockWidget::contextMenuEvent(QContextMenuEvent * e) {
	qDeleteAll(menu_k->actions());
	menu_k->clear();
	for (int i = 0; i < k_list.size_s(); ++i) {
		QAction * a = new QAction(PI2QString(K[k_list[i]].pathString().join(".")), this);
		a->setData(i);
		connect(a, SIGNAL(triggered(bool)), this, SLOT(removeK()));
		menu_k->addAction(a);
	}
	QMenu * mwm = da->createPopupMenu();
	menu->clear();
	menu->addActions(dactions);
	menu->addMenu(menu_k);
	menu->addSeparator();
	menu->addActions(mwm->actions());
	menu->popup(e->globalPos());
	mwm->deleteLater();
}


void KDockWidget::removeRow(int r) {
	if (r < 0 || r >= lay->rowCount()) return;
#if QT_VERSION >= 0x050800
	QFormLayout::TakeRowResult rr = lay->takeRow(r);
	if (rr.fieldItem) {delete rr.fieldItem->widget(); delete rr.fieldItem;}
	if (rr.labelItem) {delete rr.labelItem->widget(); delete rr.labelItem;}
#else
	piForTimes (2) {
		QLayoutItem * i = lay->itemAt(r+r);
		lay->removeItem(i);
		if (i) {delete i->widget(); delete i;}
	}
#endif
}


void KDockWidget::rename() {
	QString nn = QInputDialog::getText(this, tr("Rename area"), tr("New area name:"),
									   QLineEdit::Normal, windowTitle());
	if (nn.isEmpty()) return;
	setWindowTitle(nn);
}


void KDockWidget::removeK() {
	QAction * a = qobject_cast<QAction * >(sender());
	if (!a) return;
	int ind = a->data().toInt();
	if (ind < 0 || ind >= k_list.size_s()) return;
	k_list.remove(ind);
	if (ind >= 0 && ind < info_list.size())
		info_list.remove(ind);
	removeRow(ind);
}




CDDirectK::CDDirectK(QWidget * parent) : QWidget(parent), Ui::CDDirectK() {
	setupUi(this);
	da = new QMainWindow();
	da->setWindowFlags(frame->windowFlags());
	da->setDockNestingEnabled(true);
	layoutMain->addWidget(da);
}


CDDirectK::~CDDirectK() {
}


void CDDirectK::reset() {
	qDeleteAll(docks);
	docks.clear();
}


QByteArray CDDirectK::save() const {
	ChunkStream cs;
	QVector<QByteArray> dstates;
	foreach (KDockWidget * d, docks) {
		dstates << d->save();
	}
	cs.add(1, docks.size())
	  .add(2, dstates)
	  .add(3, da->saveState());
	return cs.data();
}


void CDDirectK::load(QByteArray ba) {
	reset();
	if (ba.isEmpty()) return;
	ChunkStream cs(ba);
	while (!cs.atEnd()) {
		switch (cs.read()) {
		case 1: {
			int s = cs.getData<int>();
			piForTimes (s)
				addArea();
			} break;
		case 2: {
			QVector<QByteArray> dstates = cs.getData<QVector<QByteArray> >();
			for (int i = 0; i < piMini(dstates.size(), docks.size()); ++i)
				docks[i]->load(dstates[i]);
			} break;
		case 3: da->restoreState(cs.getData<QByteArray>()); break;
		default: break;
		}
	}
}


void CDDirectK::addArea() {
	KDockWidget * dw = new KDockWidget(QString("area %1").arg(docks.size()), da);
	connect(dw, SIGNAL(removeRequest()), this, SLOT(removeArea()));
	da->addDockWidget(Qt::RightDockWidgetArea, dw);
	docks << dw;
	for (int i = 0; i < docks.size(); ++i)
		docks[i]->setObjectName(QString("dock_%1").arg(i));
}


void CDDirectK::changedGlobal() {
	foreach (KDockWidget * d, docks)
		d->changedGlobal();
}


void CDDirectK::removeArea() {
	KDockWidget * d = qobject_cast<KDockWidget * >(sender());
	if (!d) return;
	docks.removeAll(d);
	d->deleteLater();
	for (int i = 0; i < docks.size(); ++i)
		docks[i]->setObjectName(QString("dock_%1").arg(i));
}


void CDDirectK::on_buttonAdd_clicked() {
	addArea();
}


void CDDirectK::on_buttonRemoveAll_clicked() {
	qDeleteAll(docks);
	docks.clear();
}
