package org.opentosca.toscana.core.csar;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.opentosca.toscana.core.parse.InvalidCsarException;
import org.opentosca.toscana.core.transformation.logging.Log;

import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;

public class CustomTypeInjector {

    private final static File CUSTOM_TYPE_DEFINITION_ROOT = new File(CustomTypeInjector.class.getResource("/tosca_definitions").getFile());
    private final static File NODE_TYPE_DEFINITIONS = new File(CUSTOM_TYPE_DEFINITION_ROOT, "node");
    private final static String NOTE = "  # autogenerated by toscana";

    private final Log log;
    private final Logger logger;

    public CustomTypeInjector(Log log) {
        this.log = log;
        this.logger = log.getLogger(CustomTypeInjector.class);
    }

    /**
     Injects custom TOSCA node type definitions into service templates, if necessary
     */
    public void inject(Csar csar) {
        try {
            File serviceTemplate = csar.getTemplate();
            String templateContent = FileUtils.readFileToString(serviceTemplate);
            List<String> template = Lists.newArrayList(templateContent.split("\n"));

            for (File nodeTypeDefinition : NODE_TYPE_DEFINITIONS.listFiles()) {
                if (isRequired(nodeTypeDefinition, templateContent)) {
                    template = inject(template, nodeTypeDefinition, "node_types:");
                }
            }
            FileUtils.writeLines(serviceTemplate, template);
        } catch (InvalidCsarException | IOException e) {
            logger.error("Failed to inject custom types into csar", e);
        }
    }

    private boolean isRequired(File nodeTypeDefinition, String templateContent) {
        String typeName = nodeTypeDefinition.getName().replace(".yaml", "");
        String typeAssignment = "type: " + typeName;
        return (templateContent.contains(typeAssignment));
    }

    private List<String> inject(List<String> template, File typeDefinition, String location) throws IOException {
        String typeDefinitionString = FileUtils.readFileToString(typeDefinition);
        List<String> definitionContent = Lists.newArrayList(typeDefinitionString.split("\n"));
        definitionContent.add(0, NOTE);
        definitionContent.add("");
        List<String> injectedTemplate = new LinkedList<>();
        boolean injected = false;
        for (String line : template) {
            injectedTemplate.add(line);
            if (line.startsWith(location) && !injected) {
                injectedTemplate.addAll(definitionContent);
                injected = true;
            }
        }
        if (!injected) {
            injectedTemplate.add("");
            injectedTemplate.add(location);
            injectedTemplate.addAll(definitionContent);
        }
        return injectedTemplate;
    }
}

@@ -80,24 +80,78 @@
 OException;%0A
+import java.io.InputStream;%0Aimport java.util.HashMap;%0A
 import java.
@@ -189,16 +189,38 @@
 il.List;
+%0Aimport java.util.Map;
 %0A%0Aimport
@@ -418,16 +418,54 @@
 eUtils;%0A
+import org.apache.commons.io.IOUtils;%0A
 import o
@@ -542,20 +542,22 @@
  static 
-File
+String
  CUSTOM_
@@ -583,54 +583,8 @@
 T = 
-new File(CustomTypeInjector.class.getResource(
 %22/to
@@ -603,20 +603,8 @@
 ons%22
-).getFile())
 ;%0A  
@@ -630,81 +630,150 @@
 tic 
-File NODE_TYPE_DEFINITIONS = new File(CUSTOM_TYPE_DEFINITION_ROOT, %22node%22
+String NODES = CUSTOM_TYPE_DEFINITION_ROOT + %22/node%22;%0A    private final static Map%3CString, InputStream%3E NODE_TYPE_DEFINITIONS = new HashMap%3C%3E(
 );%0A 
@@ -904,16 +904,123 @@
 ogger;%0A%0A
+    static %7B%0A        loadDefinitions(%22toscana.nodes.JavaApplication%22, %22toscana.nodes.JavaRuntime%22);%0A    %7D%0A%0A
     publ
@@ -1142,24 +1142,497 @@
 ss);%0A    %7D%0A%0A
+    private static void loadDefinitions(String... fileNames) %7B%0A        for (String fileName : fileNames) %7B%0A            String definitionPath = String.format(%22%25s/%25s.yaml%22, NODES, fileName);%0A            System.out.println(definitionPath);%0A            InputStream definitionStream = CustomTypeInjector.class.getResourceAsStream(definitionPath);%0A            assert (definitionStream != null);%0A            NODE_TYPE_DEFINITIONS.put(fileName, definitionStream);%0A        %7D%0A    %7D%0A%0A
     /**%0A    
@@ -2010,30 +2010,48 @@
    for (
-File nodeTypeD
+Map.Entry%3CString, InputStream%3E d
 efinitio
@@ -2080,17 +2080,16 @@
 ONS.
-listFiles
+entrySet
 ()) 
@@ -2121,34 +2121,35 @@
 equired(
-nodeTypeDefinition
+definition.getKey()
 , templa
@@ -2210,34 +2210,37 @@
 mplate, 
-nodeTypeDefinition
+definition.getValue()
 , %22node_
@@ -2523,22 +2523,16 @@
 red(
-File nodeTypeD
+String d
 efin
@@ -2528,32 +2528,36 @@
 tring definition
+Name
 , String templat
@@ -2598,57 +2598,22 @@
 e = 
-nodeTypeDefinition.getName().replace(%22.yaml%22, %22%22)
+definitionName
 ;%0A  
@@ -2788,18 +2788,21 @@
 te, 
-File typeD
+InputStream d
 efin
@@ -2888,35 +2888,25 @@
 g = 
-File
+IO
 Utils.
-readFileT
+t
 oString(
 type
@@ -2901,21 +2901,17 @@
 oString(
-typeD
+d
 efinitio
@@ -2907,24 +2907,33 @@
 g(definition
+, %22UTF-8%22
 );%0A        L

Fix resource loading in TypeInjector (#560)