//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================
#include "smtk/session/rgg/plugin/smtkRGGEditDuctView.h"
#include "smtk/session/rgg/plugin/ui_smtkRGGEditDuctParameters.h"

#include "smtkRGGViewHelper.h"

#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/DoubleItem.h"
#include "smtk/attribute/GroupItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/ReferenceItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/attribute/VoidItem.h"

#include "smtk/extension/qt/qtAttribute.h"
#include "smtk/extension/qt/qtBaseAttributeView.h"
#include "smtk/extension/qt/qtItem.h"
#include "smtk/extension/qt/qtUIManager.h"

#include "smtk/io/Logger.h"

#include "smtk/model/AuxiliaryGeometry.h"
#include "smtk/model/Resource.h"

#include "smtk/session/rgg/Core.h"
#include "smtk/session/rgg/Duct.h"

#include "smtk/session/rgg/json/jsonCore.h"
#include "smtk/session/rgg/json/jsonDuct.h"

#include "smtk/session/rgg/operators/CreateModel.h"
#include "smtk/session/rgg/operators/EditDuct.h"

#include "smtk/view/Configuration.h"

#include "pqActiveObjects.h"
#include "pqApplicationCore.h"
#include "pqPresetDialog.h"
#include "pqRenderView.h"
#include "pqServer.h"
#include "pqSettings.h"

#include <QComboBox>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>

using namespace smtk::model;
using namespace smtk::extension;
using namespace smtk::session::rgg;
using json = nlohmann::json;
using rggDuct = smtk::session::rgg::Duct;

constexpr int numberOfSegmentTableColumns = 2;

class smtkRGGEditDuctViewInternals : public Ui::RGGEditDuctParameters
{
public:
  smtkRGGEditDuctViewInternals() {}

  ~smtkRGGEditDuctViewInternals()
  {
    if (CurrentAtt)
      delete CurrentAtt;
  }

  qtAttribute* createAttUI(smtk::attribute::AttributePtr att, QWidget* pw, qtBaseView* view)
  {
    if (att && att->numberOfItems() > 0)
    {
      const smtk::view::Configuration::Component comp;
      qtAttribute* attInstance = new qtAttribute(att, comp, pw, view);
      if (attInstance && attInstance->widget())
      {
        //Without any additional info lets use a basic layout with model associations
        // if any exists
        attInstance->createBasicLayout(true);
        attInstance->widget()->setObjectName("RGGDuctEditor");
        QVBoxLayout* parentlayout = static_cast<QVBoxLayout*>(pw->layout());
        parentlayout->insertWidget(0, attInstance->widget());
      }
      return attInstance;
    }
    return nullptr;
  }

  QPointer<qtAttribute> CurrentAtt;

  smtk::model::Model CurrentModel;
};

smtkRGGEditDuctView::smtkRGGEditDuctView(const smtk::view::Information& info)
  : qtBaseAttributeView(info)
{
  this->Internals = new smtkRGGEditDuctViewInternals();
}

smtkRGGEditDuctView::~smtkRGGEditDuctView()
{
  delete this->Internals;
}

const smtk::operation::OperationPtr& smtkRGGEditDuctView::operation() const
{
  return m_viewInfo.get<smtk::operation::OperationPtr>();
}

qtBaseView* smtkRGGEditDuctView::createViewWidget(const smtk::view::Information& info)
{
  smtkRGGEditDuctView* view = new smtkRGGEditDuctView(info);
  view->buildUI();
  return view;
}

void smtkRGGEditDuctView::valueChanged(smtk::attribute::ItemPtr /*optype*/)
{
  this->requestOperation(this->operation());
}

void smtkRGGEditDuctView::requestOperation(const smtk::operation::OperationPtr& op)
{
  if (!op || !op->parameters())
  {
    return;
  }
  op->operate();
}

void smtkRGGEditDuctView::attributeModified()
{
  // Always enable apply button here
}

void smtkRGGEditDuctView::onAttItemModified(smtk::extension::qtItem* item)
{
  smtk::attribute::ItemPtr itemPtr = item->item();
  // only changing duct would update edit duct panel
  std::cout << "Item modified! " << itemPtr->name() << " " << itemPtr->typeName() <<std::endl;
  if (itemPtr->name() == "model/duct" &&
      itemPtr->type() == smtk::attribute::Item::Type::ReferenceType)
  {
    this->updateEditDuctPanel();
  }
}

void smtkRGGEditDuctView::apply()
{
  // Fill the attribute - read all data from UI
  Duct duct;
  duct.setName(this->Internals->ductName->text().toStdString());

  duct.setCutAway(this->Internals->isCrossSectionButton->isChecked());

  QTableWidget* dst = this->Internals->ductSegmentTable;
  std::vector<Duct::Segment> segments;
  for (int i = 0; i < dst->rowCount(); i++)
  {
    Duct::Segment seg;
    // Fill z values first
    // FIXME: Is it right?
    seg.baseZ = dst->item(i, 0)->text().toDouble();
    seg.height = dst->item(i, 1)->text().toDouble() - dst->item(i, 0)->text().toDouble();

    QTableWidget* mlt = dynamic_cast<QTableWidget*>(
          this->Internals->materialLayerStack->widget(i));
    for (int j = 0; j < mlt->rowCount(); j++)
    {
      int materialIndex = dynamic_cast<QComboBox*>(mlt->cellWidget(j, 0))->currentIndex();
      double radiusN1 = mlt->item(j, 1)->text().toDouble();
      if (this->Internals->ductPitchX->isHidden())
      {
        seg.layers.push_back(std::make_tuple(materialIndex, radiusN1, radiusN1));
      }
      else
      {
        double radiusN2 = mlt->item(j, 2)->text().toDouble();
        seg.layers.push_back(std::make_tuple(materialIndex, radiusN1, radiusN2));
      }
    }
    segments.push_back(seg);
  }
  duct.setSegments(segments);
  json ductJson = duct;
  std::string ductStr = ductJson.dump();

  smtk::attribute::AttributePtr att = this->Internals->CurrentAtt->attribute();
  att->findString("duct representation")->setValue(ductStr);

  this->requestOperation(this->operation());
}

void smtkRGGEditDuctView::updateUI()
{
  smtk::view::ConfigurationPtr view = this->configuration();
  if (!view || !this->Widget)
  {
    return;
  }

  if (this->Internals->CurrentAtt)
  {
    delete this->Internals->CurrentAtt;
  }

  int i = view->details().findChild("AttributeTypes");
  if (i < 0)
  {
    return;
  }
  smtk::view::Configuration::Component& comp = view->details().child(i);
  std::string defName;
  for (std::size_t ci = 0; ci < comp.numberOfChildren(); ++ci)
  {
    smtk::view::Configuration::Component& attComp = comp.child(ci);
    if (attComp.name() != "Att")
    {
      continue;
    }
    std::string optype;
    if (attComp.attribute("Type", optype) && !optype.empty())
    {
      if (optype == "edit duct")
      {
        defName = optype;
        break;
      }
    }
  }
  if (defName.empty())
  {
    return;
  }

  smtk::attribute::AttributePtr att = this->operation()->parameters();
  this->Internals->CurrentAtt = this->Internals->createAttUI(att, this->Widget, this);
  if (this->Internals->CurrentAtt)
  {
    QObject::connect(this->Internals->CurrentAtt, &qtAttribute::itemModified, this,
      &smtkRGGEditDuctView::onAttItemModified);
    this->updateEditDuctPanel();
  }
}

void smtkRGGEditDuctView::createWidget()
{
  smtk::view::ConfigurationPtr view = this->configuration();
  if (!view)
  {
    return;
  }

  QVBoxLayout* parentLayout = dynamic_cast<QVBoxLayout*>(this->parentWidget()->layout());

  // Delete any pre-existing widget
  if (this->Widget)
  {
    if (parentLayout)
    {
      parentLayout->removeWidget(this->Widget);
    }
    delete this->Widget;
  }

  // Create a new frame and lay it out
  this->Widget = new QFrame(this->parentWidget());
  QVBoxLayout* layout = new QVBoxLayout(this->Widget);
  layout->setMargin(0);
  this->Widget->setLayout(layout);
  this->Widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);

  // QUESTION: You might need to keep tracking of the widget
  QWidget* tempWidget = new QWidget(this->parentWidget());
  this->Internals->setupUi(tempWidget);
  tempWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
  layout->addWidget(tempWidget, 1);
  // Make sure that we have enough space for the custom widget
  this->Internals->scrollArea->setMinimumHeight(800);

  // Duct height is modified at core level
  this->Internals->z1LineEdit->setEnabled(false);
  this->Internals->z2LineEdit->setEnabled(false);

  QObject::connect(this->Internals->isHexButton, &QCheckBox::stateChanged, this, [=](int status) {
    this->Internals->ductPitchX->setHidden(status);
    this->Internals->ductPitchXLabel->setHidden(status);
    // Always show pitch y lineEdit widget
    this->Internals->ductPitchY->setToolTip(
      QString::fromStdString(status ? "Hex duct's pitch" : "Rect duct's pitch along y axis"));
    this->Internals->ductPitchYLabel->setHidden(status);
  });
  this->Internals->ductPitchX->setToolTip(QString::fromStdString("Rect duct's pitch along x axis"));

  this->createDuctSegmentsTable();
  // Material layers buttons
  QObject::connect(this->Internals->addMaterialLayerBefore, &QPushButton::released, this,
    &smtkRGGEditDuctView::onAddMaterialLayerBefore);
  QObject::connect(this->Internals->addMaterialLayerAfter, &QPushButton::released, this,
    &smtkRGGEditDuctView::onAddMaterialLayerAfter);
  QObject::connect(this->Internals->deleteMaterialLayer, &QPushButton::released, this,
    &smtkRGGEditDuctView::onDeleteMaterialLayer);

  // Show help when the info button is clicked.
  QObject::connect(
    this->Internals->infoButton, &QPushButton::released, this, &smtkRGGEditDuctView::onInfo);

  QObject::connect(
    this->Internals->applyButton, &QPushButton::released, this, &smtkRGGEditDuctView::apply);

  this->updateUI();
}

void smtkRGGEditDuctView::updateEditDuctPanel()
{
  smtk::model::EntityRefArray ents = this->Internals->CurrentAtt->attribute()
                                       ->associatedModelEntities<smtk::model::EntityRefArray>();
  bool isEnabled(true);
  if ((ents.size() == 0) ||
      // Not a valid rgg duct nor model
      (((!ents[0].hasStringProperty("rggType")) ||
    (ents[0].stringProperty("rggType")[0] != smtk::session::rgg::Duct::typeDescription) ||
    (!ents[0].embeddedEntities<smtk::model::EntityRefArray>().size())) &&
      !ents[0].isModel()))
  { // Its type is not rgg duct
    isEnabled = false;
  }
  if (this->Internals)
  {
    this->Internals->scrollArea->setEnabled(isEnabled);
  }

  if (isEnabled)
  {
    smtk::model::Model model = ents[0].isModel() ?
          ents[0].as<smtk::model::Model>() : ents[0].owningModel();
    if (!this->Internals->CurrentModel.isValid())
    {
      this->Internals->CurrentModel = model;
    }
    Duct duct = ents[0].isModel() ? Duct() : Duct(json::parse(
                                                    ents[0].stringProperty(rggDuct::propDescription)[0]));

    // Since duct properties are defined at core level, find the core from resource
    // then use its info to populate the panel.
    EntityRefArray coreArray =
        model.resource()->findEntitiesByProperty("rggType", Core::typeDescription);
    if (coreArray.size() != 1)
    {
      smtkErrorMacro(smtk::io::Logger::instance(), "Failed to find the core group");
      return;
    }
    EntityRef coreGroup = coreArray[0];
    Core core = json::parse(coreGroup.stringProperty(Core::propDescription)[0]);
    bool isHex = core.geomType() == Core::GeomType::Hex;
    if (ents[0].isModel())
    { // Populate the init segment if the assocation is a model
      Duct::Segment initialSegment;
      initialSegment.baseZ = core.zOrigin();
      initialSegment.height = core.height();
      // No material, single layer
      initialSegment.layers.push_back(std::make_tuple(0, 1.0, 1.0));
      duct.setSegments({initialSegment});
    }

    // Populate the panel
    // Name
    this->Internals->ductName->setText(QString::fromStdString(duct.name()));

    // IsHex
    this->Internals->isHexButton->setEnabled(true);
    this->Internals->isHexButton->setChecked(isHex);
    // isHex would have an impact on pitch options.
    // For now it's specified at core creation time
    this->Internals->isHexButton->setEnabled(false);

    this->Internals->isCrossSectionButton->setChecked(duct.isCutAway());

    auto ductPitch = core.ductThickness();
    if (isHex)
    { // Since hex pitch has two same values, we only show one
      this->Internals->ductPitchY->setText(QString::number(ductPitch.first));
    }
    else
    {
      this->Internals->ductPitchX->setText(QString::number(ductPitch.first));
      this->Internals->ductPitchY->setText(QString::number(ductPitch.second));
    }

    // Duct height
    this->Internals->z1LineEdit->setText(QString::number(core.zOrigin()));
    this->Internals->z2LineEdit->setText(QString::number(core.height()));

    // Clear the duct segment table first then populate it
    this->Internals->ductSegmentTable->clearSpans();
    this->Internals->ductSegmentTable->model()->removeRows(
      0, this->Internals->ductSegmentTable->rowCount());
    const auto& segments = duct.segments();
    for (size_t index = 0; index < segments.size(); index++)
    {
      this->addSegmentToTable(static_cast<int>(index),segments[index].baseZ,
                              segments[index].baseZ + segments[index].height);
    }

    // Clear the material layer stack widget first
    while (this->Internals->materialLayerStack->count() > 0)
    {
      QWidget* tmp = this->Internals->materialLayerStack->widget(
        this->Internals->materialLayerStack->count() - 1);
      this->Internals->materialLayerStack->removeWidget(tmp);
    }
    // Populate the material layer tables
    for (size_t index = 0; index < segments.size(); index++)
    {
      this->createMaterialLayersTable(static_cast<int>(index), segments[index].layers);
    }
    this->Internals->materialLayerStack->setCurrentIndex(0);
  }
  this->updateButtonStatus();
}

void smtkRGGEditDuctView::setInfoToBeDisplayed()
{
  this->m_infoDialog->displayInfo(this->configuration());
}

void smtkRGGEditDuctView::createDuctSegmentsTable()
{
  QTableWidget* dsT = this->Internals->ductSegmentTable;
  dsT->clear();
  dsT->horizontalHeader()->setStretchLastSection(true);
  dsT->setColumnCount(numberOfSegmentTableColumns);
  dsT->setHorizontalHeaderLabels(QStringList() << "Z1"
                                               << "Z2");

  // Split
  QObject::connect(
    this->Internals->segSplit, &QPushButton::pressed, this, &smtkRGGEditDuctView::onSegmentSplit);

  // Delete up
  QObject::connect(this->Internals->segDeleteUp, &QPushButton::pressed, this, [=]() {
    QTableWidget* dst = this->Internals->ductSegmentTable;
    // If there is no selected item then the button would be disabled. we can
    // safely ask for the 1st item
    QTableWidgetItem* selected = dst->selectedItems().value(0);
    int currentRow = selected->row();
    if (currentRow)
    {
      dst->blockSignals(true);
      dst->removeRow(currentRow - 1);
      dst->blockSignals(false);
    }
    if (currentRow == 1)
    { // Update the lower bound
      dst->item(0, 0)->setText(this->Internals->z1LineEdit->text());
    }
    // Remove the corresponding table widget
    this->Internals->materialLayerStack->removeWidget(
      this->Internals->materialLayerStack->widget(currentRow - 1));
    this->updateButtonStatus();

  });

  // Delete down
  QObject::connect(this->Internals->segDeleteDown, &QPushButton::pressed, this, [=]() {
    QTableWidget* dst = this->Internals->ductSegmentTable;
    // If there is no selected item then the button would be disabled. we can
    // safely ask for the 1st item
    QTableWidgetItem* selected = dst->selectedItems().value(0);
    int currentRow = selected->row(), rowC = dst->rowCount();
    if (currentRow < (rowC - 1))
    {
      dst->blockSignals(true);
      dst->removeRow(currentRow + 1);
      dst->blockSignals(false);
    }
    else
    {
      return;
    }
    if (currentRow == (rowC - 2))
    { // Update the lower bound
      dst->item(dst->rowCount() - 1, 1)->setText(this->Internals->z2LineEdit->text());
    }
    // Remove the corresponding table widget
    this->Internals->materialLayerStack->removeWidget(
      this->Internals->materialLayerStack->widget(currentRow + 1));
    this->updateButtonStatus();
  });

  // Selection
  QObject::connect(this->Internals->ductSegmentTable, &QTableWidget::itemSelectionChanged, this,
    &smtkRGGEditDuctView::updateButtonStatus);
  // Bring up the material layer table associated with current row
  QObject::connect(
    this->Internals->ductSegmentTable, &QTableWidget::itemSelectionChanged, this, [=]() {
      int row = this->Internals->ductSegmentTable->currentRow();
      this->Internals->materialLayerStack->setCurrentIndex(row);
    });
}

void smtkRGGEditDuctView::addSegmentToTable(int row, double z1, double z2)
{
  QTableWidget* dst = this->Internals->ductSegmentTable;
  if (row < 0 || row > dst->rowCount())
  { // invalid input
    return;
  }
  dst->blockSignals(true);
  dst->insertRow(row);
  // z1
  QTableWidgetItem* z1Item = new dSTableItem();
  z1Item->setText(QString::number(z1));
  dst->setItem(row, 0, z1Item);
  // z2
  QTableWidgetItem* z2Item = new dSTableItem();
  z2Item->setText(QString::number(z2));
  dst->setItem(row, 1, z2Item);
  dst->blockSignals(false);
  this->updateButtonStatus();
}

void smtkRGGEditDuctView::onSegmentSplit()
{
  QTableWidget* dst = this->Internals->ductSegmentTable;
  // If there is no selected item then the buttons would be disabled. we can
  // safely ask for the 1st item
  QTableWidgetItem* selected = dst->selectedItems().value(0);
  QTableWidgetItem* z1 = dst->item(selected->row(), 0);
  QTableWidgetItem* z2 = dst->item(selected->row(), 1);
  // Calcuate average and update z1
  double min(z1->text().toDouble()), max(z2->text().toDouble()), average = (min + max) / 2;
  z1->setText(QString::number(average));
  this->addSegmentToTable(selected->row(), min, average);
  // Create the corresponding material table based on selected row
  std::vector<layer> layers;
  // Extract the info from current material layers table
  QTableWidget* mlt =
    dynamic_cast<QTableWidget*>(this->Internals->materialLayerStack->currentWidget());
  for (int i = 0; i < mlt->rowCount(); i++)
  {
    QComboBox* box = dynamic_cast<QComboBox*>(mlt->cellWidget(i, 0));
    int materialIndex = box ? box->currentIndex() : 0;
    if (this->Internals->ductPitchX->isHidden())
    { // Hex
      layers.push_back(std::make_tuple(materialIndex, mlt->item(i, 1)->text().toDouble(),
                                       mlt->item(i, 1)->text().toDouble()));
    }
    else
    {
      layers.push_back(std::make_tuple(materialIndex, mlt->item(i, 1)->text().toDouble(),
                                       mlt->item(i, 2)->text().toDouble()));
    }
  }
  this->createMaterialLayersTable(selected->row(), layers);
}

void smtkRGGEditDuctView::createMaterialLayersTable(const int index, const std::vector<layer>& layers)
{
  // Create the table widget
  QTableWidget* mlt = new QTableWidget;
  // Selection
  QObject::connect(
    mlt, &QTableWidget::itemSelectionChanged, this, &smtkRGGEditDuctView::updateButtonStatus);

  if (this->Internals->ductPitchX->isHidden())
  { // If we hide the ductPitchX then it's a hex duct.
    mlt->setColumnCount(2);
    mlt->setHorizontalHeaderLabels(QStringList() << "Material"
                                                 << "Radius\n(normalized)");
  }
  else
  {
    mlt->setColumnCount(3);
    mlt->setHorizontalHeaderLabels(QStringList() << "Material"
                                                 << "Radius\n(normalized)"
                                                 << "Radius\n(normalized)");
  }
  mlt->horizontalHeader()->setStretchLastSection(true);
  // Hard code a value so that the widget is align with the table
  mlt->horizontalHeader()->setMinimumSectionSize(180);
  mlt->setSelectionBehavior(QAbstractItemView::SelectRows);

  for (size_t mI = 0; mI < layers.size(); mI++)
  {
    const auto& layer = layers[mI];
    this->addMaterialLayerToTable(mlt, static_cast<int>(mI), std::get<0>(layer),
                                  std::get<1>(layer), std::get<2>(layer));
  }

  this->Internals->materialLayerStack->insertWidget(static_cast<int>(index), mlt);
}

void smtkRGGEditDuctView::onAddMaterialLayerBefore()
{
  QTableWidget* mlt =
    dynamic_cast<QTableWidget*>(this->Internals->materialLayerStack->currentWidget());
  int row;
  if (mlt->selectedItems().count() != 0)
  {
    row = mlt->selectedItems()[0]->row();
  }
  else
  {
    return;
  }
  // generate the new thickness1 and thickness2
  double beforeTN0, afterTN0, beforeTN1, afterTN1, averageTN0, averageTN1;
  beforeTN0 = (row == 0) ? 0 : mlt->item(row - 1, 1)->text().toDouble();
  afterTN0 = mlt->item(row, 1)->text().toDouble();
  averageTN0 = (beforeTN0 + afterTN0) / 2;
  if (this->Internals->ductPitchX->isHidden())
  { // Hex has only one normalized thicknesses
    this->addMaterialLayerToTable(mlt, row, 0, averageTN0, averageTN0);
  }
  else
  {
    beforeTN1 = (row == 0) ? 0 : mlt->item(row - 1, 2)->text().toDouble();
    afterTN1 = mlt->item(row, 2)->text().toDouble();
    averageTN1 = (beforeTN1 + afterTN1) / 2;
    this->addMaterialLayerToTable(mlt, row, 0, averageTN0, averageTN1);
  }
  this->updateButtonStatus();
}

void smtkRGGEditDuctView::onAddMaterialLayerAfter()
{
  QTableWidget* mlt =
    dynamic_cast<QTableWidget*>(this->Internals->materialLayerStack->currentWidget());
  int row;
  if (mlt->selectedItems().count() != 0)
  {
    row = mlt->selectedItems()[0]->row();
  }
  else
  {
    return;
  }
  // generate the new thickness1 and thickness2
  double beforeTN0, afterTN0, beforeTN1, afterTN1, averageTN0, averageTN1;
  beforeTN0 = mlt->item(row, 1)->text().toDouble();
  if (row == (mlt->rowCount() - 1))
  { // Cannot add after the last item
    return;
  }
  afterTN0 = mlt->item(row + 1, 1)->text().toDouble();
  averageTN0 = (beforeTN0 + afterTN0) / 2;
  if (this->Internals->ductPitchX->isHidden())
  { // Hex has only one normalized thicknesses
    this->addMaterialLayerToTable(mlt, row, 0, averageTN0, averageTN0);
  }
  else
  {
    beforeTN1 = mlt->item(row, 2)->text().toDouble();
    afterTN1 = mlt->item(row + 1, 2)->text().toDouble();
    averageTN1 = (beforeTN1 + afterTN1) / 2;
    this->addMaterialLayerToTable(mlt, row + 1, 0, averageTN0, averageTN1);
  }
  this->updateButtonStatus();
}

void smtkRGGEditDuctView::onDeleteMaterialLayer()
{
  QTableWidget* mlt =
    dynamic_cast<QTableWidget*>(this->Internals->materialLayerStack->currentWidget());
  int row = mlt->currentRow();
  mlt->blockSignals(true);
  if (row == (mlt->rowCount() - 1))
  { // Upper bound of normalized radius should always be 1
    mlt->item(row - 1, 1)->setText(QString::number(1.0));
    if (!this->Internals->ductPitchX->isHidden())
    { // Rect duct has two different normalized thicknesses
      mlt->item(row - 1, 2)->setText(QString::number(1.0));
    }
  }
  mlt->removeRow(row);
  mlt->blockSignals(false);
  this->updateButtonStatus();
}

void smtkRGGEditDuctView::addMaterialLayerToTable(
  QTableWidget* mlt, int row, int subMaterial, double thickness1, double thickness2)
{
  mlt->blockSignals(true);
  mlt->insertRow(row);
  // Create the material combobox first
  QComboBox* materialCom = new QComboBox(mlt);
  materialCom->setObjectName("DuctMaterialBox_" + QString::number(row));
  mlt->setCellWidget(row, 0, materialCom);
  materialCom->blockSignals(true);
  this->setupMaterialComboBox(materialCom);
  materialCom->blockSignals(false);
  materialCom->setCurrentIndex(subMaterial);

  // Normalized thicknessnesses
  rangeItem* radiusNItem = new rangeItem();
  radiusNItem->setText(QString::number(thickness1));
  mlt->setItem(row, 1, radiusNItem);

  if (!this->Internals->ductPitchX->isHidden())
  { // For a rect duct, we have radius along length and width
    rangeItem* radiusNItem2 = new rangeItem();
    radiusNItem2->setText(QString::number(thickness2));
    mlt->setItem(row, 2, radiusNItem2);
  }
  mlt->blockSignals(false);
}

void smtkRGGEditDuctView::updateButtonStatus()
{
  bool deleteDuctStatus = this->Internals->ductSegmentTable->rowCount() > 1;
  this->Internals->segDeleteUp->setEnabled(deleteDuctStatus);
  this->Internals->segDeleteDown->setEnabled(deleteDuctStatus);
  if (this->Internals->ductSegmentTable->selectedItems().size() > 0)
  {
    this->Internals->segSplit->setEnabled(true);
    int row = this->Internals->ductSegmentTable->selectedItems()[0]->row();
    this->Internals->segDeleteUp->setEnabled((row != 0));
    this->Internals->segDeleteDown->setEnabled(
      (row != (this->Internals->ductSegmentTable->rowCount() - 1)));
  }
  else
  {
    this->Internals->segSplit->setEnabled(false);
  }

  QTableWidget* mlt =
    dynamic_cast<QTableWidget*>(this->Internals->materialLayerStack->currentWidget());
  bool deleteMaterialStatus(false), hasSelection(false), canAddAfter(false);
  if (mlt)
  {
    hasSelection = mlt->selectedItems().size() > 0;
    deleteMaterialStatus = (mlt->rowCount() > 1) && hasSelection;
    if (hasSelection)
    { // Can not add after the last row
      canAddAfter = mlt->selectedItems()[0]->row() != (mlt->rowCount() - 1);
    }
  }
  this->Internals->addMaterialLayerBefore->setEnabled(hasSelection);
  this->Internals->addMaterialLayerAfter->setEnabled(canAddAfter);
  this->Internals->deleteMaterialLayer->setEnabled(deleteMaterialStatus);
}

void smtkRGGEditDuctView::setupMaterialComboBox(QComboBox* box, bool isCell)
{
  box->clear();
  size_t matN = smtk::session::rgg::CreateModel::materialNum(this->Internals->CurrentModel);
  for (size_t i = 0; i < matN; i++)
  {
    std::string name = smtk::session::rgg::CreateModel::getMaterial(i,
                                                                    this->Internals->CurrentModel);
    box->addItem(QString::fromStdString(name));
  }
  if (isCell)
  {
    // In this condition, the part does not need to have a material. Change the item text
  }
}
