/*
 * LXImage-Qt - a simple and fast image viewer
 * Copyright (C) 2013  PCMan <pcman.tw@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 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 "application.h"
#include <QCommandLineParser>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QPixmapCache>
#include "applicationadaptor.h"
#include "screenshotdialog.h"
#include "mainwindow.h"

using namespace LxImage;

static const char* serviceName = "org.lxqt.LxImage";
static const char* ifaceName = "org.lxqt.LxImage.Application";

Application::Application(int& argc, char** argv):
  QApplication(argc, argv),
  libFm(),
  windowCount_(0) {
  setApplicationVersion(QStringLiteral(LXIMAGE_VERSION));
  setWindowIcon(QIcon::fromTheme(QStringLiteral("lximage-qt")));
}

bool Application::init(int argc, char** argv) {
  Q_UNUSED(argc)
  Q_UNUSED(argv)

  // no reason to set an allocation limit because this is an image viewer
  QImageReader::setAllocationLimit(0);

  // install the translations built-into Qt itself
  if(qtTranslator.load(QStringLiteral("qt_") + QLocale::system().name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
      installTranslator(&qtTranslator);
  }

  // install libfm-qt translator
  installTranslator(libFm.translator());

  // install our own translations
  if(translator.load(QStringLiteral("lximage-qt_") + QLocale::system().name(), QStringLiteral(LXIMAGE_DATA_DIR) + QStringLiteral("/translations"))) {
      installTranslator(&translator);
  }

  // initialize dbus
  QDBusConnection dbus = QDBusConnection::sessionBus();
  if(dbus.registerService(QLatin1String(serviceName))) {
    settings_.load(); // load settings
    // we successfully registered the service
    isPrimaryInstance = true;
    setQuitOnLastWindowClosed(false); // do not quit even when there're no windows

    new ApplicationAdaptor(this);
    dbus.registerObject(QStringLiteral("/Application"), this);

    connect(this, &Application::aboutToQuit, this, &Application::onAboutToQuit);

    if(settings_.useFallbackIconTheme())
      QIcon::setThemeName(settings_.fallbackIconTheme());
  }
  else {
    // an service of the same name is already registered.
    // we're not the first instance
    isPrimaryInstance = false;
  }

  QPixmapCache::setCacheLimit(1024); // avoid pixmap caching.

  return parseCommandLineArgs();
}

bool Application::parseCommandLineArgs() {
  QCommandLineParser parser;
  parser.addHelpOption();
  parser.addVersionOption();

  QCommandLineOption fullscreenOption(
    QStringList() << QStringLiteral("f") << QStringLiteral("fullscreen"),
    tr("Start in fullscreen (can be useful with tiling window managers)")
  );
  parser.addOption(fullscreenOption);

  const bool isX11 = QGuiApplication::platformName() == QStringLiteral("xcb");

  QCommandLineOption screenshotOption(
    QStringList() << QStringLiteral("s") << QStringLiteral("screenshot"),
    tr("Take a screenshot (deprecated, please use screengrab instead)")
  );
  if(isX11) {
    parser.addOption(screenshotOption);
  }


  QCommandLineOption screenshotOptionDir(
    QStringList() << QStringLiteral("d") << QStringLiteral("dirscreenshot"),
    tr("Take a screenshot and save it to the directory without showing the GUI (deprecated, please use screengrab instead)"), tr("DIR")
  );
  if(isX11) {
    parser.addOption(screenshotOptionDir);
  }

  const QString files = tr("[FILE1, FILE2,...]");
  parser.addPositionalArgument(QStringLiteral("files"), files, files);

  parser.process(*this);

  const QStringList args = parser.positionalArguments();
  bool screenshotTool = false;
  if(isX11)
    screenshotTool = parser.isSet(screenshotOption);

  QStringList paths;
  for(const QString& arg : args) {
    QFileInfo info(arg);
    paths.push_back(info.absoluteFilePath());
  }


  //silent no-gui screenshot
  if(isX11) {
    if (parser.isSet(screenshotOptionDir)) {
        ScreenshotDialog::cmdTopShotToDir(parser.value(screenshotOptionDir));
        return false;
    }
  }

  bool keepRunning = false;
  if(isPrimaryInstance) {
    settings_.load();
    keepRunning = true;
    if(screenshotTool) {
      screenshot();
    }
    else
      newWindow(paths, parser.isSet(fullscreenOption));
  }
  else {
    // we're not the primary instance.
    // call the primary instance via dbus to do operations
    QDBusConnection dbus = QDBusConnection::sessionBus();
    QDBusInterface iface(QLatin1String(serviceName), QStringLiteral("/Application"), QLatin1String(ifaceName), dbus, this);
    if(screenshotTool)
      iface.call(QStringLiteral("screenshot"));
    else
      iface.call(QStringLiteral("newWindow"), paths, parser.isSet(fullscreenOption));
  }
  return keepRunning;
}

MainWindow* Application::createWindow(bool fullscreen) {
  LxImage::MainWindow* window;
  window = new LxImage::MainWindow();
  window->setShowFullScreen(fullscreen);
  return window;
}

void Application::newWindow(QStringList files, bool fullscreen) {
  LxImage::MainWindow* window;
  if(files.empty()) {
    window = createWindow(fullscreen);

    window->resize(settings_.windowWidth(), settings_.windowHeight());
    if(settings_.windowMaximized())
      window->setWindowState(window->windowState() | Qt::WindowMaximized);

    window->showAndRaise();
  }
  else {
    for(const QString& fileName : std::as_const(files)) {
      window = createWindow(fullscreen);
      window->openImageFile(fileName);

      window->resize(settings_.windowWidth(), settings_.windowHeight());
      if(settings_.windowMaximized())
        window->setWindowState(window->windowState() | Qt::WindowMaximized);

      /* when there's an image, we show the window AFTER resizing
         and centering it appropriately at MainWindow::updateUI() */
      //window->show();
    }
  }
}

void Application::applySettings() {
  const auto windows = topLevelWidgets();
  for(QWidget* window : windows) {
    if(window->inherits("LxImage::MainWindow")) {
      static_cast<MainWindow*>(window)->applySettings();
    }
  }
}

void Application::screenshot() {
  ScreenshotDialog* dlg = new ScreenshotDialog();
  dlg->show();
}

void Application::editPreferences() {
  // open Preferences dialog only if default shortcuts are known
  if(defaultShortcuts_.isEmpty()) {
    return;
  }
  if(preferencesDialog_ == nullptr) {
    preferencesDialog_ = new PreferencesDialog();
  }
  preferencesDialog_.data()->show();
  preferencesDialog_.data()->raise();
  preferencesDialog_.data()->activateWindow();
}

void Application::onAboutToQuit() {
  settings_.save();
}
