//============================================================================
//  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 <fides/DataSetReader.h>
#include <vtkm/Version.h>

#ifdef FIDES_USE_MPI
#include <mpi.h>
#endif
#include <string>
#include <unordered_map>

int main(int argc, char** argv)
{
#ifdef FIDES_USE_MPI
  MPI_Init(&argc, &argv);
#endif
  int retVal = 0;

  std::string filename = std::string(argv[1]) + "/groups.bp";
  fides::io::DataSetReader reader(filename, fides::io::DataSetReader::DataModelInput::BPFile);
  std::unordered_map<std::string, std::string> paths;
  paths["source"] = filename;

  auto groups = reader.GetGroupNames(paths);
  for (auto& group : { "IOSS/assemblies/Conglomerate/Top/Prime/mesh_2",
                       "IOSS/assemblies/Conglomerate/Top/Prime/mesh_3",
                       "IOSS/assemblies/Conglomerate/Top/Prime/mesh_5",
                       "IOSS/assemblies/Conglomerate/Top/Prime/mesh_7" })
  {
    if (!groups.count(group))
    {
      std::cerr << "Group \"" << group << "\" was not retrieved!" << std::endl;
      retVal |= 1;
      continue;
    }
    auto metaData = reader.ReadMetaData(paths, group);
    const auto nSteps =
      metaData.Get<fides::metadata::Size>(fides::keys::NUMBER_OF_STEPS()).NumberOfItems;
    if (nSteps != 11)
    {
      std::cerr << "Error: expected 11 steps, got " << nSteps << std::endl;
      retVal |= 1;
    }
    for (size_t i = 0; i < nSteps; ++i)
    {
      fides::metadata::MetaData selections = metaData;
      selections.Set(fides::keys::GROUP_SELECTION(), fides::metadata::String(group));
      selections.Set(fides::keys::STEP_SELECTION(), fides::metadata::Index(i));
      vtkm::cont::PartitionedDataSet output = reader.ReadDataSet(paths, selections);
      // output.PrintSummary(std::cout);
      const auto& ds = output.GetPartition(0);
      const auto nPartitions = output.GetNumberOfPartitions();
      if (nPartitions != 1)
      {
        std::cerr << "Error: expected 1 output block, got " << output.GetNumberOfPartitions()
                  << std::endl;
        retVal |= 1;
      }

      const auto nPoints = ds.GetNumberOfPoints();
      const auto nCells = ds.GetNumberOfCells();
      const auto nFields = ds.GetNumberOfFields();
      if (nPoints != 27)
      {
        std::cerr << "Error: expected 27 points, got " << nPoints << std::endl;
        retVal |= 1;
      }
      if (nCells != 8)
      {
        std::cerr << "Error: expected 8 cells, got " << nCells << std::endl;
        retVal |= 1;
      }
      // 11 fields: 10 for the output; another one for the coordinates.
      if (nFields != 11)
      {
        std::cerr << "Error: expected 11 output arrays, got " << nFields << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("accel", vtkm::cont::Field::Association::Points))
      {
        std::cerr << "Error: expected a accel array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("disp", vtkm::cont::Field::Association::Points))
      {
        std::cerr << "Error: expected a disp array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("force", vtkm::cont::Field::Association::Points))
      {
        std::cerr << "Error: expected a force array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("ids", vtkm::cont::Field::Association::Points))
      {
        std::cerr << "Error: expected a ids array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("vel", vtkm::cont::Field::Association::Points))
      {
        std::cerr << "Error: expected a vel array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("cell_set_ids", vtkm::cont::Field::Association::Cells))
      {
        std::cerr << "Error: expected a cell_set_ids array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("eqps", vtkm::cont::Field::Association::Cells))
      {
        std::cerr << "Error: expected a eqps array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("pressure", vtkm::cont::Field::Association::Cells))
      {
        std::cerr << "Error: expected a pressure array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("mises", vtkm::cont::Field::Association::Cells))
      {
        std::cerr << "Error: expected a mises array. Did not get it." << std::endl;
        retVal |= 1;
      }
      if (!ds.HasField("object_id", vtkm::cont::Field::Association::Cells))
      {
        std::cerr << "Error: expected a object_id array. Did not get it." << std::endl;
        retVal |= 1;
      }
    }
  }
#ifdef FIDES_USE_MPI
  MPI_Finalize();
#endif
  return retVal;
}
