VolumeProfile::VolumeProfile(const string &mappingValue,
                             CInstanceConfigurableElement *instanceConfigurableElement,
                             const CMappingContext &context)
    : CFormattedSubsystemObject(instanceConfigurableElement,
                                mappingValue,
                                MappingKeyAmend1,
                                (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
                                context),
      mPolicySubsystem(static_cast<const PolicySubsystem *>(
                           instanceConfigurableElement->getBelongingSubsystem())),
      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
    uint32_t categoryKey = context.getItemAsInteger(MappingKeyCategory);
    if (categoryKey >= Volume::DEVICE_CATEGORY_CNT) {
        mCategory = Volume::DEVICE_CATEGORY_SPEAKER;
    } else {
        mCategory = static_cast<Volume::device_category>(categoryKey);
    }
    mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));

    // (no exception support, defer the error)
    if (instanceConfigurableElement->getType() != CInstanceConfigurableElement::EParameterBlock) {
        return;
    }
    // Get actual element type
    const CParameterBlockType *parameterType = static_cast<const CParameterBlockType *>(
                instanceConfigurableElement->getTypeElement());
    mPoints = parameterType->getArrayLength();
}
// Mapping generic context handling
bool CSubsystem::handleMappingContext(
        const CInstanceConfigurableElement* pInstanceConfigurableElement,
        CMappingContext& context,
        string& strError) const
{
    // Feed context with found mapping data
    uint32_t uiItem;

    for (uiItem = 0; uiItem < _contextMappingKeyArray.size(); uiItem++) {

        const string& strKey = _contextMappingKeyArray[uiItem];
        const string* pStrValue;

        if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
            // Assign item to context
            if (!context.setItem(uiItem, &strKey, pStrValue)) {

                strError = getMappingError(strKey, "Already set", pInstanceConfigurableElement);

                return false;
            }
        }
    }
    return true;
}
string CFormattedSubsystemObject::formatMappingValue(const string& strMappingValue,
                                                     uint32_t uiFirstAmendKey,
                                                     uint32_t uiNbAmendKeys,
                                                     const CMappingContext& context)
{
    string strFormattedValue = strMappingValue;

    // Search for amendment (only one supported for now)
    string::size_type uiPercentPos = strFormattedValue.find('%', 0);

    // Amendment limited to one digit (values from 1 to 9)
    assert(isAmendKeyValid(uiNbAmendKeys));

    // Check we found one and that there's room for value
    if (uiPercentPos != string::npos && uiPercentPos < strFormattedValue.size() - 1) {

        // Get Amend number
        uint32_t uiAmendNumber = strFormattedValue[uiPercentPos + 1] - '0';

        // Check if current Amend number is Valid
        if ((uiAmendNumber > 0) && (uiAmendNumber <= uiNbAmendKeys)) {

            uint32_t uiAmendType = uiFirstAmendKey + uiAmendNumber - 1;

            // Check if current Amend type is Set in the context
            if (context.iSet(uiAmendType)) {

                // Make the amendment on the part of the string after the current Amend
                string strEndOfLine = strFormattedValue.substr(uiPercentPos + 2,
                                                               strFormattedValue.size()
                                                               - uiPercentPos - 2);
                string strEndOfLineAmended = formatMappingValue(strEndOfLine, uiFirstAmendKey,
                                                                uiNbAmendKeys, context);

                // Get current Amend value
                string strAmendValue = context.getItem(uiAmendType);

                // Make the amendment
                strFormattedValue = strFormattedValue.substr(0, uiPercentPos) + strAmendValue
                        + strEndOfLineAmended;

            }
        }
    }
    return strFormattedValue;
}
AlsaCtlPortConfig::AlsaCtlPortConfig(const string &mappingValue,
                                     CInstanceConfigurableElement *instanceConfigurableElement,
                                     const CMappingContext &context,
                                     const PortConfig &defaultPortConfig)
    : base(mappingValue,
           instanceConfigurableElement,
           context),
      _device(context.getItemAsInteger(AlsaCtlDevice)),
      _portConfig(defaultPortConfig)
{

}
Stream::Stream(const string &mappingValue,
                   CInstanceConfigurableElement *instanceConfigurableElement,
                   const CMappingContext &context)
    : CFormattedSubsystemObject(instanceConfigurableElement,
                                mappingValue,
                                MappingKeyAmend1,
                                (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
                                context),
      mPolicySubsystem(static_cast<const PolicySubsystem *>(
                           instanceConfigurableElement->getBelongingSubsystem())),
      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
      mApplicableStrategy(mDefaultApplicableStrategy)
{
    mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));

    // Declares the strategy to audio policy engine
    mPolicyPluginInterface->addStream(getFormattedMappingValue(), mId);
}
// Subsystem object creation handling
bool CSubsystem::handleSubsystemObjectCreation(
        CInstanceConfigurableElement* pInstanceConfigurableElement,
        CMappingContext& context, bool& bHasCreatedSubsystemObject, string& strError)
{
    uint32_t uiItem;
    bHasCreatedSubsystemObject = false;

    for (uiItem = 0; uiItem < _subsystemObjectCreatorArray.size(); uiItem++) {

        const CSubsystemObjectCreator* pSubsystemObjectCreator =
                _subsystemObjectCreatorArray[uiItem];

        // Mapping key
        string strKey = pSubsystemObjectCreator->getMappingKey();
        // Object id
        const string* pStrValue;

        if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {

            // First check context consistency
            // (required ancestors must have been set prior to object creation)
            uint32_t uiAncestorKey;
            uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();

            for (uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size(); uiAncestorKey++) {

                if (!((1 << uiAncestorKey) & uiAncestorMask)) {
                    // Ancestor not required
                    continue;
                }
                // Check ancestor was provided
                if (!context.iSet(uiAncestorKey)) {

                    strError = getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] +
                                               " not set", pInstanceConfigurableElement);

                    return false;
                }
            }

            // Then check configurable element size is correct
            if (pInstanceConfigurableElement->getFootPrint() >
                pSubsystemObjectCreator->getMaxConfigurableElementSize()) {

                string strSizeError = "Size should not exceed " +
                                      pSubsystemObjectCreator->getMaxConfigurableElementSize();

                strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);

                return false;
            }

            // Do create object and keep its track
            _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
                    *pStrValue, pInstanceConfigurableElement, context));

            // Indicate subsytem creation to caller
            bHasCreatedSubsystemObject = true;

            // The subsystem Object has been instantiated, no need to continue looking for an
            // instantiation mapping
            break;
        }
    }

    return true;
}