// SPDX-FileCopyrightText: 2022 The Ikarus Developers mueller@ibb.uni-stuttgart.de
// SPDX-License-Identifier: LGPL-3.0-or-later

#pragma once
#include "observer.hh"
#include "observerMessages.hh"

#include <string>

#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
#include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh>

#include <spdlog/spdlog.h>

template <typename Basis>  // Check basis
class ControlSubsamplingVertexVTKWriter : public IObserver<ControlMessages> {
  static constexpr int components = Basis::LocalView::Tree::CHILDREN == 0 ? 1 : Basis::LocalView::Tree::CHILDREN;

public:
  ControlSubsamplingVertexVTKWriter(const Basis& p_basis, const Eigen::VectorXd& sol, int refinementLevels = 0)
      : basis{&p_basis}, vtkWriter(p_basis.gridView(), Dune::refinementLevels(refinementLevels)), solution{&sol} {}

  auto setFieldInfo(std::string&& name, Dune::VTK::FieldInfo::Type type, std::size_t size,
                    Dune::VTK::Precision prec = Dune::VTK::Precision::float32) {
    fieldInfo      = Dune::VTK::FieldInfo(std::move(name), type, size, prec);
    isFieldInfoSet = true;
  }

  auto setFileNamePrefix(std::string&& p_name) { prefixString = std::move(p_name); }

  void updateImpl(ControlMessages message) override {
    assert(isFieldInfoSet && "You need to call setFieldInfo first!");
    switch (message) {
      case ControlMessages::SOLUTION_CHANGED: {
        auto disp = Dune::Functions::makeDiscreteGlobalBasisFunction<Dune::FieldVector<double, components>>(*basis,
                                                                                                            *solution);
        vtkWriter.addVertexData(disp, fieldInfo);
        vtkWriter.write(prefixString + std::to_string(step++));
      } break;
      default:
        break;  //   default: do nothing when notified
    }
  }

  using IObserver::updateImpl;
  void updateImpl(ControlMessages, double) override {}
  void updateImpl(ControlMessages, const Eigen::VectorXd&) override {}

private:
  Basis const* basis;
  Dune::SubsamplingVTKWriter<typename Basis::GridView> vtkWriter;
  Eigen::VectorXd const* solution;
  int step{0};
  Dune::VTK::FieldInfo fieldInfo{"Default", Dune::VTK::FieldInfo::Type::scalar, 1};
  std::string prefixString{};
  bool isFieldInfoSet{false};
};
