// Value access
bool CEnumParameterType::toBlackboard(int32_t userValue, uint32_t &value,
                                      CParameterAccessContext &parameterAccessContext) const
{
    // Take care of format
    if (parameterAccessContext.valueSpaceIsRaw()) {
        signExtend(userValue);
    }

    if (!checkValueAgainstSpace(userValue)) {

        parameterAccessContext.setError(std::to_string(userValue) +
                                        " is not part of numerical space.");

        return false;
    }

    if (userValue < getMin() or userValue > getMax()) {

        // FIXME: values provided as hexa (either on command line or in a config
        // file will appear in decimal base instead of hexa base...
        parameterAccessContext.setError(
            "Value " + std::to_string(userValue) + " standing out of admitted range [" +
            std::to_string(getMin()) + ", " + std::to_string(getMax()) + "] for " + getKind());
        return false;
    }

    value = static_cast<uint32_t>(userValue);

    return true;
}
bool CInstanceConfigurableElement::sync(CParameterAccessContext& parameterAccessContext) const
{
    if (!parameterAccessContext.getAutoSync()) {

        // AutoSync is disabled, do not perform the sync.
        // This is not an error, but the expected behavior so return true anyway.
        return true;
    }
    ISyncer* pSyncer = getSyncer();

    if (!pSyncer) {

        parameterAccessContext.setError("Unable to synchronize modification. No Syncer object associated to configurable element:");

        return false;
    }
    std::string strError;

    if (!pSyncer->sync(*parameterAccessContext.getParameterBlackboard(), false, strError)) {

        parameterAccessContext.setError(strError);

        return false;
    }
    return true;
}
// Range checking
bool CEnumParameterType::checkValueAgainstRange(const string& strValue, int64_t value, CParameterAccessContext& parameterAccessContext, bool bHexaValue, bool bConversionSucceeded) const
{
    // Enums are always signed, it means we have one less util bit
    int64_t maxValue = getMaxValue<uint64_t>();
    int64_t minValue = -maxValue - 1;

    if (!bConversionSucceeded || value < minValue || value > maxValue) {

	std::ostringstream strStream;

        strStream << "Value " << strValue << " standing out of admitted range [";

        if (bHexaValue) {

            // Format Min
            strStream << "0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(minValue);
            // Format Max
            strStream << ", 0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(maxValue);

        } else {

            strStream << minValue << ", " <<  maxValue;
        }

        strStream << "] for " << getKind();

        parameterAccessContext.setError(strStream.str());

        return false;
    }
    return true;
}
// Conversion
bool CBitParameterType::toBlackboard(const string& strValue, uint64_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    // Hexa
    bool bValueProvidedAsHexa = !strValue.compare(0, 2, "0x");

    // Get value
    uint64_t uiConvertedValue = strtoull(strValue.c_str(), NULL, 0);

    if (uiConvertedValue > _uiMax) {

        // Range exceeded
        std::ostringstream strStream;

        strStream << "Value " << strValue << " standing out of admitted range [";

        if (bValueProvidedAsHexa) {

            strStream << "0x0, " << "0x" << std::hex << std::uppercase;
        } else {

            strStream << "0, ";
        }
        strStream << _uiMax << "] for " + getKind();

        parameterAccessContext.setError(strStream.str());

        return false;
    }

    // Do bitwise RMW operation
    uiValue = (uiValue & ~getMask()) | (uiConvertedValue << _uiBitPos);

    return true;
}
// Conversion (tuning)
bool CEnumParameterType::toBlackboard(const string &strValue, uint32_t &uiValue,
                                      CParameterAccessContext &parameterAccessContext) const
{
    int32_t iParsedUserValue = 0;

    // Try to read the user-provided string as an integer
    if (not convertTo(strValue, iParsedUserValue)) {
        // If it fails to parse as an integer, first try to convert it from
        // lexical to numerical space.
        int32_t iNumerical;
        if (not getNumerical(strValue, iNumerical)) {

            parameterAccessContext.setError("Provided value '" + strValue +
                                            "' is not part of the lexical space"
                                            " or not within the numerical range.");

            return false;
        }
        iParsedUserValue = iNumerical;
    }

    // Once it has been converted to a number (either through parsing or
    // through lexical->numerical conversion), call the numerical overload of
    // toBlackboard.
    return toBlackboard(iParsedUserValue, uiValue, parameterAccessContext);
}
// Sync
bool CInstanceConfigurableElement::sync(CParameterAccessContext& parameterAccessContext) const
{
    ISyncer* pSyncer = getSyncer();

    if (!pSyncer) {

        parameterAccessContext.setError("Unable to synchronize modification. No Syncer object associated to configurable element:");

        return false;
    }
    string strError;

    if (!pSyncer->sync(*parameterAccessContext.getParameterBlackboard(), false, strError)) {

        parameterAccessContext.setError(strError);

        return false;
    }
    return true;
}
// Parameter access
bool CConfigurableElement::accessValue(CPathNavigator& pathNavigator, string& strValue, bool bSet, CParameterAccessContext& parameterAccessContext) const
{
    string* pStrChildName = pathNavigator.next();

    if (!pStrChildName) {

        parameterAccessContext.setError("Non accessible element");

        return false;
    }

    const CConfigurableElement* pChild = static_cast<const CConfigurableElement*>(findChild(*pStrChildName));

    if (!pChild) {

        parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());

        return false;
    }

    return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
}
void CFixedPointParameterType::setOutOfRangeError(const string& strValue, CParameterAccessContext& parameterAccessContext) const
{
    std::ostringstream strStream;

    strStream << "Value " << strValue << " standing out of admitted ";

    if (!parameterAccessContext.valueSpaceIsRaw()) {

        // Min/Max computation
        double dMin = 0;
        double dMax = 0;
        getRange(dMin, dMax);

        strStream << std::fixed << std::setprecision(_uiFractional)
                  << "real range [" << dMin << ", " << dMax << "]";
    } else {

        // Min/Max computation
        int32_t iMax = getMaxValue<uint32_t>();
        int32_t iMin = -iMax - 1;

        strStream << "raw range [";

        if (isHexadecimal(strValue)) {

            // Format Min
            strStream << "0x" << std::hex << std::uppercase <<
                      std::setw(getSize() * 2) << std::setfill('0') << makeEncodable(iMin);
            // Format Max
            strStream << ", 0x" << std::hex << std::uppercase <<
                      std::setw(getSize() * 2) << std::setfill('0') << makeEncodable(iMax);

        } else {

            strStream << iMin << ", " << iMax;
        }

        strStream << "]";
    }
    strStream << " for " << getKind();

    parameterAccessContext.setError(strStream.str());
}
// Numerical validity of the enum value
bool CEnumParameterType::isValid(int iNumerical, CParameterAccessContext& parameterAccessContext) const
{
    // Check that the value is part of the allowed values for this kind of enum
    size_t uiChild;
    size_t uiNbChildren = getNbChildren();

    for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {

        const CEnumValuePair* pValuePair = static_cast<const CEnumValuePair*>(getChild(uiChild));

        if (pValuePair->getNumerical() == iNumerical) {

            return true;
        }
    }

    parameterAccessContext.setError("Provided value not part of numerical space");

    return false;
}
// Value access
bool CFixedPointParameterType::toBlackboard(double dUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    // Check that the value is within the allowed range for this type
    if (!checkValueAgainstRange(dUserValue)) {

        // Illegal value provided
        parameterAccessContext.setError("Value out of range");

        return false;
    }

    // Do the conversion
    int32_t iData = doubleToBinaryQnm(dUserValue);

    // Check integrity
    assert(isEncodable((uint32_t)iData, true));

    uiValue = iData;

    return true;
}
bool CFixedPointParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    bool bValueProvidedAsHexa = isHexadecimal(strValue);

    // Check data integrity
    if (bValueProvidedAsHexa && !parameterAccessContext.valueSpaceIsRaw()) {

        parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() + " when selected value space is real:");

        return false;
    }

    if (parameterAccessContext.valueSpaceIsRaw()) {

        if (bValueProvidedAsHexa) {

            return convertFromHexadecimal(strValue, uiValue, parameterAccessContext);

        }
        return convertFromDecimal(strValue, uiValue, parameterAccessContext);
    }
    return convertFromQnm(strValue, uiValue, parameterAccessContext);
}
// Conversion (tuning)
bool CEnumParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    int64_t iData;

    if (isNumber(strValue)) {

        /// Numerical value provided

        // Hexa
        bool bValueProvidedAsHexa = !strValue.compare(0, 2, "0x");

        errno = 0;
        char *pcStrEnd;

        // Get value
        iData = strtoll(strValue.c_str(), &pcStrEnd, 0);

        // Conversion error when the input string does not contain any digit or the number is out of range (int32_t type)
        bool bConversionSucceeded = !errno && (strValue.c_str() != pcStrEnd);

        // Check validity against type
        if (!checkValueAgainstRange(strValue, iData, parameterAccessContext, bValueProvidedAsHexa, bConversionSucceeded)) {

            return false;
        }

        if (bValueProvidedAsHexa) {

            // Sign extend
            signExtend(iData);
        }

        // Check validity against lexical space
        string strError;
        if (!isValid(iData, parameterAccessContext)) {

            parameterAccessContext.setError(strError);

            return false;
        }
    } else {
        /// Literal value provided

        // Check validity against lexical space
        int iNumerical;
        if (!getNumerical(strValue, iNumerical)) {

            parameterAccessContext.setError("Provided value not part of lexical space");

            return false;
        }
        iData = iNumerical;

        // Check validity against type
        if (!checkValueAgainstRange(strValue, iData, parameterAccessContext, false, isEncodable((uint64_t)iData, true))) {

            return false;
        }
    }

    // Return data
    uiValue = (uint32_t)iData;

    return true;
}