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

  Copyright (C) 2003-2020 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
  See COPYING file for copying and redistribution conditions.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/

#ifndef MODULES_H
#define MODULES_H

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

// 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 module_t
{
  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
  ModuleRestrictions restrictions = NoRestriction;
  module_t(){};
  module_t(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)
      : func(p_func), help(p_help), operators(p_opers), mode(p_m), number(p_n), streamInCnt(p_siC), streamOutCnt(p_soC),
        restrictions(p_onlyFirst)
  {
  }
  std::string toString();
};

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

/***
  Maps operator names to their module names
 */
extern std::map<std::string, std::string> modules_map;

/***
  Contains added modules as values and their names as key
  */
extern std::map<std::string, module_t> modules;

/***
  Key: operator alias / Value: operator original name
 */
extern std::map<std::string, std::string> aliases;

void registerOperatorsFromModules();

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

std::map<std::string, module_t>::iterator findModule(const std::string &operatorName);
module_t &getModule(const std::string &operatorName);

void init_modules();

const char **operatorHelp(const std::string &operatorName);
// int operatorStreamInCnt(const char *operatorName);
// int operatorStreamOutCnt(const char *operatorName);
int operatorStreamNumber(const char *operatorName);

std::string get_module_name_to(const std::string &operatorName);
const char *get_original(const char *operatorName);
void add_module(const std::string &module_name, const module_t &new_module);
int add_alias(const std::string &alias, const std::string &original);
std::vector<std::string> get_sorted_operator_name_list();

#ifdef CUSTOM_MODULES
void load_custom_module(std::string path);
void load_custom_modules(std::string folder_path);
void close_library_handles();
#endif

#endif /* MODULES_H */
