#include <dlfcn.h>
#include <graph/server/plugin.h>
#include <qthread.h>
#include <iostream>
#include <stdexcept>
#include <string>

namespace Graph {
Plugin::Plugin(const std::string& path, update_callback_t callback, int argc, char** argv) : path(path) {
  handle = dlopen(path.c_str(), RTLD_LAZY);
  if (!handle)
    throw std::runtime_error(dlerror());

  plugin = (plugin_t*)dlsym((void*)this->handle, "plugin");
  if (!plugin)
    throw std::runtime_error(dlerror());

  plugin->update_callback = callback;
  plugin->argc = argc;
  plugin->argv = argv;
}

void Plugin::run() {
  emit exited(plugin->run_method());
}

Plugin::~Plugin() {
  if (plugin->destroy_method)
    emit exited(plugin->destroy_method());

  if (handle)
    dlclose((void*)handle);
}

PluginModel::~PluginModel() {
  for (Plugin* plugin : plugins) {
    delete plugin;
  }
}

int PluginModel::rowCount(const QModelIndex& parent) const {
  return plugins.size();
}

QVariant PluginModel::data(const QModelIndex& index, int role) const {
  if (!index.isValid())
    return QVariant();

  if (role == Qt::DisplayRole) {
    return QString(plugins[index.row()]->getPath().c_str());
  }

  return QVariant();
}

void PluginModel::add(Plugin* plugin) {
  plugins << plugin;
}

void PluginModel::remove(int index) {
  delete plugins[index];
  plugins.removeAt(index);
}

} // namespace Graph