#include "adduniversedialog.h"
#include "multiverseview.h"
#include "multiversemodel.h"
#include "ui_multiverseview.h"
#include "universeview.h"

/**
 * @brief MultiverseView::MultiverseView
 * @param parent
 */
MultiverseView::MultiverseView(QWidget *parent, QSacnNode *node)
    : QMainWindow(parent)
    , ui(new Ui::MultiverseView)
    , node(node)
    , model(new MultiverseModel(this, node))
    , sortProxy(new QSortFilterProxyModel(this))
{
  ui->setupUi(this);
  ui->actionTerminate->setEnabled(false);
  ui->actionUnsubscribe->setEnabled(false);
  ui->actionInspect->setEnabled(false);

  sortProxy->setSourceModel(model);

  ui->multiverseView->setModel(sortProxy);
  ui->multiverseView->setSortingEnabled(true);
  ui->multiverseView->sortByColumn(MultiverseModel::Column::Universe,
                                   Qt::SortOrder::AscendingOrder);
  ui->multiverseView->setContextMenuPolicy(Qt::CustomContextMenu);
  ui->multiverseView->expandAll();
  for (int i = 0; i < ui->multiverseView->model()->rowCount(); i++)
    ui->multiverseView->setFirstColumnSpanned(i, QModelIndex(), true);

  connect(ui->multiverseView, &QTreeView::customContextMenuRequested,
          this, &MultiverseView::createContextMenu);

  connect(ui->multiverseView, &QTreeView::doubleClicked,
          this, &MultiverseView::createEditor);

  connect(ui->actionInspect, &QAction::triggered,
          this, [this]() {
      auto selected = ui->multiverseView->currentIndex();
      createEditor(selected);
    });

  connect(ui->actionCreate, &QAction::triggered,
          this, [this, node]() {
      auto dialog = new AddUniverseDialog(this, 1, tr("Create Universe"));
      connect(dialog, &AddUniverseDialog::additionRequested,
              node, &QSacnNode::create);
      dialog->exec();
    });

  connect(ui->actionTerminate, &QAction::triggered,
          this, [&, node]() {
      auto index = ui->multiverseView->currentIndex();
      auto data = index.data(Qt::EditRole);
      if (data.metaType().id() == qMetaTypeId<QSacnUniverse*>())
        {
          auto univ = data.value<QSacnUniverse*>();
          if (univ->isEditable())
            node->terminate(univ->number());
        }
    });

  connect(ui->actionSubscribe, &QAction::triggered,
          this, [this, node]() {
      auto index = ui->multiverseView->currentIndex();
      auto actual = sortProxy->mapToSource(index);
      auto item = static_cast<MultiverseItem*>(actual.internalPointer());
      auto val = item->data(MultiverseModel::Column::Universe, Qt::DisplayRole);
      auto dialog = new AddUniverseDialog(this, val.toInt(),
                                          tr("Subscribe to Universe"));
      connect(dialog, &AddUniverseDialog::additionRequested,
              node, &QSacnNode::subscribe);
      dialog->exec();
    });

  connect(ui->actionUnsubscribe, &QAction::triggered,
          this, [&, node]() {
      auto index = ui->multiverseView->currentIndex();
      auto data = index.data(Qt::EditRole);
      if (data.metaType().id() == qMetaTypeId<QSacnUniverse*>())
        {
          auto univ = data.value<QSacnUniverse*>();
          if (!univ->isEditable())
            node->unsubscribe(univ->number());
        }
    });

  connect(ui->multiverseView->selectionModel(),
          &QItemSelectionModel::currentChanged,
          this, &MultiverseView::selectionChanged);
}


/**
 * @brief MultiverseView::~MultiverseView
 */
MultiverseView::~MultiverseView()
{
  delete ui;
}


/**
 * @brief MultiverseView::selectionChanged
 * @param selected
 * @param deselected
 */
void MultiverseView::selectionChanged(const QModelIndex &current,
                                      const QModelIndex &previous)
{
  Q_UNUSED(previous)

  ui->actionTerminate->setEnabled(false);
  ui->actionUnsubscribe->setEnabled(false);
  ui->actionInspect->setEnabled(false);

  auto data = current.data(Qt::EditRole);

  // Data universes:
  if (data.metaType().id() == qMetaTypeId<QSacnUniverse*>())
    {
      ui->actionInspect->setEnabled(true);
      auto univ = data.value<QSacnUniverse*>();
      if (univ->isEditable())
        ui->actionTerminate->setEnabled(true);
      else
        ui->actionUnsubscribe->setEnabled(true);
      return;
    }
}


/**
 * @brief MultiverseView::multiverseContextMenu
 * @param pos
 */
void MultiverseView::createContextMenu(const QPoint &pos)
{
  QMenu menu(ui->multiverseView);

  auto globalpos = ui->multiverseView->mapToGlobal(pos);
  auto index = ui->multiverseView->indexAt(pos);
  auto data = index.data(Qt::EditRole);

  // Data universes:
  if (data.metaType().id() == qMetaTypeId<QSacnUniverse*>())
    {
      menu.addAction(ui->actionInspect);
      menu.addSeparator();
      auto univ = data.value<QSacnUniverse*>();
      if (univ->isEditable())
        menu.addAction(ui->actionTerminate);
      else
        menu.addAction(ui->actionUnsubscribe);
      menu.exec(globalpos);
      return;
    }

  // Discovery universes:
  if (data.metaType().id() ==
                  qMetaTypeId<sACN::EXTENDED::DISCOVERY::discoveredUniverse*>())
    {
      menu.addAction(ui->actionSubscribe);
      menu.exec(globalpos);
      return;
    }
}


/**
 * @brief MultiverseView::createEditor
 * @param index
 */
void MultiverseView::createEditor(const QModelIndex &index)
{
  auto data = index.data(Qt::EditRole);

  // Data universes:
  if (data.metaType().id() == qMetaTypeId<QSacnUniverse*>())
    {
      auto univ = data.value<QSacnUniverse*>();
      auto universeView = new UniverseView(nullptr, univ);
      universeView->show();
    }

  // Discovery universes:
  if (data.metaType().id() ==
                 qMetaTypeId<sACN::EXTENDED::DISCOVERY::discoveredUniverse*>())
    {
      auto disc = data.value<sACN::EXTENDED::DISCOVERY::discoveredUniverse*>();
      auto subscribe = new AddUniverseDialog(this, disc->universe,
                                             tr("Subscribe to Universe"));
      connect(subscribe, &AddUniverseDialog::additionRequested,
              node, &QSacnNode::subscribe);
      subscribe->exec();
    }
}
