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

  Program:   ParaView
  Module:    vtkPVApplicationOptions.cxx

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkPVApplicationOptions.h"

#include "vtkLogger.h"
#include "vtkObjectFactory.h"

#include <vtk_cli11.h>

class vtkPVApplicationOptions::vtkInternals
{
public:
  std::vector<std::string> ServerConfigurationsFiles;
  std::string ServerResourceName;
  std::string ServerURL;
  std::string DataDirectory;
  std::string TestDirectory;
  std::string BaselineDirectory;
};

#define CHECK_READ_ONLY()                                                                          \
  vtkLogIfF(ERROR, this->GetReadOnly(), "Options is read-only!");                                  \
  if (this->GetReadOnly())                                                                         \
  {                                                                                                \
    return;                                                                                        \
  }

vtkStandardNewMacro(vtkPVApplicationOptions);
//----------------------------------------------------------------------------
vtkPVApplicationOptions::vtkPVApplicationOptions()
  : Internals(new vtkPVApplicationOptions::vtkInternals())
{
}

//----------------------------------------------------------------------------
vtkPVApplicationOptions::~vtkPVApplicationOptions() = default;

//----------------------------------------------------------------------------
const std::vector<std::string>& vtkPVApplicationOptions::GetServerConfigurationsFiles() const
{
  const auto& internals = (*this->Internals);
  return internals.ServerConfigurationsFiles;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::SetServerConfigurationsFiles(const std::vector<std::string>& files)
{
  CHECK_READ_ONLY();
  auto& internals = (*this->Internals);
  internals.ServerConfigurationsFiles = files;
}

//----------------------------------------------------------------------------
const std::string& vtkPVApplicationOptions::GetServerResourceName() const
{
  const auto& internals = (*this->Internals);
  return internals.ServerResourceName;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::SetServerResourceName(const std::string& name)
{
  CHECK_READ_ONLY();
  auto& internals = (*this->Internals);
  internals.ServerResourceName = name;
}

//----------------------------------------------------------------------------
const std::string& vtkPVApplicationOptions::GetServerURL() const
{
  const auto& internals = (*this->Internals);
  return internals.ServerURL;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::SetServerURL(const std::string& name)
{
  CHECK_READ_ONLY();
  auto& internals = (*this->Internals);
  internals.ServerURL = name;
}

//----------------------------------------------------------------------------
const std::string& vtkPVApplicationOptions::GetBaselineDirectory() const
{
  const auto& internals = (*this->Internals);
  return internals.BaselineDirectory;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::SetBaselineDirectory(const std::string& name)
{
  CHECK_READ_ONLY();
  auto& internals = (*this->Internals);
  internals.BaselineDirectory = name;
}

//----------------------------------------------------------------------------
const std::string& vtkPVApplicationOptions::GetTestDirectory() const
{
  const auto& internals = (*this->Internals);
  return internals.TestDirectory;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::SetTestDirectory(const std::string& name)
{
  CHECK_READ_ONLY();
  auto& internals = (*this->Internals);
  internals.TestDirectory = name;
}

//----------------------------------------------------------------------------
const std::string& vtkPVApplicationOptions::GetDataDirectory() const
{
  const auto& internals = (*this->Internals);
  return internals.DataDirectory;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::SetDataDirectory(const std::string& name)
{
  CHECK_READ_ONLY();
  auto& internals = (*this->Internals);
  internals.DataDirectory = name;
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::Populate(CLI::App& app)
{
  CHECK_READ_ONLY();

  this->Superclass::Populate(app);

  auto& internals = (*this->Internals);
  auto* groupConnection = app.add_option_group(
    "Connection options", "Options affecting connections between client/server processes");

  groupConnection->add_option("--servers-file", internals.ServerConfigurationsFiles,
    "Additional servers configuration file(s) (.pvsc) to use.");

  auto url = groupConnection->add_option("--url,--server-url", internals.ServerURL,
    "Server connection URL. On startup, the client will connect to the server using the URL "
    "specified.");

  groupConnection
    ->add_option("-s,--server", internals.ServerResourceName,
      "Server resource name. On startup, the client will connect to the server using the "
      "resource specified.")
    ->excludes(url);

  auto* groupTesting = app.add_option_group("Testing", "Testing specific options");

  groupTesting
    ->add_option("--baseline-directory", internals.BaselineDirectory,
      "Baseline directory where test recorder will store baseline images.")
    ->envname("PARAVIEW_TEST_BASELINE_DIR");

  groupTesting
    ->add_option("--test-directory", internals.TestDirectory,
      "Temporary directory used to output test results and other temporary files.")
    ->envname("PARAVIEW_TEST_DIR");

  groupTesting
    ->add_option(
      "--data-directory", internals.DataDirectory, "Directory containing data files for tests.")
    ->envname("PARAVIEW_DATA_ROOT");
}

//----------------------------------------------------------------------------
void vtkPVApplicationOptions::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  const auto& internals = (*this->Internals);
  os << indent << "ServerConfigurationsFiles: ";
  os << "[ ";
  for (auto& file : internals.ServerConfigurationsFiles)
  {
    os << "'" << file << "'"
       << " ";
  }
  os << "]\n";
  os << indent << "ServerResourceName: " << internals.ServerResourceName << "\n";
  os << indent << "ServerURL: " << internals.ServerURL << "\n";
  os << indent << "DataDirectory:" << internals.DataDirectory << "\n";
  os << indent << "TestDirectory:" << internals.TestDirectory << "\n";
  os << indent << "BaselineDirectory:" << internals.BaselineDirectory << "\n";
}
