/*
  This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.

  Author: Uwe Schulzweida

*/
#ifndef MODULES_H
#define MODULES_H

#include <iostream>
#include <map>
#include <array>
#include <vector>

#include "module_static_maps.h"

// Obase uses input name as base name for files e.g 'test' gets used as test_001 test_002 which are created inside the operator
#define OBASE -1
#define INTERNAL 0
#define EXPOSED 1

/***
  type definition for module functions loaded from a custom module
  */
using dyn_oper_t = void (*)(void *arg);

enum ModuleRestrictions
{
  NoRestriction = 0,
  FilesOnly = 1,
  OnlyFirst = 2
};

struct Alias
{
  Alias(const std::string &_alias, const std::string &_original);
  std::string alias;
  std::string original;
};

struct module_t
{
  std::string mod_name;
  void *(*func)(void *);               // Module
  const char **help;                   // Help
  std::vector<std::string> operators;  // Operator names
  short mode;                          // Module mode: 0:intern 1:extern
  short number;                        // Allowed number type
  short streamInCnt;                   // Number of input streams
  short streamOutCnt;                  // Number of output streams
  std::vector<Alias> aliases;
  ModuleRestrictions restrictions = NoRestriction;

  module_t(const std::string &mod_name, void *(*p_func)(void *), const char **p_help, const std::vector<std::string> &p_opers,
           short p_m, short p_n, short p_siC, short p_soC, ModuleRestrictions p_onlyFirst,
           const std::vector<Alias> &p_aliases = {});
  module_t(){};
  std::string toString();
};

/***
  vector for library handles for loaded custom modules
  */
extern std::vector<void *> custom_modules_lib_handles;

std::string extract_operator_name(const std::string &operatorCommand);
void extract_name_and_argument(const std::string &command, std::string &operatorName, std::string &operatorArgument);

/***
  Key: operator alias / Value: operator original name
 */

void register_operators(const std::string &p_mod_name, const module_t &p_mod);

// void *(*operatorModule(const char *operatorName))(void *);

std::map<std::string, module_t>::iterator find_module(const std::string &operatorName);
module_t &get_module(const std::string &operatorName);

std::string get_original(const std::string &operatorName);

void init_modules();

const char **operator_help(const std::string &operatorName);
const char **operator_help(const char *operatorName);
// int operatorStreamInCnt(const char *operatorName);
// int operatorStreamOutCnt(const char *operatorName);
int operator_stream_number(std::string &operatorName);

std::string get_module_name_to(const std::string &operatorName);
std::vector<std::string> get_sorted_operator_name_list();

#endif /* MODULES_H */
