/**
 * ParamTable.cc
 *
 *  Created on: 10 oct. 2014
 *  Author: AKKA
 */
#include "ParamTable.hh"

#include "Parameter.hh"
#include "ParamData.hh"
#include "ParamInfo.hh"
#include "ParamMgr.hh"
#include "Process.hh"
#include <algorithm>

using namespace log4cxx;

namespace AMDA {
    namespace Info {

#define PUSHINFO(infoMap, key, value) if(!value.empty())infoMap.push_back(std::pair<std::string,std::string>(key,value))

        LoggerPtr ParamTable::_logger(Logger::getLogger("AMDA-Kernel.ParamTable"));

        ParamTable::ParamTable(const char *paramId) : _paramId(paramId),
        _tableName(""), _tableUnits(""), _variable("false") {
        }

        ParamTable::~ParamTable() {
        }

        std::string ParamTable::getTableParamKeyForInfo(ParameterManager* /*parameterManager*/) {
            return "";
        }

        /*
         * @brief Get param id
         */
        std::string ParamTable::getParamId(void) {
            return _paramId;
        }

        /*
         * @brief Set name of the table
         */
        void ParamTable::setName(std::string name) {
            _tableName = name;
        }

        /*
         * @brief Get name of the table
         */
        std::string ParamTable::getName(ParameterManager* parameterManager) {
            if (_tableName.empty() && _variable) {
                std::string paramKeyForInfo = getTableParamKeyForInfo(parameterManager);
                if (!paramKeyForInfo.empty()) {
                    std::string tableParam = getTableParamByKey(parameterManager, paramKeyForInfo);
                    AMDA::Info::ParamInfoSPtr paramTableInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(tableParam);
                    if (paramTableInfo != nullptr)
                        return paramTableInfo->getName();
                }
            }

            return _tableName;
        }

        /*
         * @brief Set units
         */
        void ParamTable::setUnits(std::string units) {
            _tableUnits = units;
        }

        /*
         * @brief Get units of the table
         */
        std::string ParamTable::getUnits(ParameterManager* parameterManager) {
            if (_tableName.empty() && _variable) {
                std::string paramKeyForInfo = getTableParamKeyForInfo(parameterManager);
                if (!paramKeyForInfo.empty()) {
                    std::string tableParam = getTableParamByKey(parameterManager, paramKeyForInfo);
                    AMDA::Info::ParamInfoSPtr paramTableInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(tableParam);
                    if (paramTableInfo != nullptr)
                        return paramTableInfo->getUnits();
                }
            }

            return _tableUnits;
        }

        /*
         * @brief Set isVariable attribute
         */
        void ParamTable::setIsVariable(bool isVariable) {
            _variable = isVariable;
        }

        /*
         * @brief Get if it's a variable table
         */
        bool ParamTable::isVariable(ParameterManager* /*parameterManager*/) {
            return _variable;
        }
        
           /*
         * @brief Set isVariable attribute
         */
        void ParamTable::setIsFullVariable(bool isFullVariable) {
            _fullVariable = isFullVariable;
        }

        /*
         * @brief Get if it's a variable table
         */
        bool ParamTable::isFullVariable(ParameterManager* /*parameterManager*/) {
            return _fullVariable;
        }
        
        void ParamTable::addRelatedParams(ParameterManager *parameterManager, std::string paramId, std::list<std::string>relatedParams){
             AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(paramId);
             if(paramInfo == NULL)
                 return;
              const std::vector<std::string>& paramLinkedParams = paramInfo->getLinkedParamList();
              if(paramLinkedParams.empty())
                  return;
              for (auto pId : paramLinkedParams){
                  relatedParams.push_back(pId);
                  addRelatedParams(parameterManager, paramId, relatedParams);
              }
              return;
        }

        void ParamTable::addTableParam(std::string key, std::string name) {
            _tableParams[key] = name;
        }

        std::string ParamTable::getTableParamByKey(ParameterManager* /*parameterManager*/, std::string key) {
            return _tableParams[key];
        }

        std::map<std::string, std::string>& ParamTable::getTableParams(ParameterManager* /*parameterManager*/) {
            return _tableParams;
        }

        std::vector<double> ParamTable::getConstantTableParamValuesByKey(ParameterManager *parameterManager, std::string key) {
            std::vector<double> paramValues;
            ParameterSPtr tmpParam = parameterManager->getParameter(_paramId);
            if (tmpParam == nullptr)
                return paramValues;
            AMDA::Parameters::Parameter::InfoList lInfoList = tmpParam->getInfoList();
            if (_tableParams.find(key) == _tableParams.end())
                return paramValues;
            std::string tableParamName = _tableParams[key];
            if (lInfoList.find(tableParamName) == lInfoList.end())
                return paramValues;
            paramValues = *lInfoList[tableParamName].get();
            return paramValues;
        }

        std::vector<double> ParamTable::getVariableTableParamValuesByKey(ParameterManager* /*parameterManager*/, std::map<std::string, std::vector<double>>*paramsTableData, std::string key) {
            std::vector<double> paramValues;
            if (paramsTableData == NULL)
                return paramValues;
            if (paramsTableData->find(key) == paramsTableData->end())
                return paramValues;
            return (*paramsTableData)[key];
        }

        std::vector<double> ParamTable::getTableParamValuesByKey(ParameterManager *parameterManager, std::map<std::string, std::vector<double>>*paramsTableData, std::string key) {
            if (_variable)
                return getVariableTableParamValuesByKey(parameterManager, paramsTableData, key);
            else
                return getConstantTableParamValuesByKey(parameterManager, key);
        }

        void ParamTable::addTableInfo(ParameterManager *parameterManager, int dim, std::vector<std::pair<std::string, std::string>>&infoMap) {
            std::stringstream tableDim;
            tableDim << dim;

            std::stringstream infoKey;
            infoKey.str("");
            infoKey << PARAMETER_TABLE << "[" << tableDim.str() << "]";
            PUSHINFO(infoMap, infoKey.str(), this->getName(parameterManager));

            infoKey.str("");
            infoKey << PARAMETER_TABLE_UNITS << "[" << tableDim.str() << "]";
            PUSHINFO(infoMap, infoKey.str(), this->getUnits(parameterManager));

            if (this->isVariable(parameterManager)) {
                this->addVariableTableInfo(parameterManager, dim, infoMap);
            } else {
                //build min and max values list
                std::stringstream tableMinValues;
                std::stringstream tableMaxValues;
                for (int i = 0; i< this->getSize(parameterManager); ++i) {
                    if (i > 0) {
                        tableMinValues << ",";
                        tableMaxValues << ",";
                    }
                    AMDA::Info::t_TableBound bound = this->getBound(parameterManager, i);
                    tableMinValues << bound.min;
                    tableMaxValues << bound.max;
                }
                infoKey.str("");
                infoKey << PARAMETER_TABLE_MINVAL << "[" << tableDim.str() << "]";
                PUSHINFO(infoMap, infoKey.str(), tableMinValues.str());

                infoKey.str("");
                infoKey << PARAMETER_TABLE_MAXVAL << "[" << tableDim.str() << "]";
                PUSHINFO(infoMap, infoKey.str(), tableMaxValues.str());
            }
        }

        void ParamTable::addSemiVariableTableInfo(ParameterManager* parameterManager, int dim, std::string paramId, std::string tabKey, std::vector<std::pair<std::string, std::string>>&infoMap) {
            AMDA::Parameters::ParameterSPtr pParam = parameterManager->getParameter(paramId);
            Process* lProcess = dynamic_cast<Process*> (pParam->getDataWriterTemplate().get());
            if (lProcess != NULL) {
                AMDA::Parameters::SemiVariableTable semiVariableTable = lProcess ->getSemiVariableTable();
                std::list<std::string>::iterator it;
                it = std::find(_printedTables.begin(), _printedTables.end(), paramId);
                if (!semiVariableTable.tabHeader.empty() && it == _printedTables.end()) {
                    std::stringstream head;
                    head.str("");
                    head << "mode" << " ";
                    for (auto h : semiVariableTable.tabHeader) {
                        head << h << " ";
                    }
                    PUSHINFO(infoMap, "", head.str());
                    // recuperer les centres 
                    bool variableSizes = false;
                    //unsigned int nModes = semiVariableTable.tabValues.size();
                    unsigned int index =0;
                    unsigned nValues = 0;
                    for (auto tabValues : semiVariableTable.tabValues) {
                        if (index == 0)
                             nValues = tabValues.second.size();
                        if (tabValues.second.size() != nValues)
                            variableSizes = true;
                        ++index;
                    }
                    if (variableSizes || !semiVariableTable.calculateBounds) {
                        std::ostringstream values;
                        for (auto tabValues : semiVariableTable.tabValues) {
                            values << tabValues.first << " ";
                            for (unsigned int i = 0; i < nValues; i++) {
                                if (i < tabValues.second.size()) {
                                    values << std::to_string(tabValues.second[i]) << " ";
                                } else {
                                    values << "NAN ";
                                }
                            }
                            PUSHINFO(infoMap, "", values.str());
                            values.str("");
                        }
                    } else {
                        std::vector<double> energyVec;
                        std::map<std::string, std::vector<double>> paramsTableData;
                        std::map<int, std::vector<double>> semiVariableTableData;
                        int nMode=0;
                        for (auto tabValues : semiVariableTable.tabValues) {
                        paramsTableData[tabKey] = tabValues.second;
                        for (unsigned int j = 0; j < nValues; ++j) {
                                t_TableBound bound = getBound(parameterManager, j , &paramsTableData);
                                if(bound.min != j/2 && bound.max !=j/2+1){
                                semiVariableTableData[nMode].push_back(bound.min);
                                semiVariableTableData[nMode + 1].push_back(bound.max);
                                }
                            
                        }
                        nMode +=2;
                        }
                        int l = 0;
                        int k = 0;
                        for (auto v : semiVariableTableData) {
                            std::ostringstream values;
                            std::string born;
                            (l % 2 == 0) ? born = " Min " : born = " Max ";
                            values << std::to_string(k) << born;
                            // Convert all doubles to string ","
                            std::copy(v.second.begin(), v.second.end(),
                                    std::ostream_iterator<double>(values, " "));
                            PUSHINFO(infoMap, "", values.str());
                            values.str("");
                            if (l % 2 != 0)
                                k++;
                            l++;

                        }
                    }
                    _printedTables.push_back(paramId);
                }

            }
            AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(paramId);
            const std::vector<std::string>& paramLinkedParams = paramInfo->getLinkedParamList();
            for (auto pId : paramLinkedParams)
                addSemiVariableTableInfo(parameterManager, dim, pId, tabKey, infoMap);
            return;
        }

        void ParamTable::addVariableTableInfo(ParameterManager * parameterManager, int dim, std::vector<std::pair<std::string, std::string>>&tableInfo) {
            std::map<std::string, std::string>& tableParams = this->getTableParams(parameterManager);
            if (!tableParams.empty()) {
                std::stringstream infoKey;
                int i = 0;
                for (auto tableParam : tableParams) {
                    infoKey.str("");
                    infoKey << VARIABLE_PARAMETER_TABLE << tableParam.first << "[" << i << "]";
                    PUSHINFO(tableInfo, infoKey.str(), tableParam.second);
                    AMDA::Parameters::ParameterSPtr variableTableParam = parameterManager->getParameter(tableParam.second);
                    addSemiVariableTableInfo(parameterManager, dim, tableParam.second, tableParam.first, tableInfo);
                    i++;
                }
            }
        }

        std::string ParamBoundsTable::_boundsParamKey = "TABLEPARAM_BOUNDS";

        ParamBoundsTable::ParamBoundsTable(const char *paramId) :
        ParamTable(paramId) {
        }

        std::string ParamBoundsTable::getTableParamKeyForInfo(ParameterManager* /*parameterManager*/) {
            return ParamBoundsTable::_boundsParamKey;
        }

        /*
         * @brief Get size of the table
         */
        int ParamBoundsTable::getSize(ParameterManager *parameterManager) {
            if (!_variable) {
                std::vector<double> boundsValues = getConstantTableParamValuesByKey(parameterManager, ParamBoundsTable::_boundsParamKey);
                return boundsValues.size() - 1;
            } else {
                return 0;
            }
        }

        /*
         * @brief Get a bounds for a specified index
         */
        t_TableBound ParamBoundsTable::getBound(ParameterManager *parameterManager, unsigned int index, std::map<std::string, std::vector<double>>*paramsTableData) {
            t_TableBound bound;
            bound.index = index;

            std::vector<double> boundsValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamBoundsTable::_boundsParamKey);

            if (boundsValues.empty() || (index >= boundsValues.size() - 1)) {
                LOG4CXX_ERROR(_logger, "Index " << index << " outside of table definition => Cannot get real bound");
                bound.min = index;
                bound.max = index + 1;
                return bound;
            }
            bound.min = std::min(boundsValues[index], boundsValues[index + 1]);
            bound.max = std::max(boundsValues[index], boundsValues[index + 1]);

            return bound;
        }

        std::string ParamCenterTable::_centersParamKey = "TABLEPARAM_CENTERS";

        ParamCenterTable::ParamCenterTable(const char *paramId, double size) :
        ParamTable(paramId), _size(size) {
        }

        std::string ParamCenterTable::getTableParamKeyForInfo(ParameterManager* /*parameterManager*/) {
            return ParamCenterTable::_centersParamKey;
        }

        /*
         * @brief Get size of the table
         */
        int ParamCenterTable::getSize(ParameterManager *parameterManager) {
            if (!_variable) {
                std::vector<double> centersValues = getConstantTableParamValuesByKey(parameterManager, ParamCenterTable::_centersParamKey);
                return centersValues.size();
            } else {
                return 0;
            }
        }

        /*
         * @brief Get a bound for a specified index
         */
        t_TableBound ParamCenterTable::getBound(ParameterManager *parameterManager, unsigned int index, std::map<std::string, std::vector<double>>*paramsTableData) {
            t_TableBound bound;
            bound.index = index;

            std::vector<double> centersValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamCenterTable::_centersParamKey);

            if (index >= centersValues.size()) {
                LOG4CXX_ERROR(_logger, "Index " << index << " outside of table definition => Cannot get real bound");
                bound.min = index;
                bound.max = index + 1;
                return bound;
            }

            if (!std::isnan(centersValues[index])) {
                bound.min = centersValues[index] - _size / 2.;
                bound.max = centersValues[index] + _size / 2.;
            } else {
                bound.min = NAN;
                bound.max = NAN;
            }

            return bound;
        }

        std::string ParamCenterWidthTable::_centersParamKey = "TABLEPARAM_CENTERS";
        std::string ParamCenterWidthTable::_widthsParamKey = "TABLEPARAM_WIDTHS";

        ParamCenterWidthTable::ParamCenterWidthTable(const char *paramId) :
        ParamTable(paramId) {
        }

        std::string ParamCenterWidthTable::getTableParamKeyForInfo(ParameterManager* /*parameterManager*/) {
            return ParamCenterWidthTable::_centersParamKey;
        }

        /*
         * @brief Get size of the table
         */
        int ParamCenterWidthTable::getSize(ParameterManager *parameterManager) {
            if (!_variable) {
                std::vector<double> centersValues = getConstantTableParamValuesByKey(parameterManager, ParamCenterWidthTable::_centersParamKey);
                return centersValues.size();
            } else {
                return 0;
            }
        }

        /*
         * @brief Get a bound for a specified index
         */
        t_TableBound ParamCenterWidthTable::getBound(ParameterManager *parameterManager, unsigned int index, std::map<std::string, std::vector<double>>*paramsTableData) {
            t_TableBound bound;
            bound.index = index;

            std::vector<double> centersValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamCenterWidthTable::_centersParamKey);
            std::vector<double> widthsValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamCenterWidthTable::_widthsParamKey);

            if ((index >= centersValues.size()) || (index >= widthsValues.size())) {
                LOG4CXX_ERROR(_logger, "Index " << index << " outside of table definition => Cannot get real bound");
                bound.min = index;
                bound.max = index + 1;
                return bound;
            }

            if (!std::isnan(centersValues[index]) && !std::isnan(widthsValues[index])) {
                bound.min = centersValues[index] - widthsValues[index] / 2.;
                bound.max = centersValues[index] + widthsValues[index] / 2.;
            } else {
                bound.min = NAN;
                bound.max = NAN;
            }

            return bound;
        }

        std::string ParamCenterAutoTable::_centersParamKey = "TABLEPARAM_CENTERS";

        ParamCenterAutoTable::ParamCenterAutoTable(const char *paramId, bool log) :
        ParamTable(paramId), _log(log) {
        }

        std::string ParamCenterAutoTable::getTableParamKeyForInfo(ParameterManager* /*parameterManager*/) {
            return ParamCenterAutoTable::_centersParamKey;
        }

        /*
         * @brief Get size of the table
         */
        int ParamCenterAutoTable::getSize(ParameterManager *parameterManager) {
            if (!_variable) {
                std::vector<double> centersValues = getConstantTableParamValuesByKey(parameterManager, ParamCenterAutoTable::_centersParamKey);
                return centersValues.size();
            } else {
                return 0;
            }
        }

        /*
         * @brief Get a bound for a specified index
         */
        t_TableBound ParamCenterAutoTable::getBound(ParameterManager *parameterManager, unsigned int index, std::map<std::string, std::vector<double>>*paramsTableData) {
            t_TableBound bound;
            bound.index = index;

            std::vector<double> centersValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamCenterAutoTable::_centersParamKey);

            if (index >= centersValues.size()) {
                LOG4CXX_ERROR(_logger, "Index " << index << " outside of table definition => Cannot get real bound");
                bound.min = index;
                bound.max = index + 1;
                return bound;
            }

            //Compute bounds

            if (centersValues.size() <= 1) {
                LOG4CXX_ERROR(_logger, "Table dimension too small to compute bound");
                bound.min = index;
                bound.max = index + 1;
                return bound;
            }

            double minus = 0.;
            double plus = 0.;

            if (index == 0) {
                if (!std::isnan(centersValues[1]) && !std::isnan(centersValues[0])) {
                    if (_log)
                        plus = (log10(centersValues[1]) - log10(centersValues[0])) / 2.;
                    else
                        plus = (centersValues[1] - centersValues[0]) / 2.;
                } else
                    plus = NAN;
                minus = plus;
            } else if (index == centersValues.size() - 1) {
                if (!std::isnan(centersValues[centersValues.size() - 1]) && !std::isnan(centersValues[centersValues.size() - 2])) {
                    if (_log)
                        minus = (log10(centersValues[centersValues.size() - 1]) - log10(centersValues[centersValues.size() - 2])) / 2.;
                    else
                        minus = (centersValues[centersValues.size() - 1] - centersValues[centersValues.size() - 2]) / 2.;
                } else
                    minus = NAN;
                plus = minus;

            } else {
                if (_log) {
                    if (!std::isnan(centersValues[index]) && !std::isnan(centersValues[index - 1]) && (centersValues[index] > 0) && (centersValues[index - 1] > 0))
                        minus = (log10(centersValues[index]) - log10(centersValues[index - 1])) / 2.;
                    else
                        minus = NAN;
                    if (!std::isnan(centersValues[index + 1]) && !std::isnan(centersValues[index]) && (centersValues[index + 1] > 0) && (centersValues[index] > 0))
                        plus = (log10(centersValues[index + 1]) - log10(centersValues[index])) / 2.;
                    else
                        plus = NAN;
                } else {
                    if (!std::isnan(centersValues[index]) && !std::isnan(centersValues[index - 1]))
                        minus = (centersValues[index] - centersValues[index - 1]) / 2.;
                    else
                        minus = NAN;
                    if (!std::isnan(centersValues[index + 1]) && !std::isnan(centersValues[index]))
                        plus = (centersValues[index + 1] - centersValues[index]) / 2.;
                    else
                        plus = NAN;
                }
            }

            if (_log) {
                if (!std::isnan(minus))
                    bound.min = exp(log10(centersValues[index]) - minus);
                else
                    bound.min = NAN;
                if (!std::isnan(plus))
                    bound.max = exp(log10(centersValues[index]) + plus);
                else
                    bound.max = NAN;
            } else {
                if (!std::isnan(minus))
                    bound.min = centersValues[index] - minus;
                else
                    bound.min = NAN;
                if (!std::isnan(plus))
                    bound.max = centersValues[index] + plus;
                else
                    bound.max = NAN;
            }

            if (bound.min > bound.max) {
                double temp = bound.max;
                bound.max = bound.min;
                bound.min = temp;
            }

            return bound;
        }


        std::string ParamMinMaxTable::_minParamKey = "TABLEPARAM_MIN";
        std::string ParamMinMaxTable::_maxParamKey = "TABLEPARAM_MAX";

        ParamMinMaxTable::ParamMinMaxTable(const char *paramId) : ParamTable(paramId) {
        }

        /*
         * @brief Get size of the table
         */
        int ParamMinMaxTable::getSize(ParameterManager *parameterManager) {
            if (!_variable) {
                std::vector<double> minValues = getConstantTableParamValuesByKey(parameterManager, ParamMinMaxTable::_minParamKey);
                return minValues.size();
            } else {
                return 0;
            }
        }

        /*
         * @brief Get bound for a specified index
         */
        t_TableBound ParamMinMaxTable::getBound(ParameterManager *parameterManager, unsigned int index, std::map<std::string, std::vector<double>>*paramsTableData) {
            t_TableBound bound;
            bound.index = index;

            std::vector<double> minValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamMinMaxTable::_minParamKey);
            std::vector<double> maxValues = getTableParamValuesByKey(parameterManager, paramsTableData, ParamMinMaxTable::_maxParamKey);

            if ((index >= minValues.size()) || (index >= maxValues.size())) {
                LOG4CXX_ERROR(_logger, "Index " << index << " outside of table definition => Cannot get real bound");
                bound.min = index;
                bound.max = index + 1;
                return bound;
            }

            bound.min = std::min(minValues[index], maxValues[index]);
            bound.max = std::max(minValues[index], maxValues[index]);

            return bound;
        }

        LinkTable::LinkTable(const char *paramId, const char* originParamId) : ParamTable(paramId), _originParamId(originParamId), _originTableDim(0) {
        }

        ParamTable* LinkTable::getOriginParamTable(ParameterManager* parameterManager) {
            if (parameterManager == NULL) {
                return NULL;
            }

            ParameterSPtr tmpParam = parameterManager->getParameter(_originParamId);
            if (tmpParam == nullptr) {
                return NULL;
            }

            ParamInfoSPtr paramInfo = ParamMgr::getInstance()->getParamInfoFromId(tmpParam->getInfoId());
            if (paramInfo == nullptr) {
                return NULL;
            }

            boost::shared_ptr<AMDA::Info::ParamTable> tableSPtr = paramInfo->getTable(_originTableDim);
            if (tableSPtr == nullptr) {
                return NULL;
            }
            return tableSPtr.get();
        }

        std::string LinkTable::getTableParamKeyForInfo(ParameterManager* parameterManager) {
            std::string res = "";
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table != NULL) {
                res = table->getTableParamKeyForInfo(parameterManager);
            }
            return res;
        }

        std::string LinkTable::getName(ParameterManager* parameterManager) {
            std::string res = "";
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table != NULL) {
                res = table->getName(parameterManager);
            }
            return res;
        }

        std::string LinkTable::getUnits(ParameterManager* parameterManager) {
            std::string res = "";
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table != NULL) {
                res = table->getUnits(parameterManager);
            }
            return res;
        }

        bool LinkTable::isVariable(ParameterManager* parameterManager) {
            bool res = false;
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table != NULL) {
                res = table->isVariable(parameterManager);
            }
            return res;
        }
        
          bool LinkTable::isFullVariable(ParameterManager* parameterManager) {
            bool res = false;
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table != NULL) {
                res = table->isFullVariable(parameterManager);
            }
            return res;
        }

        std::map<std::string, std::string>& LinkTable::getTableParams(ParameterManager* parameterManager) {
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table == NULL) {
                return _emptyTableParam;
            }
            return table->getTableParams(parameterManager);
        }

        int LinkTable::getSize(ParameterManager *parameterManager) {
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table == NULL) {
                return 0;
            }
            return table->getSize(parameterManager);
        }

        t_TableBound LinkTable::getBound(ParameterManager *parameterManager, unsigned int index, std::map<std::string, std::vector<double>>*paramsTableData) {
            t_TableBound res;
            ParamTable* table = getOriginParamTable(parameterManager);
            if (table == NULL) {
                res.index = index;
                res.min = index;
                res.max = index + 1;
            } else {
                res = table->getBound(parameterManager, index, paramsTableData);
            }
            return res;
        }

    } /* namespace Info */
} /* namespace AMDA */