%dw 2.0

output application/dw

input in0 application/xml

fun convertToMetadataTypeFormat(format) = format match {
		case "csv" -> "APPLICATION_CSV"
        case "xml" -> "APPLICATION_XML"
        case "json" -> "APPLICATION_JSON"
        case "java" -> "APPLICATION_JAVA"
        case "excel" -> "APPLICATION_EXCEL"
        case "fixedWidth" -> "APPLICATION_FIXED_WIDTH"
        case "flatfile" -> "APPLICATION_FLAT_FILE"
        case "copybook" -> "APPLICATION_COPYBOOK"
        else -> null
    }

fun convertToMetadataTypeOrigin(format, origin) = log(format) match {
        case "json" -> origin match {
            case "json" -> "EXAMPLE"
            case "json-schema" -> "SCHEMA"
            case "weave" -> "WEAVE"
        }
        case "xml" -> origin match {
            case "xml" -> "EXAMPLE"
            case "xml-schema" -> "SCHEMA"
        }
        case "java" -> origin match {
            case "raml" -> "RAML"
            case "java" -> "SCHEMA"
        }
        case "CSV" -> origin match {
            case "raml" -> "RAML"
            case "weave" -> "WEAVE"
        }
        case "copybook" -> "SCHEMA"
        case "flatfile" -> "SCHEMA"
        case "fixedWidth" -> "SCHEMA"
        else -> upper(origin)
    }

fun resolveElement(elementType) = if (elementType.example?) "example" else "shape"

fun resolveEvent(container, eventType) = container[eventType]

fun isCollection(typeRef) = if (not typeRef is Null) typeRef endsWith "[]" else false

fun stripWrapper(typeRef) = typeRef[0 to -3]

fun resolveProcessorDeclaration(processors, eventType) = do {
    var event = resolveEvent(processors, eventType)
    ---
    {
        payload: using (elementType = event.message.payload.@"type", collection = isCollection(elementType)) {
            id: if (not elementType is Null) trim(if (collection) stripWrapper(elementType) else elementType) else null,
            collection: collection
        } as Object { class: "org.mule.tooling.metadata.types.model.TypeRef" },
        attributes: using (elementType = event.message.attributes.@"type", collection = isCollection(elementType)) {
            id: if (not elementType is Null) trim (if (collection) stripWrapper(elementType) else elementType) else null,
            collection: collection
        } as Object { class: "org.mule.tooling.metadata.types.model.TypeRef" },
        variables: using (variables = event.variables default {}) {
            (
                variables pluck {
                    ($$.@name): using (collection = isCollection($$.@"type")) {
                        id: if (not $$.@"type" is Null) trim (if (collection) stripWrapper($$.@"type") else $$.@"type") else null,
                        collection: collection
                    } as Object { class: "org.mule.tooling.metadata.types.model.TypeRef" }
                }
            )
        }
    }
}

var emptyEvent = {
	payload: {
	    id: null,
		collection: false
	} as Object { class: "org.mule.tooling.metadata.types.model.TypeRef" },
	attributes: {
		id: null,
		collection: false
	} as Object { class: "org.mule.tooling.metadata.types.model.TypeRef" },
	variables: {}
}

var content = if (in0.mule is Object) in0.mule else {}
var defaultCatalog = if (content.catalog is Object) content.catalog else null
var enrichments = content.*enrichment default []

fun asTypeRef(elementType) = do {
    var collection = isCollection(elementType)
    ---
    {
      id: if (not elementType is Null)
              trim(if (collection) stripWrapper(elementType) else elementType)
          else
              null,
      collection: collection
    }
}
---
{
  catalogs: {
    "default": if (not defaultCatalog is Null)
                {
                  (
                    defaultCatalog.*"type" default [] map ($.@name): {
                      name: $.@name,
                      format: convertToMetadataTypeFormat($.@format),
                      origin: convertToMetadataTypeOrigin($.@format, log($[resolveElement($)].@format)),
                      content: $[resolveElement($)],
                      additionalInformation: using (
                          location = $[resolveElement($)].@location,
                          example = $[resolveElement($)].@example,
                          element = $[resolveElement($)].@element
                          ) {
                            (location: location) if (not location is Null),
                            (example: example) if (not example is Null),
                            (element: element) if (not element is Null)
                      },
                      properties: $.properties mapObject {
                        ($$.@name): $$.@value
                      }
                    } as Object { class: "org.mule.tooling.metadata.types.model.MetadataTypeDefinition" }
                  )
                }
               else {}
  },
  enrichers: {
      (
          enrichments map ((enrichment) -> {
              (enrichment.@select[1 to -1]): do {
                var processorDeclaration = enrichment["processor-declaration"]
                 ---
                 {
                      "input": if (processorDeclaration is Object) resolveProcessorDeclaration(processorDeclaration, "input-event") else emptyEvent,
                      "output": if (processorDeclaration is Object) resolveProcessorDeclaration(processorDeclaration, "output-event") else emptyEvent,
                      (operation: {
                          ("params": enrichment."operation-declaration".inputs.*parameter map (param) -> {
                                name: param.@name,
                                typeRef: asTypeRef(param.@"type")
                            }
                          ) if (enrichment."operation-declaration".inputs.*parameter?) ,
                          ("output": {
                                (payload: asTypeRef(enrichment."operation-declaration".outputs.payload.@"type")) if (enrichment."operation-declaration".outputs.payload?),
                                (attributes: asTypeRef(enrichment."operation-declaration".outputs.attributes.@"type")) if (enrichment."operation-declaration".outputs.attributes?),
                          }) if (enrichment."operation-declaration".outputs?)
                      }) if (enrichment."operation-declaration"?)
                 } as Object { class: "org.mule.tooling.metadata.types.model.MessageProcessorEnricher" }
              }
          })
      )
  }
} as Object { class: "org.mule.tooling.metadata.types.model.CustomMetadataDefinition" }