class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin {

    @SuppressWarnings("unchecked")
    @Override
    public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName,
            VduModelInfo vduModel, String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion,
            int timeoutMinutes, String environment, Map<String, Object> files, Map<String, Object> heatFiles,
            boolean backout, boolean failIfExists) throws MsoException {

        logger.trace("Started MsoMulticloudUtils.createStack");

        // Get the directives, if present.
        String oofDirectives = "{}";
        String sdncDirectives = "{}";
        String userDirectives = "{}";
        String genericVnfId = "";
        String vfModuleId = "";
        String templateType = "";

        for (String key : MULTICLOUD_INPUTS) {
            if (!stackInputs.isEmpty() && stackInputs.containsKey(key)) {
                if (key == OOF_DIRECTIVES) {
                    oofDirectives = (String) stackInputs.get(key);
                }
                if (key == SDNC_DIRECTIVES) {
                    sdncDirectives = (String) stackInputs.get(key);
                }
                if (key == USER_DIRECTIVES) {
                    userDirectives = (String) stackInputs.get(key);
                }
                if (key == TEMPLATE_TYPE) {
                    templateType = (String) stackInputs.get(key);
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(String.format("Found %s: %s", key, stackInputs.get(key)));
                }
                stackInputs.remove(key);
            }
        }

        if (!stackInputs.isEmpty() && stackInputs.containsKey(VF_MODULE_ID)) {
            vfModuleId = (String) stackInputs.get(VF_MODULE_ID);
        }
        if (!stackInputs.isEmpty() && stackInputs.containsKey(VNF_ID)) {
            genericVnfId = (String) stackInputs.get(VNF_ID);
        }

        // create the multicloud payload
        CreateStackParam stack =
                createStackParam(stackName, heatTemplate, stackInputs, timeoutMinutes, environment, files, heatFiles);

        MulticloudRequest multicloudRequest = new MulticloudRequest();

        multicloudRequest.setGenericVnfId(genericVnfId);
        multicloudRequest.setVfModuleId(vfModuleId);
        multicloudRequest.setVfModuleModelInvariantId(vduModel.getModelInvariantUUID());
        multicloudRequest.setVfModuleModelVersionId(vduModel.getModelUUID());
        multicloudRequest.setVfModuleModelCustomizationId(vduModel.getModelCustomizationUUID());
        multicloudRequest.setTemplateType(templateType);
        multicloudRequest.setTemplateData(stack);
        multicloudRequest.setOofDirectives(getDirectiveNode(oofDirectives));
        multicloudRequest.setSdncDirectives(getDirectiveNode(sdncDirectives));
        multicloudRequest.setUserDirectives(getDirectiveNode(userDirectives));
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Multicloud Request is: %s", multicloudRequest.toString()));
        }

        String multicloudEndpoint = getMulticloudEndpoint(cloudSiteId, cloudOwner, null, false);
        RestClient multicloudClient = getMulticloudClient(multicloudEndpoint, tenantId);

        if (multicloudClient == null) {
            MsoOpenstackException me = new MsoOpenstackException(0, "", "Multicloud client could not be initialized");
            me.addContext(CREATE_STACK);
            throw me;
        }

        Response response = multicloudClient.post(multicloudRequest);

        MulticloudCreateResponse multicloudResponseBody = null;
        if (response.hasEntity()) {
            multicloudResponseBody = getCreateBody((java.io.InputStream) response.getEntity());
        }
        if (response.getStatus() == Response.Status.CREATED.getStatusCode() && response.hasEntity()) {
            String canonicalName = stackName + "/";
            if (multicloudResponseBody != null) {
                canonicalName = canonicalName + multicloudResponseBody.getWorkloadId();
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Multicloud Create Response Body: {}", multicloudResponseBody);
            }
            StackInfo stackStatus = getStackStatus(cloudSiteId, cloudOwner, tenantId, canonicalName, pollForCompletion,
                    timeoutMinutes, backout);

            if (HeatStatus.CREATED.equals(stackStatus.getStatus())) {
                multicloudAaiUpdate(cloudSiteId, cloudOwner, tenantId, genericVnfId, vfModuleId, canonicalName,
                        pollForCompletion, timeoutMinutes);
            }

            return stackStatus;
        }
        StringBuilder stackErrorStatusReason = new StringBuilder(response.getStatusInfo().getReasonPhrase());
        if (null != multicloudResponseBody) {
            stackErrorStatusReason.append(multicloudResponseBody.toString());
        }
        MsoOpenstackException me = new MsoOpenstackException(0, "", stackErrorStatusReason.toString());
        me.addContext(CREATE_STACK);
        throw me;
    }

}