/***************************************************************************
*   Copyright (C) 2006-2008 by Ian Reinhart Geiser                        *
*   geiseri@yahoo.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 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.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/
#include "mainwindow.h"
#include "block.h"
#include "mindmap.h"
#include "blockpropertymodel.h"
#include "asciiexportdialog.h"
#include "docbookexportdialog.h"
#include "wikiexport.h"
#include "pdfslidereporter.h"
#include "slideproperties.h"
#include "emblemselector.h"
#include "helpdialog.h"
#include "floparserobserver.h"
#include "parser.h"
#include "wikilexer.h"
#include "startupscreen.h"
#include "basicpropertyeditor.h"

#include <QDir>
#include <QGraphicsScene>
#include <QDockWidget>
#include <QUndoView>
#include <QTreeView>
#include <QDataWidgetMapper>
#include <QPrinter>
#include <QPrintDialog>
#include <QFileDialog>
#include <QImageWriter>
#include <QCloseEvent>
#include <QMessageBox>
#include <QTimer>
#include <QDesktopWidget>
#include <QSettings>
#include <QLibrary>
#include <QPictureIO>
#include <QSlider>
#include <QSpinBox>
#include <QDomDocument>

#include <qdebug.h>

const QString windowTitleTemplate = "Flo - (%1)[*]";

MainWindow::MainWindow(QWidget *parent)
	:QMainWindow(parent)
{
	m_ui.setupUi(this);
#ifdef Q_OS_WIN32
	m_ui.blockToolBar->setIconSize ( QSize(16,16) );
	m_ui.toolBar->setIconSize ( QSize(16,16) );
	m_ui.blockToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
#endif

	m_file = new MindMap(this);

	m_ui.graphicsView->setScene(m_file->scene());
	m_ui.graphicsView->setMindmap(m_file);

	m_ui.menuEdit->insertAction( m_ui.actionCut, m_file->undoAction());
	m_ui.menuEdit->insertAction( m_ui.actionCut, m_file->redoAction());
	m_ui.menuEdit->insertSeparator( m_ui.actionCut );
	m_ui.menuFile->insertMenu( m_ui.actionSave, m_file->recentFileMenu( ) );
#if QT_VERSION < 0x040300
	m_ui.actionExportDocbook->setEnabled(false);
#endif
	setupDocks();
	setupModel();
	setupMainwindow();

	connect( m_ui.graphicsView, SIGNAL( reparentBlocks(Block*,Block*)),
	         m_file, SLOT(slotReparentBlocks(Block*,Block*)));
	connect( m_ui.graphicsView, SIGNAL( selectionChanged()),
	         m_file, SLOT(itemSelectionChanged()));
	connect( m_file, SIGNAL(fileModified( bool )),
	         this, SLOT(setWindowModified ( bool )));
	connect( m_file, SIGNAL(fileSaved( const QString& )),
	         this, SLOT(updateWindowTitle(const QString &)));
	connect( m_file, SIGNAL(fileLoaded( const QString& )),
	         this, SLOT(fileLoaded(const QString &)));

	connect( m_file, SIGNAL(status(const QString &)),
	         statusBar(), SLOT(showMessage( const QString& )));

	m_slider = new QSlider( Qt::Horizontal, statusBar() );
	m_slider->setMinimum(10);
	m_slider->setMaximum(200);
	m_slider->setMaximumWidth(200);
	statusBar()->addPermanentWidget(m_slider);
	connect( m_slider, SIGNAL(valueChanged( int )),
	         m_ui.graphicsView, SLOT(setZoomView(int)));
	connect( m_ui.graphicsView, SIGNAL(zoomLevelChanged(int) ),
	         m_slider, SLOT(setValue( int )));

	m_ui.actionSave->setShortcut(QKeySequence::Save);
	m_ui.actionLoad->setShortcut(QKeySequence::Open);
	m_ui.actionNew->setShortcut(QKeySequence::New);
	m_ui.actionCut->setShortcut(QKeySequence::Cut);
	m_ui.actionCopy->setShortcut(QKeySequence::Copy);
	m_ui.actionPaste->setShortcut(QKeySequence::Paste);
	m_ui.actionDelete->setShortcut(QKeySequence::Delete);
	m_ui.actionSelectAll->setShortcut(QKeySequence::SelectAll);
	m_ui.actionPrint->setShortcut(QKeySequence::Print);
	m_ui.actionZoomIn->setShortcut(QKeySequence::ZoomIn);
	m_ui.actionZoomOut->setShortcut(QKeySequence::ZoomOut);
 	m_ui.actionQuit->setShortcut(QKeySequence::Close);

	QList<QAction*> blockActions;
	blockActions << m_ui.menuNode->actions();

	m_file->setBlockActions( blockActions );

	QTimer::singleShot(0, this, SLOT(startupScreen()));
}

void MainWindow::on_actionNew_activated( )
{
	m_file->slotNewFile();
}

void MainWindow::on_actionSave_activated( )
{
	qDebug() << QPictureIO::inputFormats() << QPictureIO::outputFormats();
	m_file->slotSaveFile();
}

void MainWindow::on_actionLoad_activated( )
{
	m_file->slotOpenFile();
}

void MainWindow::on_actionArrangeChildren_activated()
{
	m_file->arrangeBlocks();
}

void MainWindow::setupDocks( )
{
}

void MainWindow::setupModel( )
{
	m_file->propertyModel()->setBlock(m_file->root());
}

void MainWindow::on_actionReparentIdea_activated( )
{
	m_ui.graphicsView->setMode( MindMapView::Reparent );
}

void MainWindow::on_actionRemoveIdea_activated( )
{
	m_file->deleteSelection();
}

void MainWindow::on_actionCut_activated( )
{
	m_file->cutSelection();
}

void MainWindow::on_actionCopy_activated( )
{
	m_file->copySelection();
}

void MainWindow::on_actionPaste_activated( )
{
	m_file->pasteNode(m_file->selectedNode());
}

void MainWindow::on_actionPrint_activated( )
{
	QPrinter printer;
	printer.setOrientation( (QPrinter::Orientation)
	                        m_file->getProperty("page.orientation", QPrinter::Portrait).toInt());
	printer.setPageSize( (QPrinter::PageSize)
		m_file->getProperty("page.pagesize", QPrinter::Letter).toInt());

	if (QPrintDialog(&printer).exec() == QDialog::Accepted)
	{
		m_file->setProperty( "page.orientation", printer.orientation() );
		m_file->setProperty( "page.pagesize", printer.pageSize() );

		QPainter painter(&printer);
		painter.setRenderHint(QPainter::Antialiasing);
		m_file->clearSelection();
		m_file->scene()->render(&painter);
	}
}

void MainWindow::on_actionQuit_activated( )
{
	close();
}

void MainWindow::on_actionZoomIn_activated( )
{
	m_slider->triggerAction(QAbstractSlider::SliderPageStepAdd);
}

void MainWindow::on_actionZoomOut_activated( )
{
	m_slider->triggerAction(QAbstractSlider::SliderPageStepSub);
}

void MainWindow::on_actionAddIdea_activated( )
{
	m_file->createChildOnSelection();
}

QString generateImageFilter()
{
	QList<QByteArray> formats = QImageWriter::supportedImageFormats();
	QStringList returnFormats;
	const QString filterTemplate = "*.%1";
	foreach( QString format, formats )
		returnFormats += filterTemplate.arg(format);

#if QT_VERSION >= 0x040300
	returnFormats += "*.svg";
#endif
	return returnFormats.join(" ");
}

void MainWindow::on_actionExportImage_activated( )
{
	QString startFile = m_file->generateFilePath("png");
	if(startFile.isEmpty())
		startFile = QDir::homePath ();
	QString exportFile = QFileDialog::getSaveFileName(
		this,
		tr("Choose a filename to save under"),
		startFile,
		tr("Image Files ( %1 );;All Files (*.*)").arg(generateImageFilter()));
	if(exportFile.isEmpty())
		return;

#if QT_VERSION >= 0x040300
	if( exportFile.endsWith("svg", Qt::CaseInsensitive) )
		m_file->exportSVG( exportFile );
	else
#endif
		m_file->exportImage( exportFile );
}

void MainWindow::on_actionExportText_activated( )
{
	ASCIIExportDialog::exportMindmap( m_file );
}

void MainWindow::on_actionExportDocbook_activated( )
{
	DocbookExportDialog::exportMindmap(m_file);
}

void MainWindow::on_actionExportWiki_activated()
{
	WikiExport::exportMindmap(m_file);
}

void MainWindow::on_actionAlignLeftEdges_activated( )
{
	m_file->alignLeftEdgesOfSelection();
}

void MainWindow::on_actionAlignRightEdges_activated( )
{
	m_file->alignRightEdgesOfSelection();
}

void MainWindow::on_actionAlignTopEdges_activated( )
{
	m_file->alignTopEdgesOfSelection();
}

void MainWindow::on_actionAlignBottomEdges_activated( )
{
	m_file->alignBottomEdgesOfSelection();
}

void MainWindow::on_actionSelectAll_activated( )
{
	m_file->selectAllBlocks();
	on_graphicsView_selectionChanged();
}

void MainWindow::closeEvent( QCloseEvent * event )
{
	if( m_file->queryCloseCurrentFile() )
	{
		QSettings settings;
		settings.setValue("Mainwindow/Geometry", geometry() );
		event->accept();
	}
	else
		event->ignore();
}

void MainWindow::on_actionAlignCenterV_activated( )
{
	m_file->alignCenterVSelection();
}

void MainWindow::on_actionAlignCenterH_activated( )
{
	m_file->alignCenterHSelection();
}

void MainWindow::on_actionReload_activated( )
{
	m_file->slotReloadFile();
}

void MainWindow::on_actionAbout_activated( )
{
	QMessageBox::about(this, "About Flo", "Flo is a mind mapping program");
}

void MainWindow::on_actionAboutQt_activated( )
{
	QMessageBox::aboutQt(this, "About Qt(tm)");
}

void MainWindow::on_actionDocumentOptions_activated( )
{
	m_file->configureDocument();
}

void MainWindow::setupMainwindow( )
{
	QDesktopWidget desktop;
	QSettings settings;

	setGeometry( settings.value("Mainwindow/Geometry",
	                            desktop.availableGeometry(this).adjusted(25,25,-50,-50)).value<QRect>() );
}

void MainWindow::updateWindowTitle( const QString & fileName )
{
	setWindowTitle( windowTitleTemplate.arg(fileName));
}

void MainWindow::fileLoaded( const QString & fileName )
{
	m_file->root()->setSelected(true);
	m_ui.graphicsView->setZoomView(100);
	m_slider->setValue(100);
	m_ui.graphicsView->ensureVisible( m_file->root() );
	updateWindowTitle( fileName );
	m_file->scene()->update();
}

void MainWindow::on_actionExportPDFSlides_activated( )
{
	SlideProperties properties(m_file, this);
	QString exportFile = m_file->getProperty("slides.output", m_file->generateFilePath("pdf")).toString();

	if( properties.exec() )
	{
		PDFSlideReporter reporter;
		if(exportFile.isEmpty())
			return;
		reporter.generateReport( m_file, exportFile);
	}
}

void MainWindow::on_actionEditEmblems_activated()
{
	EmblemSelector selector(this, m_file);
	selector.exec();
}

void MainWindow::on_actionManual_activated()
{
	HelpDialog dlg(this);
	dlg.exec();
}


void MainWindow::on_actionColorIdea_activated( )
{
	m_file->colorSelection();
}


void MainWindow::on_actionImportCreoleWiki_activated( )
{
// 	QString wikiFileName = QFileDialog::getOpenFileName( this, tr("Select Wiki Text")
	QFile wiki;
	StateMachineBase::Context ctx;
	ctx.lexer = new WikiLexer;
	ctx.observer = new FloParserObserver( m_file, "" );
	ctx.nextState = new Parser;

	ctx.lexer->setInput ( QString::fromUtf8( wiki.readAll() ) );
	ctx.observer->startPage( wiki.fileName() );
	while ( ctx.nextState != 0 )
			ctx.nextState->exec ( &ctx );
	ctx.observer->endPage();

}

void MainWindow::startupScreen( )
{
	StartupScreen screen(this);
	screen.setRecentFiles( m_file->recentFileList( ) );
	switch( screen.exec() )
	{
	case 0:
		m_file->slotNewFile();
		break;
	case 1:
		m_file->slotOpenFile();
		break;
	case 2:
		m_file->slotOpenFileByName(screen.recentFileName());
		break;
	default:
		close();
		break;
	};
}

void MainWindow::on_actionChangeFont_activated( )
{
	m_file->changeFontSelection();
}

void MainWindow::on_actionChangeType_activated( )
{
	m_file->changeShapeSelection();
}


void MainWindow::on_actionImportFreemindMindmap_activated( )
{
	QString wikiFileName = QFileDialog::getOpenFileName( this, tr("Select Freemind File..."), m_file->currentPath(), "*.mm");
	if( wikiFileName.isEmpty() )
		return;

	QFile inputFile(wikiFileName);
	if( inputFile.open(QIODevice::ReadOnly) )
	{
		QDomDocument document;
		if( document.setContent( &inputFile ) )
		{
			if( !m_file->importFreemindMindMap( document ) )
			{
				// load error
				qDebug("load error");
			}
			else
				return;
		}
		else
			return;
		// parser error
		qDebug("parser error");
	}
	// access error.
	qDebug("access error");
}

void MainWindow::on_actionTextOutline_activated( )
{
	QString textFileName = QFileDialog::getOpenFileName( this, tr("Select Freemind File..."), m_file->currentPath(), "*.txt");
	if( textFileName.isEmpty() )
		return;

	QFile inputFile(textFileName);
	if( inputFile.open(QIODevice::ReadOnly) )
	{
		if( !m_file->importTextOutline( &inputFile ))
		{
			// load error
			qDebug("load error");
		}
		else
			return;
	}
	// access error.
	qDebug("access error");
}

void MainWindow::on_actionProperties_activated( )
{
	BasicPropertyEditor editor( m_file, this);
	editor.setupModel( m_file->propertyModel() );
	editor.exec();
}

void MainWindow::on_actionCheckSpelling_activated( )
{

}

void MainWindow::on_graphicsView_selectionChanged( )
{
	int items = m_file->selectedNodes().size();
	if( items == 0 )
	{
		m_ui.actionCut->setEnabled(false);
		m_ui.actionCopy->setEnabled(false);
		m_ui.actionPaste->setEnabled(true);
		m_ui.actionDelete->setEnabled(false);
		m_ui.actionAddIdea->setEnabled(false);
		m_ui.actionRemoveIdea->setEnabled(false);
		m_ui.actionColorIdea->setEnabled(false);
		m_ui.actionChangeFont->setEnabled(false);
		m_ui.actionChangeType->setEnabled(false);
		m_ui.actionProperties->setEnabled(false);
		m_ui.actionReparentIdea->setEnabled(false);
		m_ui.actionAlignLeftEdges->setEnabled(false);
		m_ui.actionAlignRightEdges->setEnabled(false);
		m_ui.actionAlignTopEdges->setEnabled(false);
		m_ui.actionAlignBottomEdges->setEnabled(false);
		m_ui.actionAlignCenterV->setEnabled(false);
		m_ui.actionAlignCenterH->setEnabled(false);
	}
	else if( items == 1 )
	{
		m_ui.actionCut->setEnabled(true);
		m_ui.actionCopy->setEnabled(true);
		m_ui.actionPaste->setEnabled(true);
		m_ui.actionDelete->setEnabled(true);
		m_ui.actionAddIdea->setEnabled(true);
		m_ui.actionRemoveIdea->setEnabled(true);
		m_ui.actionColorIdea->setEnabled(true);
		m_ui.actionChangeFont->setEnabled(true);
		m_ui.actionChangeType->setEnabled(true);
		m_ui.actionProperties->setEnabled(true);
		m_ui.actionReparentIdea->setEnabled(true);
		m_ui.actionAlignLeftEdges->setEnabled(false);
		m_ui.actionAlignRightEdges->setEnabled(false);
		m_ui.actionAlignTopEdges->setEnabled(false);
		m_ui.actionAlignBottomEdges->setEnabled(false);
		m_ui.actionAlignCenterV->setEnabled(false);
		m_ui.actionAlignCenterH->setEnabled(false);
	}
	else
	{
		m_ui.actionCut->setEnabled(true);
		m_ui.actionCopy->setEnabled(true);
		m_ui.actionPaste->setEnabled(true);
		m_ui.actionDelete->setEnabled(true);
		m_ui.actionAddIdea->setEnabled(false);
		m_ui.actionRemoveIdea->setEnabled(true);
		m_ui.actionColorIdea->setEnabled(true);
		m_ui.actionChangeFont->setEnabled(true);
		m_ui.actionChangeType->setEnabled(true);
		m_ui.actionProperties->setEnabled(false);
		m_ui.actionReparentIdea->setEnabled(false);
		m_ui.actionAlignLeftEdges->setEnabled(true);
		m_ui.actionAlignRightEdges->setEnabled(true);
		m_ui.actionAlignTopEdges->setEnabled(true);
		m_ui.actionAlignBottomEdges->setEnabled(true);
		m_ui.actionAlignCenterV->setEnabled(true);
		m_ui.actionAlignCenterH->setEnabled(true);
	}
}

