/*    This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
 *    See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
 *    Author(s):       Hannah Schreiber
 *
 *    Copyright (C) 2022-24 Inria
 *
 *    Modification(s):
 *      - YYYY/MM Author: Description of the modification
 */

/**
 * @file persistence_matrix_options.h
 * @author Hannah Schreiber
 * @brief Contains the options for the matrix template.
 */

#ifndef PM_OPTIONS_INCLUDED
#define PM_OPTIONS_INCLUDED

#include "Fields/Zp_field_operators.h"

namespace Gudhi {
namespace persistence_matrix {

/**
 * @ingroup persistence_matrix
 *
 * @brief List of column types.
 */
enum Column_types { 
  LIST,           /**< @ref List_column "": Underlying container is a std::list<@ref Cell*>. */
  SET,            /**< @ref Set_column "": Underlying container is a std::set<@ref Cell*>. */
  HEAP,           /**< @ref Heap_column "": Underlying container is a std::vector<@ref Cell*> ordered as a heap.
                       Is not compatible with row access and column compression. */
  VECTOR,         /**< @ref Vector_column "": Underlying container is a std::vector<@ref Cell*>
                       with a lazy removal method. */
  NAIVE_VECTOR,   /**< @ref Naive_vector_column "": Underlying container is a std::vector<@ref Cell*>. */
  UNORDERED_SET,  /**< @ref Unordered_set_column "": Underlying container is a std::unordered_set<@ref Cell*>. */
  INTRUSIVE_LIST, /**< @ref Intrusive_list_column "": Underlying container is a boost::intrusive::list<@ref Cell>. */
  INTRUSIVE_SET   /**< @ref Intrusive_set_column "": Underlying container is a boost::intrusive::set<@ref Cell>. */
};

/**
 * @ingroup persistence_matrix
 *
 * @brief List if indexation schemes. See @ref mp_indexation "description of indexation schemes" for more details
 * about the meaning of the indexation types.
 */
enum Column_indexation_types { 
  CONTAINER,  /**< Default use of @ref MatIdx indices. */
  POSITION,   /**< All input and output @ref MatIdx indices are replaced with @ref PosIdx indices. */
  IDENTIFIER  /**< All input and output @ref MatIdx indices are replaced with @ref IDIdx indices. */
};

/**
 * @struct Default_options persistence_matrix_options.h gudhi/persistence_matrix_options.h
 * @ingroup persistence_matrix
 *
 * @brief Default option structure for @ref Matrix class.
 * See the @ref PersistenceMatrixOptions concept for a more detailed description of the fields.
 * Produces a @ref basematrix "base matrix" with no enabled option.
 *
 * To create other matrix types, the easiest is to simply inherit from this structure and overwrite only the options
 * one is interested in.
 * 
 * @tparam col_type Column type for the matrix. Default value: @ref Column_types::INTRUSIVE_SET
 * @tparam is_z2_only Flag indicating if only \f$Z_2\f$ coefficient will be used with the matrix. Set to true if it
 * is the case, false otherwise. Default value: true.
 * @tparam FieldOperators Field operators used by the matrix, see FieldOperators concept.
 * Only necessary if @p is_z2_only is false. 
 * Default value: @ref Gudhi::persistence_fields::Zp_field_operators<>.
 */
template <Column_types col_type = Column_types::INTRUSIVE_SET, 
          bool is_z2_only = true,
          class FieldOperators = persistence_fields::Zp_field_operators<> >
struct Default_options 
{
  using Field_coeff_operators = FieldOperators;
  using dimension_type = int;
  using index_type = unsigned int;

  static const bool is_z2 = is_z2_only;
  static const Column_types column_type = col_type;

  static const Column_indexation_types column_indexation_type = Column_indexation_types::CONTAINER;

  static const bool has_column_compression = false;
  static const bool has_column_and_row_swaps = false;

  static const bool has_map_column_container = false;
  static const bool has_removable_columns = false;

  static const bool has_row_access = false;
  static const bool has_intrusive_rows = true;
  static const bool has_removable_rows = false;

  static const bool is_of_boundary_type = true;

  static const bool has_matrix_maximal_dimension_access = false;
  static const bool has_column_pairings = false;
  static const bool has_vine_update = false;
  static const bool can_retrieve_representative_cycles = false;
};

//TODO: The following structures are the one used by the other modules or debug tests.
// They will probably be removed once the module was properly integrated.

/**
 * @brief Options used for the Zigzag persistence module.
 * 
 * @tparam column_type Column type for the matrix.
 */
template <Column_types column_type = Column_types::INTRUSIVE_LIST>
struct Zigzag_options : Default_options<column_type, true> 
{
  static const bool has_row_access = true;
  static const bool has_column_pairings = false;
  static const bool has_vine_update = true;
  static const bool is_of_boundary_type = false;
  static const bool has_map_column_container = true;
  static const bool has_removable_columns = true;
  static const bool has_removable_rows = true;
};

/**
 * @brief Options needed to use the representative cycles.
 * 
 * @tparam col_type Column type for the matrix.
 */
template <Column_types col_type = Column_types::INTRUSIVE_SET>
struct Representative_cycles_options : Default_options<col_type, true> 
{
  static const bool has_column_pairings = true;
  static const bool can_retrieve_representative_cycles = true;
};

/**
 * @brief Options used by the Multipersistence module.
 * 
 * @tparam column_type Column type for the matrix.
 */
template <Column_types column_type = Column_types::INTRUSIVE_SET>
struct Multi_persistence_options : Default_options<column_type, true> 
{
  static const bool has_column_pairings = true;
  static const bool has_vine_update = true;
};

/**
 * @brief Options used by the cohomology module.
 * 
 * @tparam column_type Column type for the matrix.
 * @tparam is_z2_only True if Z2.
 * @tparam FieldOperators Field operator.
 */
template <Column_types column_type = Column_types::INTRUSIVE_LIST, 
          bool is_z2_only = true,
          class FieldOperators = persistence_fields::Zp_field_operators<> >
struct Cohomology_persistence_options : Default_options<column_type, is_z2_only, FieldOperators> 
{
  static const bool has_row_access = true;
  static const bool has_column_compression = true;
  static const bool has_removable_rows = true;
};

}  // namespace persistence_matrix
}  // namespace Gudhi

#endif  // PM_OPTIONS_INCLUDED
