class FunctionEvaluator {

    public static String parseAttribute(String attributeId, IValue attributeValue, Topology topology,
            Map<String, Map<String, InstanceInformation>> runtimeInformations, String currentInstance,
            IPaaSTemplate<? extends AbstractToscaType> basePaaSTemplate, Map<String, PaaSNodeTemplate> builtPaaSTemplates) {

        if (attributeValue == null) {
            return null;
        }

        // handle AttributeDefinition type
        if (attributeValue instanceof AttributeDefinition) {
            String runtimeAttributeValue = extractRuntimeInformationAttribute(runtimeInformations, currentInstance, Lists.newArrayList(basePaaSTemplate),
                    attributeId);
            if (runtimeAttributeValue != null) {
                if (!runtimeAttributeValue.contains("=Error!]") && !runtimeAttributeValue.equals("")) {
                    return runtimeAttributeValue;
                }
            }

            return ((AttributeDefinition) attributeValue).getDefault();
        }

        // handle concat function
        if (attributeValue instanceof ConcatPropertyValue) {
            StringBuilder evaluatedAttribute = new StringBuilder();
            ConcatPropertyValue concatPropertyValue = (ConcatPropertyValue) attributeValue;
            for (IValue concatParam : concatPropertyValue.getParameters()) {
                // scalar type
                if (concatParam instanceof ScalarPropertyValue) {
                    // scalar case
                    evaluatedAttribute.append(((ScalarPropertyValue) concatParam).getValue());
                } else if (concatParam instanceof PropertyDefinition) {
                    // Definition case
                    // TODO : ?? what should i do here ?? currently returns default value in the definition
                    evaluatedAttribute.append(((PropertyDefinition) concatParam).getDefault());
                } else if (concatParam instanceof FunctionPropertyValue) {
                    // Function case
                    FunctionPropertyValue functionPropertyValue = (FunctionPropertyValue) concatParam;
                    List<? extends IPaaSTemplate> paasTemplates = getPaaSTemplatesFromKeyword(basePaaSTemplate, functionPropertyValue.getTemplateName(),
                            builtPaaSTemplates);
                    switch (functionPropertyValue.getFunction()) {
                    case ToscaFunctionConstants.GET_ATTRIBUTE:
                        evaluatedAttribute.append(extractRuntimeInformationAttribute(runtimeInformations, currentInstance, paasTemplates,
                                functionPropertyValue.getElementNameToFetch()));
                        break;
                    case ToscaFunctionConstants.GET_PROPERTY:
                        evaluatedAttribute.append(extractRuntimeInformationProperty(topology, functionPropertyValue.getElementNameToFetch(), paasTemplates));
                        break;
                    case ToscaFunctionConstants.GET_OPERATION_OUTPUT:
                        String defaultValue = "<" + functionPropertyValue.getElementNameToFetch() + ">";
                        evaluatedAttribute.append(extractRuntimeInformationOperationOutput(runtimeInformations, currentInstance, paasTemplates,
                                functionPropertyValue, defaultValue));
                        break;
                    default:
                        log.warn("Function [{}] is not yet handled in concat operation.", functionPropertyValue.getFunction());
                        break;
                    }

                }
            }
            return evaluatedAttribute.toString();
        }

        // handle functions. For now, only support Get_OPERATION_OUTPUT on attributes scope
        if (attributeValue instanceof FunctionPropertyValue) {
            FunctionPropertyValue function = (FunctionPropertyValue) attributeValue;
            switch (function.getFunction()) {
            case ToscaFunctionConstants.GET_OPERATION_OUTPUT:
                List<? extends IPaaSTemplate> paasTemplates = getPaaSTemplatesFromKeyword(basePaaSTemplate, function.getTemplateName(), builtPaaSTemplates);
                return extractRuntimeInformationOperationOutput(runtimeInformations, currentInstance, paasTemplates, function, null);
            default:
                return null;
            }
        }

        return null;
    }

}