/***************************************************************************
**
**  This file is part of QGpGuiTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2010-06-24
**  Copyright: 2010-2019
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "Settings.h"
#include "MultiDocumentEnvironment.h"
#include "MultiDocumentWindow.h"
#include "MultiDocumentTab.h"

namespace QGpGuiTools {

/*!
  \class MultiDocumentEnvironment MultiDocumentEnvironment.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

  MultiDocumentEnvironment * MultiDocumentEnvironment::_instance=0;

/*!
  Description of constructor still missing
*/
MultiDocumentEnvironment::MultiDocumentEnvironment(QObject * parent)
    : QObject(parent)
{
  TRACE;
  ASSERT(!_instance);

  _instance=this;
  _fileNewAction=0;
  _fileOpenAction=0;
  _fileOpenRecentAction=0;
  _fileSaveAction=0;
  _fileSaveAsAction=0;
  _filePrintAction=0;
  _fileQuitAction=0;

  _editUndoAction=0;
  _editRedoAction=0;
  _editCutAction=0;
  _editCopyAction=0;
  _editPasteAction=0;

  _windowsNewWindowAction=0;

  _helpDocumentationAction=0;
  _helpWhatsThisAction=0;
  _helpAboutAction=0;
  _helpAboutQtAction=0;

  _recentDocumentMenu=0;
}

/*!
  Description of destructor still missing
*/
MultiDocumentEnvironment::~MultiDocumentEnvironment()
{
  TRACE;
  qDeleteAll(_windows);
  delete _recentDocumentMenu;
}

void MultiDocumentEnvironment::createFileActions()
{
  TRACE;
  QAction * a;

  a=new QAction(QIcon(":filenew.png"), tr("New"), this);
  a->setStatusTip(tr("Create a new document"));
  connect(a, SIGNAL(triggered()), this, SLOT(newDocument()));
  _fileNewAction=a;

  a=new QAction(QIcon(":fileopen.png"), tr("Open"), this);
  a->setStatusTip(tr("Open an existing document"));
  connect(a, SIGNAL(triggered()), this, SLOT(openDocument()));
  _fileOpenAction=a;

  _recentDocumentMenu=new QMenu;
  a=new QAction(QIcon(":fileopen.png"), tr("Open recent"), this);
  a->setStatusTip(tr("Open a recent existing document"));
  a->setMenu(_recentDocumentMenu);
  connect(a, SIGNAL(triggered()), this, SLOT(openMostRecentDocument()));
  connect(_recentDocumentMenu, SIGNAL(aboutToShow()), this, SLOT(showOpenRecentMenu()));
  _fileOpenRecentAction=a;

  a=new QAction(QIcon(":filesave.png"), tr("Save"), this);
  a->setStatusTip(tr("Save current document"));
  a->setShortcut(tr("Ctrl+S"));
  connect(a, SIGNAL(triggered()), this, SLOT(saveDocument()));
  _fileSaveAction=a;

  a=new QAction(tr("Save as ..."), this);
  a->setShortcut(tr("Ctrl+Shift+S"));
  a->setStatusTip(tr("Save current document"));
  connect(a, SIGNAL(triggered()), this, SLOT(saveDocumentAs()));
  _fileSaveAsAction=a;

  a=new QAction(QIcon(":fileprint.png"), tr("&Print"), this);
  a->setShortcut(tr("Ctrl+P"));
  a->setStatusTip(tr("Print current document"));
  connect(a, SIGNAL(triggered()), this, SLOT(printDocument()));
  _filePrintAction=a;

  a=new QAction(tr("&Quit"), this);
  a->setShortcut(tr("Ctrl+Q"));
  a->setStatusTip(tr("Quit application"));
  connect(a, SIGNAL(triggered()), this, SLOT(quit()));
  _fileQuitAction=a;
}

void MultiDocumentEnvironment::createEditActions()
{
  TRACE;
  QAction * a;

  a=new QAction(QIcon(":editundo.png"), tr("&Undo"), this);
  a->setShortcut(tr("Ctrl+Z"));
  a->setToolTip(tr("Undo last operation"));
  connect(a, SIGNAL(triggered()), this, SLOT(undo()));
  _editUndoAction=a;

  a=new QAction(QIcon(":editredo.png"), tr("Re&do"), this);
  a->setShortcut(tr("Ctrl+Shift+Z"));
  a->setToolTip(tr("Redo last operation"));
  connect(a, SIGNAL(triggered()), this, SLOT(redo()));
  _editRedoAction=a;

  a=new QAction(QIcon(":editcut.png"), tr("Cu&t"), this);
  a->setShortcut(tr("Ctrl+X"));
  a->setToolTip(tr("Cut the current selection's contents to the clipboard"));
  connect(a, SIGNAL(triggered()), this, SLOT(cut()));
  _editCutAction=a;

  a=new QAction(QIcon(":editcopy.png"), tr("&Copy"), this);
  a->setShortcut(tr("Ctrl+C"));
  a->setToolTip(tr("Copy the current selection's contents to the clipboard"));
  connect(a, SIGNAL(triggered()), this, SLOT(copy()));
  _editCopyAction=a;

  a=new QAction(QIcon(":editpaste.png"), tr("&Paste"), this);
  a->setShortcut(tr("Ctrl+V"));
  a->setToolTip(tr("Paste the clipboard's contents in the sheet"));
  connect(a, SIGNAL(triggered()), this, SLOT(paste()));
  _editPasteAction=a;
}

void MultiDocumentEnvironment::createWindowsActions()
{
  TRACE;
  QAction * a=new QAction(tr("New &window"), this);
  a->setToolTip(tr("Create a new main window"));
  connect(a, SIGNAL(triggered()), this, SLOT(addWindow()));
  _windowsNewWindowAction=a;
}

void MultiDocumentEnvironment::createHelpActions()
{
  TRACE;
  QAction * a;

  a=new QAction(tr("Online &Documentation"), this);
  a->setShortcut(tr("F1"));
  a->setToolTip(tr("Access to online html documentation"));
  connect(a, SIGNAL(triggered()), this, SLOT(helpDocumentation()));
  _helpDocumentationAction=a;

  a=QWhatsThis::createAction(this);
  _helpWhatsThisAction=a;

  a=new QAction(tr("&About"), this);
  a->setToolTip(tr("Shows application About box"));
  connect(a, SIGNAL(triggered()), this, SLOT(helpAbout()));
  _helpAboutAction=a;

  a=new QAction(tr("About &Qt"), this);
  a->setToolTip(tr("Shows the Qt library's About box"));
  connect(a, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
  _helpAboutQtAction=a;
}

void MultiDocumentEnvironment::addFileActions(QMenu * m, QToolBar * tb)
{
  TRACE;
  if(m) {
    m->addAction(_fileNewAction);
    m->addAction(_fileOpenAction);
    m->addAction(_fileSaveAction);
    m->addAction(_fileSaveAsAction);
    m->addSeparator();
    m->addAction(_filePrintAction);
    m->addSeparator();
    m->addAction(_fileQuitAction);
  }
  if(tb) {
    tb->addAction(_fileNewAction);
    tb->addAction(_fileOpenAction);
    tb->addAction(_fileSaveAction);
    tb->addSeparator();
    tb->addAction(_filePrintAction);
  }
}

void MultiDocumentEnvironment::addEditActions(QMenu * m, QToolBar * tb)
{
  TRACE;
  if(m) {
    m->addAction(_editUndoAction);
    m->addAction(_editRedoAction);
    m->addSeparator();
    m->addAction(_editCutAction);
    m->addAction(_editCopyAction);
    m->addAction(_editPasteAction);
    m->addSeparator();
  }
  if(tb) {
    tb->addAction(_editUndoAction);
    tb->addAction(_editRedoAction);
    tb->addSeparator();
    tb->addAction(_editCutAction);
    tb->addAction(_editCopyAction);
    tb->addAction(_editPasteAction);
    tb->addSeparator();
  }
}

void MultiDocumentEnvironment::addViewActions(QMenu * m, QToolBar * tb)
{
  TRACE;
  if(m) {
  }
  if(tb) {
  }
}

void MultiDocumentEnvironment::addWindowsActions(QMenu * m)
{
  TRACE;
  if(m) {
    m->addAction(_windowsNewWindowAction);
  }
}

void MultiDocumentEnvironment::addHelpActions(QMenu * m)
{
  TRACE;
  if(m) {
    m->addAction(_helpDocumentationAction);
    m->addAction(_helpWhatsThisAction);
    m->addSeparator();
    m->addAction(_helpAboutAction);
    m->addAction(_helpAboutQtAction);
  }
}

void MultiDocumentEnvironment::newDocument()
{
  TRACE;
  MultiDocumentWindow * w=currentWindow();
  w->newDocument();
}

void MultiDocumentEnvironment::openDocument(const QString& fileName)
{
  TRACE;
  MultiDocumentWindow * w=currentWindow();
  w->openDocument(fileName);
}

void MultiDocumentEnvironment::saveDocument()
{
  TRACE;
  MultiDocumentWindow * w=currentWindow();
  w->saveDocument();
}

void MultiDocumentEnvironment::saveDocumentAs()
{
  TRACE;
  MultiDocumentWindow * w=currentWindow();
  w->saveDocumentAs();
}

void MultiDocumentEnvironment::printDocument()
{
  TRACE;
  MultiDocumentWindow * w=currentWindow();
  w->printDocument();
}

/*!
  Return true to accept quitting application
*/
bool MultiDocumentEnvironment::quit()
{
  TRACE;
  QApplication::quit();
  return true;
}

void MultiDocumentEnvironment::undo()
{
}

void MultiDocumentEnvironment::redo()
{
}

void MultiDocumentEnvironment::cut()
{
}

void MultiDocumentEnvironment::copy()
{
}

void MultiDocumentEnvironment::paste()
{
}

MultiDocumentWindow * MultiDocumentEnvironment::createWindow()
{
  return new MultiDocumentWindow;
}

MultiDocumentWindow * MultiDocumentEnvironment::addWindow()
{
  TRACE;
  MultiDocumentWindow * w=createWindow();
  connect(w, SIGNAL(destroyed(QObject *)), this, SLOT(removeWindow(QObject *)));
  _windows.append(w);
  w->show();
  return w;
}

void MultiDocumentEnvironment::removeWindow(QObject * windowObject)
{
  TRACE;
  MultiDocumentWindow * w=static_cast<MultiDocumentWindow *>(windowObject);
  int index=_windows.indexOf(w);
  _windows.removeAt(index);
  if(_windows.isEmpty()) {
    QApplication::quit();
  }
}

/*!
  \a parent is the widget that wants to add the new widget \a w.
  The \a parent is used to get the MultiDocumentWindow and the tab index to which the widget \a w
  will be added.
*/
MultiDocumentSubWindow * MultiDocumentEnvironment::addSubWindow(QWidget * parent, QWidget * w)
{
  TRACE;
  MultiDocumentTab * t=tab(parent);
  MultiDocumentWindow * mw;
  if(t) {
    mw=window(t);
  } else {
    mw=window(parent);
    if(!mw) {
      mw=currentWindow();
    }
    t=mw->currentTab();
  }
  return mw->addSubWindow(w, t);
}

void MultiDocumentEnvironment::removeSubWindow(QWidget * w)
{
  TRACE;
  MultiDocumentTab * t=tab(w);
  if(t) {
    MultiDocumentSubWindow * msw=qobject_cast<MultiDocumentSubWindow *>(w->parentWidget());
    t->removeSubWindow(msw);
    delete msw;
  }
}

void MultiDocumentEnvironment::activateSubWindow(QWidget * w)
{
  TRACE;
  MultiDocumentTab * t=tab(w);
  if(t) {
    t->activate();
    MultiDocumentSubWindow * msw=qobject_cast<MultiDocumentSubWindow *>(w->parentWidget());
    t->setActiveSubWindow(msw);
    msw->show();
  }
}

void MultiDocumentEnvironment::helpDocumentation()
{
  TRACE;
  QUrl doc("http://www.geopsy.org/wiki/index.php");
  QDesktopServices::openUrl(doc);
}

void MultiDocumentEnvironment::helpAbout()
{
  TRACE;
  Message::information(MSG_ID, tr("About %1").arg(QApplication::applicationName()),
                       tr("Comments still missing"));
}

/*!
  Returns the current active window or the first one if none is active.
*/
MultiDocumentWindow * MultiDocumentEnvironment::currentWindow() const
{
  TRACE;
  QWidget * aw=QApplication::activeWindow();
  foreach(MultiDocumentWindow * w, _windows) {
    if(w->isAncestorOf(aw)) {
      return w;
    }
  }
  // Make sure that at least one window exists.
  ASSERT(!_windows.isEmpty());
  return _windows.first();
}

/*!
  Returns the current active window or the first one if none is active.
*/
MultiDocumentTab * MultiDocumentEnvironment::currentTab() const
{
  TRACE;
  MultiDocumentWindow * w=currentWindow();
  if(w) {
    return w->currentTab();
  } else {
    return 0;
  }
}

/*!
  Scan all parents of \a o for a QWidget.
*/
const QWidget * MultiDocumentEnvironment::parentWidget(const QObject * o)
{
  TRACE;
  const QWidget * w;
  while(o) {
    w=qobject_cast<const QWidget *>(o);
    if(w) {
      return w;
    } else {
      o=o->parent();
    }
  }
  return 0;
}

/*!
  Scan all parents of \a w for a MultiDocumentWindow.
*/
MultiDocumentWindow * MultiDocumentEnvironment::window(const QWidget * w)
{
  TRACE;
  while(w) {
    const MultiDocumentWindow * mw=qobject_cast<const MultiDocumentWindow *>(w);
    if(mw) return const_cast<MultiDocumentWindow *>(mw);
    w=w->parentWidget();
  }
  return 0;
}

/*!
  Scan all parents of \a w for a MultiDocumentTab.
*/
MultiDocumentTab * MultiDocumentEnvironment::tab(const QWidget * w)
{
  TRACE;
  while(w) {
    const MultiDocumentTab * t=qobject_cast<const MultiDocumentTab *>(w);
    if(t) return const_cast<MultiDocumentTab *>(t);
    w=w->parentWidget();
  }
  return 0;
}

void MultiDocumentEnvironment::addRecentDocument(const QString& fileName)
{
  TRACE;
  Settings::setHistory("RecentDocuments", fileName, 10);
}

void MultiDocumentEnvironment::showOpenRecentMenu()
{
  TRACE;
  QStringList docs=Settings::getHistory("RecentDocuments");
  QMenu * m=qobject_cast<QMenu *>(sender());
  if(!m) {
    return;
  }
  m->clear();
  QAction * a;
  for(QStringList::iterator it=docs.begin(); it!=docs.end(); ++it) {
    QFileInfo fi(*it);
    if(fi.exists()) {
      a=new QAction(fi.completeBaseName(), this);
      a->setStatusTip(fi.absoluteFilePath());
      connect(a, SIGNAL(triggered()), this, SLOT(openRecentDocument()));
      m->addAction(a);
    } else {
      Settings::removeHistory("RecentDocuments", *it);
    }
  }
}

void MultiDocumentEnvironment::openRecentDocument()
{
  TRACE;
  QAction * a=qobject_cast<QAction *>(sender());
  openDocument(a->statusTip());
}

void MultiDocumentEnvironment::openMostRecentDocument()
{
  TRACE;
  QStringList docs=Settings::getHistory("RecentDocuments");
  if(docs.isEmpty()) {
    openDocument();
  } else {
    openDocument(docs.first());
  }
}

} // namespace QGpGuiTools
