/*
    Peri4 Paint
    Copyright (C) 2011  Ivan Pelipenko peri4ko@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "emainwindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QLabel>


EMainWindow::EMainWindow(QWidget * parent): QMainWindow(parent), action_show_all_tools(this), action_hide_all_tools(this),
action_show_all_docks(this), action_hide_all_docks(this), first_show(true) {
	qRegisterMetaType<Qt::DockWidgetArea>("Qt::DockWidgetArea");
	action_show_all_tools.setText(trUtf8("Show all"));
	action_show_all_docks.setText(trUtf8("Show all"));
	action_hide_all_tools.setText(trUtf8("Hide all"));
	action_hide_all_docks.setText(trUtf8("Hide all"));
	action_show_all_tools.setIcon(QIcon(":/icons/layer-visible-on.png"));
	action_show_all_docks.setIcon(QIcon(":/icons/layer-visible-on.png"));
	action_hide_all_tools.setIcon(QIcon(":/icons/layer-visible-off.png"));
	action_hide_all_docks.setIcon(QIcon(":/icons/layer-visible-off.png"));
	setChanged(false);
	initMenus();
	tid = startTimer(200);
}


EMainWindow::~EMainWindow() {
	saveSession();
}


void EMainWindow::showEvent(QShowEvent * e) {
	QWidget::showEvent(e);
	initMenus();
	if (!first_show) return;
	first_show = false;
	QList<QDockWidget * > docks(findChildren<QDockWidget * >());
	foreach (QDockWidget * d, docks) {
		connect(d, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(changedDock()));
		connect(d, SIGNAL(topLevelChanged(bool)), this, SLOT(changedDock()));
	}
	changedDock();
}


void EMainWindow::closeEvent(QCloseEvent * e) {
	if (!checkSave()) e->ignore();
}


bool EMainWindow::eventFilter(QObject * o, QEvent * e) {
	//qDebug() << o << e;
	if (tbars.contains((QTabBar*)o) && e->type() == QEvent::MouseButtonDblClick) {
		int tab = ((QTabBar*)o)->tabAt(((QMouseEvent * )e)->pos());
		if (tab >= 0) {
			QDockWidget * dock = (QDockWidget * )(((QTabBar*)o)->tabData(tab).toULongLong());
			if (dock != 0) {
				dock->setFloating(true);
			}
		}
	}
	if (e->type() == QEvent::Show || e->type() == QEvent::Hide || e->type() == QEvent::ChildAdded || e->type() == QEvent::ChildRemoved || e->type() == QEvent::MouseButtonPress) {
		if (tbars.contains((QTabBar*)o) || tdocks.contains((QDockWidget*)o)) {
			if (e->type() == QEvent::MouseButtonPress) {
				if (((QMouseEvent*)e)->button() == Qt::RightButton) {
					bool popup = tbars.contains((QTabBar*)o);
					if (tdocks.contains((QDockWidget*)o))
						popup = popup || ((QDockWidget*)o)->titleBarWidget()->geometry().contains(((QMouseEvent*)e)->pos());
					if (popup) {
						createPopupMenu()->popup(((QMouseEvent*)e)->globalPos());
						return true;
					}
				}
			}
			if (e->type() == QEvent::Show || e->type() == QEvent::Hide /*|| e->type() == QEvent::ChildAdded || e->type() == QEvent::ChildRemoved*/) {
				//qDebug() << "filter";
				//QMetaObject::invokeMethod(this, "changedDock", Qt::QueuedConnection);
				changedDock();
			}
		}
	}
	return QMainWindow::eventFilter(o, e);
}


void EMainWindow::timerEvent(QTimerEvent * e) {
	if (e->timerId() == tid) {
		changedDock();
		return;
	}
	QMainWindow::timerEvent(e);
}


QMenu * EMainWindow::createPopupMenu() {
	QMenu * menuPopup = new QMenu;
	QWidgetAction * wa;
	QLabel * lbl;
	QAction * a;
	QFont f;
	f.setBold(true);
	// Toolbars
	QList<QToolBar * > tools = findChildren<QToolBar * >();
	if (!tools.isEmpty()) {
		wa = new QWidgetAction(menuPopup);
		lbl = new QLabel();
		lbl->setFrameShape(QFrame::StyledPanel);
		lbl->setFrameShadow(QFrame::Sunken);
		lbl->setText(trUtf8("Toolbars"));
		lbl->setFont(f);
		lbl->setAlignment(Qt::AlignCenter);
		wa->setDefaultWidget(lbl);
		menuPopup->addAction(wa);
		foreach (QToolBar * i, tools) {
			if (i->property("ribbon").toBool()) continue;
			a = new QAction(i->windowTitle(), menuPopup);
			a->setCheckable(true);
			a->setChecked(!i->isHidden());
			a->setIcon(i->windowIcon());
			connect(a, SIGNAL(toggled(bool)), i, SLOT(setVisible(bool)));
			menuPopup->addAction(a);
		};
		menuPopup->addSeparator();
		menuPopup->addAction(&action_show_all_tools);
		menuPopup->addAction(&action_hide_all_tools);
	}
	// Docks
	QList<QDockWidget * > docks = findChildren<QDockWidget * >();
	if (!docks.isEmpty()) {
		wa = new QWidgetAction(menuPopup);
		lbl = new QLabel();
		lbl->setFrameShape(QFrame::StyledPanel);
		lbl->setFrameShadow(QFrame::Sunken);
		lbl->setText(trUtf8("Docks"));
		lbl->setFont(f);
		lbl->setAlignment(Qt::AlignCenter);
		wa->setDefaultWidget(lbl);
		menuPopup->addAction(wa);
		foreach (QDockWidget * i, docks) {
			if (i->property("ribbon").toBool()) continue;
			a = new QAction(i->windowTitle(), menuPopup);
			a->setCheckable(true);
			a->setChecked(!i->isHidden());
			a->setIcon(i->windowIcon());
			connect(a, SIGNAL(toggled(bool)), i, SLOT(setVisible(bool)));
			menuPopup->addAction(a);
		};
		menuPopup->addSeparator();
		menuPopup->addAction(&action_show_all_docks);
		menuPopup->addAction(&action_hide_all_docks);
	}
	return menuPopup;
}


void EMainWindow::initMenus() {
	action_show_all_tools.disconnect();
	action_hide_all_tools.disconnect();
	action_show_all_docks.disconnect();
	action_hide_all_docks.disconnect();
	
	QList<QToolBar * > tools = findChildren<QToolBar * >();
	foreach (QToolBar * i, tools) {
		if (i->property("ribbon").toBool()) continue;
		i->toggleViewAction()->setIcon(i->windowIcon());
		connect(&action_show_all_tools, SIGNAL(triggered(bool)), i, SLOT(show()));
		connect(&action_hide_all_tools, SIGNAL(triggered(bool)), i, SLOT(hide()));
	}
	
	QList<QDockWidget * > docks = findChildren<QDockWidget * >();
	foreach (QDockWidget * i, docks) {
		if (i->property("ribbon").toBool()) continue;
		i->toggleViewAction()->setIcon(i->windowIcon());
		connect(&action_show_all_docks, SIGNAL(triggered(bool)), i, SLOT(show()));
		connect(&action_hide_all_docks, SIGNAL(triggered(bool)), i, SLOT(hide()));
	}
	
	QList<QAction * > actions = findChildren<QAction * >();
	foreach (QAction * i, actions)
		i->setIconVisibleInMenu(true);
	addActions(actions);
}


void EMainWindow::initSession() {
	connect(&session, SIGNAL(loading(QPIConfig & )), this, SLOT(sessionLoading(QPIConfig & )));
	connect(&session, SIGNAL(saving(QPIConfig & )), this, SLOT(sessionSaving(QPIConfig & )));
	session.addEntry("EMainWindow", this);
}


void EMainWindow::saveSession() {
	session.save();
}


void EMainWindow::loadSession() {
	session.load();
}


bool EMainWindow::checkSave() {
	if (!isWindowModified()) return true;
	return saveFile(true);
}


void EMainWindow::changedDock() {
	QList<QTabBar * > tabs(findChildren<QTabBar * >());
	QList<QDockWidget * > docks = findChildren<QDockWidget * >();
	QSet<QDockWidget * > docks_tabs;
	QDockWidget * dock;
	//qDebug() << "change";
	foreach (QTabBar * t, tabs) {
		if (!t->objectName().isEmpty() || t->isHidden()) continue;
		if (!tbars.contains(t)) {
			tbars << t;
			connect(t, SIGNAL(tabCloseRequested(int)), this, SLOT(closeDock(int)));
			t->installEventFilter(this);
			t->setIconSize(dockTabsIconSIze());
			t->setTabsClosable(true);
		}
		//qDebug() << "tab";
		for (int i = 0; i < t->count(); ++i) {
			dock = (QDockWidget * )t->tabData(i).toULongLong();
			//qDebug() << i << dock;
			if (dock == 0) continue;
			t->setTabIcon(i, dock->windowIcon());
			docks_tabs << dock;
		}
	}
	
	foreach (QDockWidget * d, docks) {
		if (d->titleBarWidget() == 0) continue;
		QWidget * ctb = d->titleBarWidget();
		if (!d->property("__titleWidget").isValid()) {
			d->setProperty("__titleWidget", qulonglong(ctb));
			QWidget * ntb = new QWidget();
			int m = style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin);
			ntb->setLayout(new QBoxLayout(QBoxLayout::BottomToTop));
			ntb->layout()->setContentsMargins(m, m, 0, 0);
			d->setProperty("__titleEmptyWidget", qulonglong(ntb));
		}
		if (!tdocks.contains(d)) {
			tdocks << d;
			//connect(t, SIGNAL((QObject*)), this, SLOT(changedDockClose(QObject*)));
			d->installEventFilter(this);
		}
		//d->titleBarWidget()->setHidden(docks_tabs.contains(d));
		if (tabifiedDockWidgets(d).isEmpty()) {
			if (d->titleBarWidget() != (QWidget * )(d->property("__titleWidget").toULongLong()))
				d->setTitleBarWidget((QWidget * )(d->property("__titleWidget").toULongLong()));
		} else {
			if (d->titleBarWidget() != (QWidget * )(d->property("__titleEmptyWidget").toULongLong())) {
				d->setTitleBarWidget((QWidget * )(d->property("__titleEmptyWidget").toULongLong()));
				d->layout()->setContentsMargins(0, 20, 0, 0);
			}
		}
	}
}


void EMainWindow::changedDockClose(QObject * bar) {
	//qDebug() << "close" << bar;
	tbars.removeAll((QTabBar * )bar);
	changedDock();
}


void EMainWindow::closeDock(int index) {
	QDockWidget * dock = (QDockWidget * )((QTabBar*)sender())->tabData(index).toULongLong();
	if (dock == 0) return;
	dock->close();
}


void EMainWindow::newFile() {
	if (!checkSave()) return;
	reset(true);
	setWindowModified(false);
}


void EMainWindow::openFile() {
	if (!checkSave()) return;
	QString ret = QFileDialog::getOpenFileName(this, trUtf8("Select file to open"), file_name, loadFilter());
	if (ret.isEmpty()) return;
	load(ret);
}


bool EMainWindow::saveFile(bool ask) {
	if (ask) {
		int ret = QMessageBox::question(this, windowTitle(), trUtf8("Save changes%1?").arg(!file_name.isEmpty() ? (trUtf8(" in") + " \"" + file_name + "\"") : ""), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save);
		if (ret == QMessageBox::Cancel) return false;
		if (ret == QMessageBox::Save) return saveFile();
		return true;
	}
	if (file_name.isEmpty()) return saveAsFile();
	save(file_name);
	return true;
}


bool EMainWindow::saveAsFile() {
	QString ret = QFileDialog::getSaveFileName(this, trUtf8("Select file to save"), file_name, saveFilter());
	if (ret.isEmpty()) return false;
	save(ret);
	return true;
}
