text: #include "masternodemanager.h"
  #include "ui_masternodemanager.h"
  #include "addeditadrenalinenode.h"
  #include "adrenalinenodeconfigdialog.h"
  
  #include "sync.h"
  #include "clientmodel.h"
  #include "walletmodel.h"
  #include "activemasternode.h"
  #include "masternodeconfig.h"
  #include "masternode.h"
  #include "walletdb.h"
  #include "wallet.h"
  #include "init.h"
  
  #include <QAbstractItemDelegate>
  #include <QPainter>
  #include <QTimer>
  #include <QDebug>
  #include <QScrollArea>
  #include <QScroller>
  #include <QDateTime>
  #include <QApplication>
  #include <QClipboard>
  #include <QMessageBox>
  
  MasternodeManager::MasternodeManager(QWidget *parent) :
      QWidget(parent),
      ui(new Ui::MasternodeManager),
      clientModel(0),
      walletModel(0)
  {
      ui->setupUi(this);
  
      ui->editButton->setVisible(false); // NTRN: hide this button for now
  
      ui->editButton->setEnabled(false);
      ui->getConfigButton->setEnabled(false);
      ui->startButton->setEnabled(false);
      ui->stopButton->setEnabled(false);
      ui->copyAddressButton->setEnabled(false);
  
      ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
      ui->tableWidget_2->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
  
      subscribeToCoreSignals();
  }
  
  MasternodeManager::~MasternodeManager()
  {
      delete ui;
  }
  
  static void NotifyAdrenalineNodeUpdated(MasternodeManager *page, CAdrenalineNodeConfig nodeConfig)
  {
      // alias, address, privkey, collateral address
      QString alias = QString::fromStdString(nodeConfig.sAlias);
      QString addr = QString::fromStdString(nodeConfig.sAddress);
      QString privkey = QString::fromStdString(nodeConfig.sMasternodePrivKey);
      QString collateral = QString::fromStdString(nodeConfig.sCollateralAddress);
  
      QMetaObject::invokeMethod(page, "updateAdrenalineNode", Qt::QueuedConnection,
                                Q_ARG(QString, alias),
                                Q_ARG(QString, addr),
                                Q_ARG(QString, privkey),
                                Q_ARG(QString, collateral)
                                );
  }
  
  void MasternodeManager::subscribeToCoreSignals()
  {
      // Connect signals to core
      uiInterface.NotifyAdrenalineNodeChanged.connect(boost::bind(&NotifyAdrenalineNodeUpdated, this, _1));
  }
  
  void MasternodeManager::unsubscribeFromCoreSignals()
  {
      // Disconnect signals from core
      uiInterface.NotifyAdrenalineNodeChanged.disconnect(boost::bind(&NotifyAdrenalineNodeUpdated, this, _1));
  }
  
  void MasternodeManager::on_tableWidget_2_itemSelectionChanged()
  {
      if(ui->tableWidget_2->selectedItems().count() > 0)
      {
          ui->editButton->setEnabled(false);
          ui->getConfigButton->setEnabled(true);
          ui->startButton->setEnabled(true);
          ui->stopButton->setEnabled(true);
          ui->copyAddressButton->setEnabled(true);
      }
  }
  
  void MasternodeManager::updateAdrenalineNode(QString alias, QString addr, QString privkey, QString collateral)
  {
      LOCK(cs_adrenaline);
  
      bool bFound = false;
      int nodeRow = 0;
      for(int i=0; i < ui->tableWidget_2->rowCount(); i++)
      {
          if(ui->tableWidget_2->item(i, 0)->text() == alias)
          {
              bFound = true;
              nodeRow = i;
              break;
          }
      }
  
      ui->tableWidget_2->setSortingEnabled(false);
  
      if(nodeRow == 0 && !bFound)
          ui->tableWidget_2->insertRow(0);
  
      QTableWidgetItem *aliasItem = new QTableWidgetItem(alias);
      QTableWidgetItem *addrItem = new QTableWidgetItem(addr);
      QTableWidgetItem *statusItem = new QTableWidgetItem("");
      QTableWidgetItem *collateralItem = new QTableWidgetItem(collateral);
  
      ui->tableWidget_2->setItem(nodeRow, 0, aliasItem);
      ui->tableWidget_2->setItem(nodeRow, 1, addrItem);
      ui->tableWidget_2->setItem(nodeRow, 2, statusItem);
      ui->tableWidget_2->setItem(nodeRow, 3, collateralItem);
  
      ui->tableWidget_2->setSortingEnabled(true);
  }
  
  static QString seconds_to_DHMS(quint32 duration)
  {
    QString res;
    int seconds = (int) (duration % 60);
    duration /= 60;
    int minutes = (int) (duration % 60);
    duration /= 60;
    int hours = (int) (duration % 24);
    int days = (int) (duration / 24);
    if((hours == 0)&&(days == 0))
        return res.sprintf("%02dm:%02ds", minutes, seconds);
    if (days == 0)
        return res.sprintf("%02dh:%02dm:%02ds", hours, minutes, seconds);
    return res.sprintf("%dd %02dh:%02dm:%02ds", days, hours, minutes, seconds);
  }
  
  void MasternodeManager::updateMyNodeList()
  {
      TRY_LOCK(cs_adrenaline, lockMasternodes);
      if(!lockMasternodes) {
          return;
      }
  
      if(pwalletMain)
      {
          BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
          {
              updateAdrenalineNode(QString::fromStdString(adrenaline.second.sAlias), QString::fromStdString(adrenaline.second.sAddress), QString::fromStdString(adrenaline.second.sMasternodePrivKey), QString::fromStdString(adrenaline.second.sCollateralAddress));
          }
      }
  }
  
  void MasternodeManager::updateNodeList()
  {
      TRY_LOCK(cs_masternodes, lockMasternodes);
      if(!lockMasternodes)
          return;
  
      ui->countLabel->setText("Updating...");
      ui->tableWidget->setSortingEnabled(false);
      ui->tableWidget->clearContents();
      ui->tableWidget->setRowCount(0);
  
      BOOST_FOREACH(CMasternode& mn, vecMasternodes)
      {
          // populate list
          // Address, Rank, Active, Active Seconds, Last Seen, Pub Key
          QTableWidgetItem *activeItem = new QTableWidgetItem(QString::number(mn.IsEnabled()));
          QTableWidgetItem *addressItem = new QTableWidgetItem(QString::fromStdString(mn.addr.ToString()));
          QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(mn.protocolVersion));
          QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(seconds_to_DHMS((qint64)(mn.lastTimeSeen - mn.now)));
          QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat(mn.lastTimeSeen)));
  
          CScript pubkey;
          pubkey =GetScriptForDestination(mn.pubkey.GetID());
          CTxDestination address1;
          ExtractDestination(pubkey, address1);
          CBitcoinAddress address2(address1);
          QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(address2.ToString()));
  
          ui->tableWidget->insertRow(0);
          ui->tableWidget->setItem(0, 0, addressItem);
          ui->tableWidget->setItem(0, 1, protocolItem);
          ui->tableWidget->setItem(0, 2, activeItem);
          ui->tableWidget->setItem(0, 3, activeSecondsItem);
          ui->tableWidget->setItem(0, 4, lastSeenItem);
          ui->tableWidget->setItem(0, 5, pubkeyItem);
      }
  
      ui->countLabel->setText(QString::number(ui->tableWidget->rowCount()));
      ui->tableWidget->setSortingEnabled(true);
  }
  
  
  void MasternodeManager::setClientModel(ClientModel *model)
  {
      this->clientModel = model;
      if(model)
      {
          updateMyNodeList();
          connect(clientModel, SIGNAL(strMasternodesChanged(QString)), this, SLOT(updateMyNodeList()));
  
          updateNodeList();
          connect(clientModel, SIGNAL(strMasternodesChanged(QString)), this, SLOT(updateNodeList()));
      }
  }
  
  void MasternodeManager::setWalletModel(WalletModel *model)
  {
      this->walletModel = model;
      if(model && model->getOptionsModel())
      {
      }
  
  }
  
  void MasternodeManager::on_createButton_clicked()
  {
      AddEditAdrenalineNode* aenode = new AddEditAdrenalineNode();
      aenode->exec();
  }
  
  void MasternodeManager::on_copyAddressButton_clicked()
  {
      QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
      if(selected.count() == 0)
          return;
  
      QModelIndex index = selected.at(0);
      int r = index.row();
      std::string sCollateralAddress = ui->tableWidget_2->item(r, 3)->text().toStdString();
  
      QApplication::clipboard()->setText(QString::fromStdString(sCollateralAddress));
  }
  
  void MasternodeManager::on_editButton_clicked()
  {
      QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
      if(selected.count() == 0)
          return;
  
      QModelIndex index = selected.at(0);
      int r = index.row();
      std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
  
      // get existing config entry
  
  }
  
  void MasternodeManager::on_getConfigButton_clicked()
  {
      QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
      if(selected.count() == 0)
          return;
  
      QModelIndex index = selected.at(0);
      int r = index.row();
      std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
      CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
      std::string sPrivKey = c.sMasternodePrivKey;
      AdrenalineNodeConfigDialog* d = new AdrenalineNodeConfigDialog(this, QString::fromStdString(sAddress), QString::fromStdString(sPrivKey));
      d->exec();
  }
  
  void MasternodeManager::on_removeButton_clicked()
  {
      QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
      if(selected.count() == 0)
          return;
  
      QMessageBox::StandardButton confirm;
      confirm = QMessageBox::question(this, "Delete Nucleus Node?", "Are you sure you want to delete this nucleus node configuration?", QMessageBox::Yes|QMessageBox::No);
  
      if(confirm == QMessageBox::Yes)
      {
          QModelIndex index = selected.at(0);
          int r = index.row();
          std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
          CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
          CWalletDB walletdb(pwalletMain->strWalletFile);
          pwalletMain->mapMyAdrenalineNodes.erase(sAddress);
          walletdb.EraseAdrenalineNodeConfig(c.sAddress);
          ui->tableWidget_2->clearContents();
          ui->tableWidget_2->setRowCount(0);
          BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
          {
              updateAdrenalineNode(QString::fromStdString(adrenaline.second.sAlias), QString::fromStdString(adrenaline.second.sAddress), QString::fromStdString(adrenaline.second.sMasternodePrivKey), QString::fromStdString(adrenaline.second.sCollateralAddress));
          }
      }
  }
  
  void MasternodeManager::on_startButton_clicked()
  {
      if (ui->tableWidget_2->rowCount() == 0)
          return;
      // start the node
      QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
      if(selected.count() == 0)
          return;
  
      QModelIndex index = selected.at(0);
      int r = index.row();
      std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
      CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
  
      std::string errorMessage;
      bool result = activeMasternode.RegisterByPubKey(c.sAddress, c.sMasternodePrivKey, c.sCollateralAddress, errorMessage);
      QMessageBox msg;
  
      if(result) {
          msg.setText("Nucleus Node at " + QString::fromStdString(c.sAddress) + " started.");
      } else {
          msg.setText("Error: " + QString::fromStdString(errorMessage));
      }
  
      msg.exec();
  }
  
  void MasternodeManager::on_stopButton_clicked()
  {
      if (ui->tableWidget_2->rowCount() == 0)
          return;
      // start the node
      QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
      QModelIndexList selected = selectionModel->selectedRows();
      if(selected.count() == 0)
          return;
  
      QModelIndex index = selected.at(0);
      int r = index.row();
      std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
      CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
  
      std::string errorMessage;
      bool result = activeMasternode.StopMasterNode(c.sAddress, c.sMasternodePrivKey, errorMessage);
      QMessageBox msg;
  
      if(result) {
          msg.setText("Nucleus Node at " + QString::fromStdString(c.sAddress) + " stopped.");
      }
      else {
          msg.setText("Error: " + QString::fromStdString(errorMessage));
      }
      msg.exec();
  }
  
  void MasternodeManager::on_startAllButton_clicked()
  {
      if (ui->tableWidget_2->rowCount() == 0)
          return;
      std::string results;
      BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
      {
          CAdrenalineNodeConfig c = adrenaline.second;
          std::string errorMessage;
          bool result = activeMasternode.RegisterByPubKey(c.sAddress, c.sMasternodePrivKey, c.sCollateralAddress, errorMessage);
  
          if(result) {
              results += c.sAddress + ": STARTED\n";
          }
          else {
              results += c.sAddress + ": ERROR: " + errorMessage + "\n";
          }
      }
  
      QMessageBox msg;
      msg.setText(QString::fromStdString(results));
      msg.exec();
  }
  
  void MasternodeManager::on_stopAllButton_clicked()
  {
      if (ui->tableWidget_2->rowCount() == 0)
          return;
  
      std::string results;
      BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
      {
          CAdrenalineNodeConfig c = adrenaline.second;
          std::string errorMessage;
          bool result = activeMasternode.StopMasterNode(c.sAddress, c.sMasternodePrivKey, errorMessage);
  
          if(result) {
              results += c.sAddress + ": STOPPED\n";
          }
          else {
              results += c.sAddress + ": ERROR: " + errorMessage + "\n";
          }
      }
  
      QMessageBox msg;
      msg.setText(QString::fromStdString(results));
      msg.exec();
  }
  
  void MasternodeManager::on_UpdateButton_clicked()
  {
      updateMyNodeList();
      updateNodeList();
  }
  