// Copyright (C) 2021 Rob Caelers <robc@krandor.nl>
// All rights reserved.
//
// 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/>.
//

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "ToolkitUnix.hh"

#include <QByteArray>

#include <X11/Xlib.h>

#include "debug.hh"
#include "utils/Platform.hh"
#include "utils/Exception.hh"
#include "ui/GUIConfig.hh"
#include "DBusPreludeWindow.hh"
// #include "GnomeSession.hh"

using namespace workrave::utils;

#include "config/IConfigurator.hh"
#include "debug.hh"

ToolkitUnix::ToolkitUnix(int &argc, char **argv)
  : Toolkit(argc, argv)
{
}

void
ToolkitUnix::apply_platform_override()
{
  // An explicit QT_QPA_PLATFORM in the environment wins.
  if (GUIConfig::force_x11()() && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM"))
    {
      spdlog::info("Forcing X11 backend");
      qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("xcb"));
    }
}

void
ToolkitUnix::preinit(std::shared_ptr<workrave::config::IConfigurator> config)
{
  TRACE_ENTRY();

  XInitThreads();

  locker = std::make_shared<UnixLocker>();
}

void
ToolkitUnix::init(std::shared_ptr<IApplicationContext> app)
{
  TRACE_ENTRY();

#if defined(HAVE_WAYLAND)
  if (Platform::running_on_wayland())
    {
      auto wm = std::make_shared<WaylandWindowManager>();
      bool success = wm->init();
      if (success)
        {
          wayland_window_manager = wm;
        }
    }
#endif

  Toolkit::init(app);
}

std::shared_ptr<Locker>
ToolkitUnix::get_locker()
{
  return locker;
}

auto
ToolkitUnix::get_display_name() const -> const char *
{
  QByteArray wayland_display = qgetenv("WAYLAND_DISPLAY");
  if (!wayland_display.isEmpty())
    {
      display_name = wayland_display.toStdString();
      return display_name.c_str();
    }

  QByteArray x11_display = qgetenv("DISPLAY");
  if (!x11_display.isEmpty())
    {
      display_name = x11_display.toStdString();
      return display_name.c_str();
    }

  return Toolkit::get_display_name();
}

auto
ToolkitUnix::get_desktop_image() -> QPixmap
{
  return {};
}

#if defined(HAVE_WAYLAND)
auto
ToolkitUnix::get_wayland_window_manager() -> std::shared_ptr<WaylandWindowManager>
{
  return wayland_window_manager;
}
#endif

auto
ToolkitUnix::create_prelude_window(int screen_index, workrave::BreakId break_id) -> IPreludeWindow::Ptr
{
  // On GNOME the compositor will not let a client position its own windows, so
  // the shell extension draws the prelude when it is available.
  if (Platform::running_on_wayland() && GUIConfig::use_gnome_shell_preludes()())
    {
      if (DBusPreludeWindow::is_gnome_shell_applet_available())
        {
          if (screen_index != 0)
            {
              // The extension draws on the focused monitor only.
              return {};
            }

          try
            {
              return std::make_shared<DBusPreludeWindow>(break_id);
            }
          catch (const workrave::utils::Exception &ex)
            {
              spdlog::debug("Workrave GNOME shell extension does not support preludes: {}", ex.details());
            }
        }
    }

  return Toolkit::create_prelude_window(screen_index, break_id);
}

void
ToolkitUnix::show_notification(const std::string &id,
                               const std::string &title,
                               const std::string &balloon,
                               std::function<void()> func)
{
  Toolkit::show_notification(id, title, balloon, std::move(func));
}
