/*
 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3, as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY, 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/>.
 *
 */
#include "anbox/platform/sdlmir_display_connection.h"
#include "anbox/logger.h"

#include <boost/throw_exception.hpp>

#include <stdexcept>
#include <string>

namespace {
static const MirDisplayOutput *find_active_output(
    const MirDisplayConfiguration *conf) {
  const MirDisplayOutput *output = NULL;
  int d;

  for (d = 0; d < (int)conf->num_outputs; d++) {
    const MirDisplayOutput *out = conf->outputs + d;

    if (out->used && out->connected && out->num_modes &&
        out->current_mode < out->num_modes) {
      output = out;
      break;
    }
  }

  return output;
}
}

namespace anbox::sdl {
MirDisplayConnection::MirDisplayConnection()
    : connection_(nullptr),
      output_id_(-1),
      vertical_resolution_(0),
      horizontal_resolution_(0) {
  auto xdg_runtime_dir = ::getenv("XDG_RUNTIME_DIR");
  if (!xdg_runtime_dir)
    BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find XDG_RUNTIME_DIR"));

  std::string socket_path = xdg_runtime_dir;
  socket_path += "/mir_socket";

  connection_ = mir_connect_sync(socket_path.c_str(), "anbox");
  if (!mir_connection_is_valid(connection_)) {
    std::string msg;
    msg += "Failed to connect with Mir server: ";
    msg += mir_connection_get_error_message(connection_);
    BOOST_THROW_EXCEPTION(std::runtime_error(msg.c_str()));
  }

  mir_connection_set_display_config_change_callback(
      connection_,
      [](MirConnection *connection, void *context) {
        auto thiz = reinterpret_cast<MirDisplayConnection *>(context);
        DEBUG("");
      },
      this);

  MirDisplayConfiguration *display_config =
      mir_connection_create_display_config(connection_);

  const MirDisplayOutput *output = find_active_output(display_config);
  if (!output)
    BOOST_THROW_EXCEPTION(
        std::runtime_error("Failed to find active output display"));

  DEBUG("Selecting output id %d", output->output_id);

  output_id_ = output->output_id;

  const MirDisplayMode *mode = &output->modes[output->current_mode];

  vertical_resolution_ = mode->vertical_resolution;
  horizontal_resolution_ = mode->horizontal_resolution;

  mir_display_config_destroy(display_config);
}

MirDisplayConnection::~MirDisplayConnection() {
  mir_connection_release(connection_);
}

MirConnection *MirDisplayConnection::connection() const { return connection_; }

MirPixelFormat MirDisplayConnection::default_pixel_format() const {
  MirPixelFormat format;
  unsigned int nformats;
  mir_connection_get_available_surface_formats(connection_, &format, 1,
                                               &nformats);
  return format;
}

EGLNativeDisplayType MirDisplayConnection::native_display() const {
  return mir_connection_get_egl_native_display(connection_);
}

int MirDisplayConnection::output_id() const { return output_id_; }

int MirDisplayConnection::vertical_resolution() const {
  return vertical_resolution_;
}

int MirDisplayConnection::horizontal_resolution() const {
  return horizontal_resolution_;
}
}