/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#include "QmitkSegmentationPreferencePage.h"

#include <mitkCoreServices.h>
#include <mitkIPreferencesService.h>
#include <mitkIPreferences.h>
#include <mitkLabelSuggestionHelper.h>

#include <mitkRenderingManager.h>

#include <QFileDialog>

#include <ui_QmitkSegmentationPreferencePageControls.h>

namespace
{
  mitk::IPreferences* GetPreferences()
  {
    auto* preferencesService = mitk::CoreServices::GetPreferencesService();
    return preferencesService->GetSystemPreferences()->Node("org.mitk.views.segmentation");
  }
}

QmitkSegmentationPreferencePage::QmitkSegmentationPreferencePage()
  : m_Ui(std::make_unique<Ui::QmitkSegmentationPreferencePageControls>()),
    m_Control(nullptr),
    m_Initializing(false)
{
}

QmitkSegmentationPreferencePage::~QmitkSegmentationPreferencePage()
{
}

void QmitkSegmentationPreferencePage::Init(berry::IWorkbench::Pointer)
{
}

void QmitkSegmentationPreferencePage::CreateQtControl(QWidget* parent)
{
  m_Initializing = true;

  m_Control = new QWidget(parent);
  m_Ui->setupUi(m_Control);

  connect(m_Ui->labelSetPresetToolButton, SIGNAL(clicked()), this, SLOT(OnLabelSetPresetButtonClicked()));
  connect(m_Ui->suggestionsToolButton, SIGNAL(clicked()), this, SLOT(OnSuggestionsButtonClicked()));
  connect(m_Ui->comboBuiltInSuggestions, &QComboBox::currentIndexChanged, this, &QmitkSegmentationPreferencePage::OnBuilInSuggestionsChanged);
  connect(m_Ui->check3DRendering, &QCheckBox::toggled, m_Ui->check3DSmoothed, &QCheckBox::setEnabled);

  this->Update();
  m_Initializing = false;
}

QWidget* QmitkSegmentationPreferencePage::GetQtControl() const
{
  return m_Control;
}

bool QmitkSegmentationPreferencePage::PerformOk()
{
  auto* prefs = GetPreferences();

  prefs->PutBool("compact view", m_Ui->compactViewCheckBox->isChecked());
  prefs->PutBool("draw outline", m_Ui->outlineRadioButton->isChecked());

  const auto opacityFactor = static_cast<float>(m_Ui->opacityFactorSlider->value()) / m_Ui->opacityFactorSlider->maximum();
  prefs->PutFloat("opacity factor", opacityFactor);

  prefs->PutBool("selection mode", m_Ui->selectionModeCheckBox->isChecked());

  prefs->PutBool("warn before converting to segmentation", m_Ui->convertWarningCheckBox->isChecked());

  if (!prefs->IsOverridden("label set preset"))
    prefs->Put("label set preset", m_Ui->labelSetPresetLineEdit->text().toStdString());

  if (!prefs->IsOverridden("default label naming"))
    prefs->PutBool("default label naming", m_Ui->defaultNameRadioButton->isChecked());

  prefs->Put("standard label suggestions", m_Ui->comboBuiltInSuggestions->currentText().toStdString());

  if (!prefs->IsOverridden("external label suggestions"))
    prefs->Put("external label suggestions", m_Ui->suggestionsLineEdit->text().toStdString());

  if (!prefs->IsOverridden("replace standard suggestions"))
    prefs->PutBool("replace standard suggestions", m_Ui->replaceStandardSuggestionsCheckBox->isChecked());

  if (!prefs->IsOverridden("suggest once"))
    prefs->PutBool("suggest once", m_Ui->suggestOnceCheckBox->isChecked());

  prefs->PutBool("enforce suggestions", m_Ui->enforceSuggestionsCheckBox->isChecked());

  prefs->PutBool("activate 3D rendering", m_Ui->check3DRendering->isChecked());
  prefs->PutBool("3D rendering smoothed", m_Ui->check3DSmoothed->isChecked());
  mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll();

  return true;
}

void QmitkSegmentationPreferencePage::PerformCancel()
{
}

void QmitkSegmentationPreferencePage::Update()
{
  auto* prefs = GetPreferences();

  m_Ui->compactViewCheckBox->setChecked(prefs->GetBool("compact view", false));

  if (prefs->GetBool("draw outline", true))
  {
    m_Ui->outlineRadioButton->setChecked(true);
  }
  else
  {
    m_Ui->overlayRadioButton->setChecked(true);
  }

  const auto opacityFactor = static_cast<int>(prefs->GetFloat("opacity factor", 1.0f) * m_Ui->opacityFactorSlider->maximum());
  m_Ui->opacityFactorSlider->setValue(opacityFactor);

  m_Ui->selectionModeCheckBox->setChecked(prefs->GetBool("selection mode", false));

  m_Ui->convertWarningCheckBox->setChecked(prefs->GetBool("warn before converting to segmentation", true));

  //label presets
  bool isOverridden = prefs->IsOverridden("label set preset");
  auto labelSetPreset = prefs->Get("label set preset", "");

  m_Ui->labelSetPresetLineEdit->setDisabled(isOverridden);
  m_Ui->labelSetPresetToolButton->setDisabled(isOverridden);
  m_Ui->labelSetPresetCmdLineArgLabel->setVisible(isOverridden);

  m_Ui->labelSetPresetLineEdit->setText(QString::fromStdString(labelSetPreset));

  if (prefs->GetBool("default label naming", true))
  {
    m_Ui->defaultNameRadioButton->setChecked(true);
  }
  else
  {
    m_Ui->askForNameRadioButton->setChecked(true);
  }

  bool isLabelNamingOverridden = prefs->IsOverridden("default label naming");
  m_Ui->defaultNameRadioButton->setDisabled(isLabelNamingOverridden);
  m_Ui->askForNameRadioButton->setDisabled(isLabelNamingOverridden);

  //label suggestions
  mitk::LabelSuggestionHelper::Preferences defaultPrefs;

  auto standardLabelSuggestions = prefs->Get("standard label suggestions", defaultPrefs.standardLabelSuggestionResource);

  FillBuiltInSuggestionComboBox(standardLabelSuggestions);

  auto externalLabelSuggestions = prefs->Get("external label suggestions", defaultPrefs.externalLabelSuggestionFile);

  m_Ui->suggestionsLineEdit->setText(QString::fromStdString(externalLabelSuggestions));

  m_Ui->replaceStandardSuggestionsCheckBox->setChecked(prefs->GetBool("replace standard suggestions", defaultPrefs.replaceStandardSuggestions));
  m_Ui->suggestOnceCheckBox->setChecked(prefs->GetBool("suggest once", defaultPrefs.suggestionOnce));
  m_Ui->enforceSuggestionsCheckBox->setChecked(prefs->GetBool("enforce suggestions", defaultPrefs.enforceSuggestions));

  const bool activate3D = prefs->GetBool("activate 3D rendering", true);
  m_Ui->check3DRendering->setChecked(activate3D);
  m_Ui->check3DSmoothed->setChecked(prefs->GetBool("3D rendering smoothed", true));
  m_Ui->check3DSmoothed->setEnabled(activate3D);
}

void QmitkSegmentationPreferencePage::FillBuiltInSuggestionComboBox(std::string& standardLabelSuggestions)
{
  auto builtInConfigs = mitk::LabelSuggestionHelper::GetAllAvailableBuiltInSuggestions();
  m_Ui->comboBuiltInSuggestions->clear();

  for (const auto& [key, val] : builtInConfigs)
  {
    m_Ui->comboBuiltInSuggestions->addItem(QString::fromStdString(key));
  }

  const QString target = QString::fromStdString(standardLabelSuggestions);
  int index = m_Ui->comboBuiltInSuggestions->findText(target);

  if (index != -1) {
    m_Ui->comboBuiltInSuggestions->setCurrentIndex(index);  // Select existing key
  }
}

void QmitkSegmentationPreferencePage::OnLabelSetPresetButtonClicked()
{
  const auto filename = QFileDialog::getOpenFileName(m_Control, QStringLiteral("Load Label Set Preset"), QString(), QStringLiteral("Label set preset (*.lsetp)"));

  if (!filename.isEmpty())
    m_Ui->labelSetPresetLineEdit->setText(filename);
}

void QmitkSegmentationPreferencePage::OnSuggestionsButtonClicked()
{
  const auto filename = QFileDialog::getOpenFileName(m_Control, QStringLiteral("Load Label Suggestions"), QString(), QStringLiteral("Label suggestions (*.json)"));

  if (!filename.isEmpty())
    m_Ui->suggestionsLineEdit->setText(filename);
}

void QmitkSegmentationPreferencePage::OnBuilInSuggestionsChanged(int index)
{
  auto builtInConfigs = mitk::LabelSuggestionHelper::GetAllAvailableBuiltInSuggestions();
  m_Ui->labelBuiltInSuggestionsInfo->clear();

  QString info;

  auto finding = builtInConfigs.find(m_Ui->comboBuiltInSuggestions->itemText(index).toStdString());

  if (finding != builtInConfigs.end())
  {
    try
    {
      auto& json = finding->second;
      if (json.contains("properties") && json["properties"].is_object())
      {
        const auto& props = json["properties"];

        std::string name = props.value("name", "");
        std::string description = props.value("description", "");

        if (!name.empty()) 
        {
          info.append("<i><b>Name:</b> ");
          info.append(QString::fromStdString(name));
          info.append("</i>");
        }

        if (!description.empty())
        {
          if (!info.isEmpty())
          {
            info.append("<br/>");
          }
          info.append("<i><b>Description:</b> ");
          info.append(QString::fromStdString(description));
          info.append("</i>");
        }
      }
    }
    catch (const nlohmann::json::parse_error& e)
    {
      info.append("Cannot provide info due to parsing error. Parse error: ").append(e.what());
    }
  }
  else
  {
    MITK_ERROR << "Not able to load standard label suggestions. Resource specified in the preferences cannot be find. Invalid resource ID: " << m_Ui->comboBuiltInSuggestions->itemData(index).toString().toStdString();
  }

  m_Ui->labelBuiltInSuggestionsInfo->setText(info);
  m_Ui->labelBuiltInSuggestionsInfo->setVisible(!info.isEmpty());
}
