/*
 * Copyright 2012-2013 by Cloudsoft Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package brooklyn.util.text;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.entity.basic.EntityInternal;
import brooklyn.entity.drivers.EntityDriver;
import brooklyn.util.exceptions.Exceptions;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;

import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;

public class TemplateProcessor {

    private static final Logger log = LoggerFactory.getLogger(TemplateProcessor.class);

    public static String processTemplate(String templateFileName, Map<String, ? extends Object> substitutions) {
        String templateContents;
        try {
            templateContents = Files.toString(new File(templateFileName), Charsets.UTF_8);
        } catch (IOException e) {
            log.warn("Error loading file " + templateFileName, e);
            throw Exceptions.propagate(e);
        }
        return processTemplateContents(templateContents, substitutions);
    }

    public static String processTemplate(String templateFileName, EntityDriver driver, Map<String, ? extends Object> extraSubstitutions) {
        String templateContents;
        try {
            templateContents = Files.toString(new File(templateFileName), Charsets.UTF_8);
        } catch (IOException e) {
            log.warn("Error loading file " + templateFileName, e);
            throw Exceptions.propagate(e);
        }
        return processTemplateContents(templateContents, driver, extraSubstitutions);
    }

    public static String processTemplateContents(String templateContents, EntityDriver driver, Map<String,? extends Object> extraSubstitutions) {
         Map<String, Object> config = driver.getEntity().getApplication().getManagementContext().getConfig().asMapWithStringKeys();
         Map<String, Object> substitutions = ImmutableMap.<String, Object>builder()
                    .putAll(config)
                    .put("driver", driver)
                    .put("entity", driver.getEntity())
                    .put("location", driver.getLocation())
                    .put("config", ((EntityInternal) driver.getEntity()).getConfigMap().asMapWithStringKeys())
                    .putAll(extraSubstitutions)
                    .build();

         return processTemplateContents(templateContents, substitutions);
    }

    public static String processTemplateContents(String templateContents, Map<String, ? extends Object> substitutions) {
        try {
            Configuration cfg = new Configuration();
            StringTemplateLoader templateLoader = new StringTemplateLoader();
            templateLoader.putTemplate("config", templateContents);
            cfg.setTemplateLoader(templateLoader);
            Template template = cfg.getTemplate("config");

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Writer out = new OutputStreamWriter(baos);
            template.process(substitutions, out);
            out.flush();

            return new String(baos.toByteArray());
        } catch (Exception e) {
            log.warn("Error processing template " + templateContents + " with vars " + substitutions, e);
            throw Exceptions.propagate(e);
        }
    }
}

@@ -2513,33 +2513,32 @@
 ions) %7B%0A        
- 
 Map%3CString, Obje
@@ -2648,28 +2648,44 @@
 ();%0A        
- Map
+ImmutableMap.Builder
 %3CString, Obj
@@ -2689,29 +2689,23 @@
 Object%3E 
-substitutions
+builder
  = Immut
@@ -2746,36 +2746,32 @@
                 
-    
 .putAll(config)%0A
@@ -2782,28 +2782,24 @@
             
-  
-  
 .put(%22driver
@@ -2809,20 +2809,16 @@
 driver)%0A
-    
         
@@ -2864,71 +2864,8 @@
 ())%0A
-                    .put(%22location%22, driver.getLocation())%0A    
     
@@ -2966,16 +2966,17 @@
 gKeys())
+;
 %0A       
@@ -2980,80 +2980,134 @@
     
-            .putAll(extraSubstitutions)%0A                    .build(
+if (driver.getLocation() != null) builder.put(%22location%22, driver.getLocation());%0A        builder.putAll(extraSubstitutions
 );%0A%0A
- 
     
@@ -3155,37 +3155,39 @@
 teContents, 
-substitutions
+builder.build()
 );%0A    %7D%0A%0A  

Check that location is not null before adding to substitutions