/*
 * Cueplot: a GUI front-end to gnuplot
 * Copyright (C) 2007, 2008 Muneyuki Noguchi
 *
 * 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 2
 * 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, write to the Free Software Foundation, 
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include "MainWindow.h"
#include "ConfigDialog.h"
#include "FitDialog.h"
#include "OptionDialog.h"
#include "PlotDataWidget.h"
#include "PlotInputWidget.h"
#include "Process.h"
#include "RawCommandDialog.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QSettings>
#include <QtGui/QCloseEvent>
#include <QtGui/QFileDialog>
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
#include <QtGui/QMessageBox>
#include <QtGui/QStatusBar>
#include <QtGui/QStyle>
#include <QtGui/QToolBar>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWhatsThis>

#include <cstring> // strcmp()

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), process(new Process)
{
	setWindowTitle(QCoreApplication::applicationName());

	plotInputWidget = new PlotInputWidget;
	plotDataWidget = new PlotDataWidget;
	connect(plotInputWidget, SIGNAL(inputChanged(bool)),
			plotDataWidget, SLOT(setAdditionEnabled(bool)));
	connect(plotInputWidget, SIGNAL(dataAdded(const Plot &)),
			plotDataWidget, SLOT(addData(const Plot &)));
	connect(plotDataWidget, SIGNAL(dataAdded()),
			plotInputWidget, SLOT(addData()));
	connect(plotDataWidget, SIGNAL(executed(const QString &)),
			process, SLOT(execute(const QString &)));

	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(plotInputWidget);
	mainLayout->addWidget(plotDataWidget);

	QWidget *mainWidget = new QWidget;
	mainWidget->setLayout(mainLayout);
	setCentralWidget(mainWidget);

	createActions();
	createMenus();
	createToolBars();

	readSettings();
}

void MainWindow::createActions()
{
	loadAct = new QAction(tr("&Open..."), this);
#if QT_VERSION >= 0x040200
	loadAct->setShortcut(QKeySequence::Open);
#else
	loadAct->setShortcut(tr("Ctrl+O"));
#endif
	loadAct->setStatusTip(tr("load '<input-file>'"));
	loadAct->setWhatsThis(tr("load '&lt;input-file&gt;'"));
	loadAct->setIcon(QIcon(":/images/fileopen.png"));
	connect(loadAct, SIGNAL(triggered()),
			this, SLOT(load()));

	saveAct = new QAction(tr("&Save"), this);
#if QT_VERSION >= 0x040200
	saveAct->setShortcut(QKeySequence::Save);
#else
	saveAct->setShortcut(tr("Ctrl+S"));
#endif
	saveAct->setStatusTip(tr("save '<filename>'"));
	saveAct->setWhatsThis(tr("save '&lt;filename&gt;'"));
	saveAct->setIcon(QIcon(":/images/filesave.png"));
	connect(saveAct, SIGNAL(triggered()),
			this, SLOT(save()));

	saveAsAct = new QAction(tr("Save &As..."), this);
	saveAsAct->setStatusTip(tr("save '<filename>'"));
	saveAsAct->setWhatsThis(tr("save '&lt;filename&gt;'"));
	saveAsAct->setIcon(QIcon(":/images/filesaveas.png"));
	connect(saveAsAct, SIGNAL(triggered()),
			this, SLOT(saveAs()));

	quitAct = new QAction(tr("&Quit"), this);
	quitAct->setShortcut(tr("Ctrl+Q"));
	quitAct->setStatusTip("quit");
	quitAct->setWhatsThis("quit");
	quitAct->setIcon(QIcon(":/images/exit.png"));
#if QT_VERSION >= 0x040200 && defined(Q_OS_DARWIN)
	// Mac OS X 環境で、使用言語によってメニューの場所が変わるのを防ぐ
	quitAct->setMenuRole(QAction::QuitRole);
#endif
	connect(quitAct, SIGNAL(triggered()),
			this, SLOT(close()));


	plotAct = new QAction(tr("&2D Plot"), this);
	plotAct->setShortcut(tr("F2"));
	plotAct->setStatusTip("plot");
	plotAct->setWhatsThis("plot");
	plotAct->setEnabled(false);
	connect(plotAct, SIGNAL(triggered()),
			this, SLOT(plot()));
	connect(plotDataWidget, SIGNAL(setPlotEnabled(bool)),
			plotAct, SLOT(setEnabled(bool)));

	splotAct = new QAction(tr("&3D Plot"), this);
	splotAct->setShortcut(tr("F3"));
	splotAct->setStatusTip("splot");
	splotAct->setWhatsThis("splot");
	splotAct->setEnabled(false);
	connect(splotAct, SIGNAL(triggered()),
			this, SLOT(splot()));
	connect(plotDataWidget, SIGNAL(setPlotEnabled(bool)),
			splotAct, SLOT(setEnabled(bool)));

	rawCommandAct = new QAction(tr("&Raw Commands..."), this);
	rawCommandAct->setIcon(QIcon(":/images/run.png"));
	connect(rawCommandAct, SIGNAL(triggered()),
			this, SLOT(rawCommand()));

	fitAct = new QAction(tr("&Fittings..."), this);
	fitAct->setStatusTip("fit");
	fitAct->setWhatsThis("fit");
	connect(fitAct, SIGNAL(triggered()),
			this, SLOT(fit()));

	setAct = new QAction(tr("&Options..."), this);
	setAct->setStatusTip("set");
	setAct->setWhatsThis("set");
#if QT_VERSION >= 0x040200 && defined(Q_OS_DARWIN)
	setAct->setMenuRole(QAction::NoRole);
#endif
	connect(setAct, SIGNAL(triggered()),
			this, SLOT(set()));


	toolBarAct = new QAction(tr("&Tool Bar"), this);
	toolBarAct->setCheckable(true);

	statusBarAct = new QAction(tr("&Status Bar"), this);
	statusBarAct->setCheckable(true);
	connect(statusBarAct, SIGNAL(toggled(bool)),
			statusBar(), SLOT(setVisible(bool)));

	consoleAct = new QAction(tr("C&onsole..."), this);
	consoleAct->setCheckable(true);
	connect(consoleAct, SIGNAL(toggled(bool)),
			this, SLOT(console(bool)));

	configAct = new QAction(tr("&Configure %1...")
			.arg(QCoreApplication::applicationName()), this);
#if QT_VERSION >= 0x040200 && defined(Q_OS_DARWIN)
	configAct->setMenuRole(QAction::PreferencesRole);
#endif
	configAct->setIcon(QIcon(":/images/configure.png"));
	connect(configAct, SIGNAL(triggered()),
			this, SLOT(config()));

	whatsThisAct = new QAction(tr("What's &This?"), this);
#if QT_VERSION >= 0x040200
	whatsThisAct->setShortcut(QKeySequence::WhatsThis);
#else
	whatsThisAct->setShortcut(tr("Shift+F1"));
#endif
	whatsThisAct->setIcon(QIcon(":/images/contexthelp.png"));
	connect(whatsThisAct, SIGNAL(triggered()),
			this, SLOT(whatsThis()));

	aboutAct = new QAction(tr("&About"), this);
#if QT_VERSION >= 0x040200 && defined(Q_OS_DARWIN)
	aboutAct->setMenuRole(QAction::AboutRole);
#endif
	connect(aboutAct, SIGNAL(triggered()),
			this, SLOT(about()));

	aboutQtAct = new QAction(tr("About &Qt"), this);
#if QT_VERSION >= 0x040200 && defined(Q_OS_DARWIN)
	aboutQtAct->setMenuRole(QAction::AboutQtRole);
#endif
	connect(aboutQtAct, SIGNAL(triggered()),
			QCoreApplication::instance(), SLOT(aboutQt()));
}

void MainWindow::createMenus()
{
	const char *name = style()->metaObject()->className();
	if (!std::strcmp(name, "QCleanlooksStyle")) {
		createCleanlooksMenus();
	} else if (!std::strcmp(name, "QMacStyle")) {
		createMacMenus();
	} else if (!std::strcmp(name, "QPlastiqueStyle")) {
		createPlastiqueMenus();
	} else if (!std::strcmp(name, "QWindowsStyle") 
			|| !std::strcmp(name, "QWindowsXPStyle")
			|| !std::strcmp(name, "QWindowsVistaStyle")){
		createWindowsMenus();
	} else {
		// CDE and Motif
		createPlastiqueMenus();
	}
}

void MainWindow::createCleanlooksMenus()
{
	QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(loadAct);
	fileMenu->addSeparator();
	fileMenu->addAction(saveAct);
	fileMenu->addAction(saveAsAct);
	fileMenu->addSeparator();
	fileMenu->addAction(quitAct);

	QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
	editMenu->addAction(configAct);

	QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
	viewMenu->addAction(toolBarAct);
	viewMenu->addAction(statusBarAct);
	viewMenu->addAction(consoleAct);
	connect(viewMenu, SIGNAL(aboutToShow()),
			this, SLOT(setSettingsAction()));

	QMenu *commandMenu = menuBar()->addMenu(tr("&Command"));
	commandMenu->addAction(plotAct);
	commandMenu->addAction(splotAct);
	commandMenu->addAction(rawCommandAct);
	commandMenu->addAction(fitAct);
	commandMenu->addAction(setAct);

	QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
	helpMenu->addAction(whatsThisAct);
	helpMenu->addSeparator();
	helpMenu->addAction(aboutAct);
	helpMenu->addAction(aboutQtAct);
}

void MainWindow::createMacMenus()
{
	QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(loadAct);
	fileMenu->addSeparator();
	fileMenu->addAction(saveAct);
	fileMenu->addAction(saveAsAct);
	fileMenu->addSeparator();
	fileMenu->addAction(quitAct);

	QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
	viewMenu->addAction(toolBarAct);
	viewMenu->addAction(statusBarAct);
	viewMenu->addAction(consoleAct);
	// QAction::MenuRole 参照
	viewMenu->addAction(configAct);
	connect(viewMenu, SIGNAL(aboutToShow()),
			this, SLOT(setSettingsAction()));

	QMenu *commandMenu = menuBar()->addMenu(tr("&Command"));
	commandMenu->addAction(plotAct);
	commandMenu->addAction(splotAct);
	commandMenu->addAction(rawCommandAct);
	commandMenu->addAction(fitAct);
	commandMenu->addAction(setAct);

	QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
	helpMenu->addAction(whatsThisAct);
	// QAction::MenuRole 参照
	helpMenu->addAction(aboutAct);
	// QAction::MenuRole 参照
	helpMenu->addAction(aboutQtAct);
}

void MainWindow::createPlastiqueMenus()
{
	QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(loadAct);
	fileMenu->addSeparator();
	fileMenu->addAction(saveAct);
	fileMenu->addAction(saveAsAct);
	fileMenu->addSeparator();
	fileMenu->addAction(quitAct);

	QMenu *commandMenu = menuBar()->addMenu(tr("&Command"));
	commandMenu->addAction(plotAct);
	commandMenu->addAction(splotAct);
	commandMenu->addAction(rawCommandAct);
	commandMenu->addAction(fitAct);
	commandMenu->addAction(setAct);

	QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
	settingsMenu->addAction(toolBarAct);
	settingsMenu->addAction(statusBarAct);
	settingsMenu->addAction(consoleAct);
	settingsMenu->addSeparator();
	settingsMenu->addAction(configAct);
	connect(settingsMenu, SIGNAL(aboutToShow()),
			this, SLOT(setSettingsAction()));

	QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
	helpMenu->addAction(whatsThisAct);
	helpMenu->addSeparator();
	helpMenu->addAction(aboutAct);
	helpMenu->addAction(aboutQtAct);
}

void MainWindow::createWindowsMenus()
{
	QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(loadAct);
	fileMenu->addSeparator();
	fileMenu->addAction(saveAct);
	fileMenu->addAction(saveAsAct);
	fileMenu->addSeparator();
	fileMenu->addAction(quitAct);

	QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
	viewMenu->addAction(toolBarAct);
	viewMenu->addAction(statusBarAct);
	viewMenu->addAction(consoleAct);
	connect(viewMenu, SIGNAL(aboutToShow()),
			this, SLOT(setSettingsAction()));

	QMenu *commandMenu = menuBar()->addMenu(tr("&Command"));
	commandMenu->addAction(plotAct);
	commandMenu->addAction(splotAct);
	commandMenu->addAction(rawCommandAct);
	commandMenu->addAction(fitAct);
	commandMenu->addAction(setAct);

	QMenu *toolMenu = menuBar()->addMenu(tr("&Tool"));
	toolMenu->addAction(configAct);

	QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
	helpMenu->addAction(whatsThisAct);
	helpMenu->addSeparator();
	helpMenu->addAction(aboutAct);
	helpMenu->addAction(aboutQtAct);
}

void MainWindow::createToolBars()
{
	toolBar = addToolBar(tr("Tool Bar"));
	toolBar->addAction(loadAct);
	toolBar->addAction(saveAct);
	toolBar->addAction(plotAct);
	toolBar->addAction(splotAct);
	connect(toolBarAct, SIGNAL(toggled(bool)),
			toolBar, SLOT(setVisible(bool)));
}

void MainWindow::plot()
{
	process->execute("plot " + plotDataWidget->commandList().join(", "));
}

// TODO use Splot object
void MainWindow::splot()
{
	process->execute("splot " + plotDataWidget->commandList().join(", "));
}

void MainWindow::save()
{
	if (currentFile.isEmpty()) {
		saveAs();
	} else {
		process->execute("save '" + currentFile + "'");
	}
}

void MainWindow::saveAs()
{
	QString file = QFileDialog::getSaveFileName(this,
			tr("Save under a file name") + " - " 
			+ QCoreApplication::applicationName(),
			currentFile); 
	if (!file.isNull()) {
		process->execute("save '" + file + "'");
		currentFile = file;
	}
}

void MainWindow::load()
{
	QString file = QFileDialog::getOpenFileName(this,
			tr("Open a file") + " - " + QCoreApplication::applicationName(),
			currentFile); 
	if (!file.isNull()) {
		process->execute("load '" + file + "'");
		currentFile = file;
	}
}

void MainWindow::rawCommand()
{
	RawCommandDialog *rawCommandDialog = &RawCommandDialog::instance();
	rawCommandDialog->disconnect();
	connect(rawCommandDialog, SIGNAL(executed(const QString &)),
			process, SLOT(execute(const QString &)));
	rawCommandDialog->show();
	rawCommandDialog->raise();
	rawCommandDialog->activateWindow();
}

void MainWindow::fit()
{
	FitDialog *fitDialog  = &FitDialog::instance();
	fitDialog->disconnect();
	connect(fitDialog, SIGNAL(executed(const QString &)),
			process, SLOT(execute(const QString &)));
	fitDialog->show();
	fitDialog->raise();
	fitDialog->activateWindow();
}

void MainWindow::set()
{
	OptionDialog *optionDialog = &OptionDialog::instance();
	optionDialog->disconnect();
	connect(optionDialog, SIGNAL(executed(const QString &)),
			process, SLOT(execute(const QString &)));
	optionDialog->show();
	optionDialog->raise();
	optionDialog->activateWindow();
}

void MainWindow::setSettingsAction()
{
	toolBarAct->setChecked(toolBar->isVisible());
	statusBarAct->setChecked(statusBar()->isVisible());
	consoleAct->setChecked(process->isDialogVisible());
}

void MainWindow::console(bool visible)
{
	process->setDialogVisible(visible);
}

void MainWindow::config()
{
	ConfigDialog *configDialog = &ConfigDialog::instance(this);
	configDialog->setProcess(*process);
	configDialog->show();
	configDialog->raise();
	configDialog->activateWindow();
}

void MainWindow::whatsThis()
{
	QWhatsThis::enterWhatsThisMode();
}

void MainWindow::about()
{
	QMessageBox::about(this, tr("About %1")
			.arg(QCoreApplication::applicationName()), 
			"<h3>" + QCoreApplication::applicationName() + " 0.0.6</h3>"
			"<p>" + QCoreApplication::applicationName() 
			+ tr(": a GUI front-end to gnuplot<br>"
				"Copyright (C) 2007, 2008 Muneyuki Noguchi</p>"
				"<p>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 2 "
				"of the License, or (at your option) any later version.</p>"
				"<p>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.</p>"
				"<p>You should have received a copy of the GNU General Public License "
				"along with this program; if not, write to the Free Software "
				"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p>"));
}

void MainWindow::readSettings()
{
	QSettings settings;
	settings.beginGroup("MainWindow");

	QVariant var = settings.value("toolbar");
	toolBar->setVisible(var.canConvert(QVariant::Bool) ? var.toBool() : true);

	var = settings.value("statusbar");
	statusBar()->setVisible(
			var.canConvert(QVariant::Bool) ? var.toBool() : false);

	settings.endGroup();
}

void MainWindow::writeSettings()
{
	QSettings settings;
	settings.beginGroup("MainWindow");
	settings.setValue("toolbar", toolBar->isVisible());
	settings.setValue("statusbar", statusBar()->isVisible());
	settings.endGroup();
}

void MainWindow::closeEvent(QCloseEvent *event)
{
	// 一つでも項目がリスト中にあれば、終了させるか確認ダイアログを表示
	if (plotDataWidget->hasItem()) {
		switch (QMessageBox::warning(this, tr("Confirmation") + " - "
					+ QCoreApplication::applicationName(),
					tr("Function(s) and/or data exist in the list.\n"
						"Are you sure you want to quit?"),
					tr("&Quit"), tr("&Cancel"), 0, 0, 1)) {
		case 1:
			event->ignore();
			return;
		}
	}
	writeSettings();
	// すべてのダイアログを閉じる
	ConfigDialog::destroyInstance();
	FitDialog::destroyInstance();
	OptionDialog::destroyInstance();
	RawCommandDialog::destroyInstance();
	process->closeDialog();
	plotDataWidget->closeDialog();
	event->accept();
}
