package org.mapfish.print.config;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.NodeId;

import java.util.Map;

/**
 * The interface to SnakeYaml that is responsible for creating the different objects during parsing the config
 * yaml files.
 * <p></p>
 * The objects are created using spring dependency injection so that the methods are correctly wired using
 * spring.
 * <p></p>
 * If an object has the interface HashConfiguration then this class will inject the configuration object after
 * creating the object.
 * <p></p>
 */
public final class MapfishPrintConstructor extends Constructor {
    private static final String CONFIGURATION_TAG = "configuration";
    private static final ThreadLocal<Configuration> CONFIGURATION_UNDER_CONSTRUCTION =
            new InheritableThreadLocal<>();
    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(MapfishPrintConstructor.class);

    /**
     * Constructor.
     *
     * @param context the application context object for creating
     */
    public MapfishPrintConstructor(final ConfigurableApplicationContext context) {
        super(new TypeDescription(Configuration.class, CONFIGURATION_TAG));
        Map<String, ConfigurationObject> yamlObjects = context.getBeansOfType(ConfigurationObject.class);
        for (Map.Entry<String, ConfigurationObject> entry: yamlObjects.entrySet()) {
            final BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(entry.getKey());
            final String message =
                    "Error: Spring bean: " + entry.getKey() + " is not defined as scope = prototype";
            if (!beanDefinition.isPrototype()) {
                LOGGER.error(message);
                throw new AssertionError(message);
            }
            addTypeDescription(new TypeDescription(entry.getValue().getClass(), "!" + entry.getKey()));
        }

        MapfishPrintConstruct construct = new MapfishPrintConstruct(context);
        super.yamlClassConstructors.put(NodeId.mapping, construct);
    }

    static void setConfigurationUnderConstruction(final Configuration config) {
        CONFIGURATION_UNDER_CONSTRUCTION.set(config);
    }

    /**
     * The object that will create the yaml object using the spring application context.
     */
    private final class MapfishPrintConstruct extends ConstructMapping {
        private final ApplicationContext applicationContext;

        private MapfishPrintConstruct(final ApplicationContext context) {
            this.applicationContext = context;
        }


        @Override
        protected Object constructJavaBean2ndStep(final MappingNode node, final Object object) {
            return super.constructJavaBean2ndStep(node, object);
        }

        @Override
        protected Object createEmptyJavaBean(final MappingNode node) {
            if (node.getType() == Configuration.class) {
                return getConfiguration();
            }
            Object bean;
            try {
                bean = this.applicationContext.getBean(node.getTag().getValue().substring(1));
            } catch (NoSuchBeanDefinitionException e) {
                bean = this.applicationContext.getBean(node.getType());
            }

            if (bean instanceof HasConfiguration) {
                ((HasConfiguration) bean).setConfiguration(getConfiguration());
            }

            return bean;
        }

        private Configuration getConfiguration() {
            return MapfishPrintConstructor.this.CONFIGURATION_UNDER_CONSTRUCTION.get();
        }
    }
}

@@ -200,63 +200,8 @@
 on;%0A
-import org.springframework.context.ApplicationContext;%0A
 impo
@@ -393,59 +393,12 @@
 des.
-MappingNode;%0Aimport org.yaml.snakeyaml.nodes.NodeId
+Node
 ;%0A%0Ai
@@ -1210,16 +1210,74 @@
 .class);
+%0A    private final ConfigurableApplicationContext context;
 %0A%0A    /*
@@ -1534,24 +1534,56 @@
 TION_TAG));%0A
+        this.context = context;%0A
         Map%3C
@@ -1867,24 +1867,77 @@
 .getKey());%0A
+            if (!beanDefinition.isPrototype()) %7B%0A    
             
@@ -1959,16 +1959,20 @@
 ssage =%0A
+    
         
@@ -2069,57 +2069,8 @@
 e%22;%0A
-            if (!beanDefinition.isPrototype()) %7B%0A
     
@@ -2286,155 +2286,8 @@
    %7D
-%0A%0A        MapfishPrintConstruct construct = new MapfishPrintConstruct(context);%0A        super.yamlClassConstructors.put(NodeId.mapping, construct);
 %0A   
@@ -2435,385 +2435,8 @@
  %7D%0A%0A
-    /**%0A     * The object that will create the yaml object using the spring application context.%0A     */%0A    private final class MapfishPrintConstruct extends ConstructMapping %7B%0A        private final ApplicationContext applicationContext;%0A%0A        private MapfishPrintConstruct(final ApplicationContext context) %7B%0A            this.applicationContext = context;%0A        %7D%0A%0A%0A    
     
@@ -2441,36 +2441,32 @@
   @Override%0A    
-  
-  
 protected Object
@@ -2470,232 +2470,26 @@
 ect 
-constructJavaBean2ndStep(final MappingNode node, final Object object) %7B%0A            return super.constructJavaBean2ndStep(node, object);%0A        %7D%0A%0A        @Override%0A        protected Object createEmptyJavaBean(final Mapping
+newInstance(final 
 Node
@@ -2493,28 +2493,24 @@
 ode node) %7B%0A
-    
         if (
@@ -2566,35 +2566,51 @@
     
-    
 return 
-getConfiguration
+CONFIGURATION_UNDER_CONSTRUCTION.get
 ();%0A
@@ -2613,34 +2613,26 @@
 ();%0A        
-    %7D%0A    
+%7D%0A
         Obje
@@ -2648,20 +2648,16 @@
         
-    
 try %7B%0A  
@@ -2658,36 +2658,32 @@
 y %7B%0A            
-  
-  
 bean = this.appl
@@ -2674,36 +2674,25 @@
 bean = this.
-applicationC
+c
 ontext.getBe
@@ -2742,20 +2742,16 @@
         
- 
-   
 %7D catch 
@@ -2790,36 +2790,32 @@
 ) %7B%0A            
-    
 bean = this.appl
@@ -2814,20 +2814,9 @@
 his.
-applicationC
+c
 onte
@@ -2847,35 +2847,27 @@
 ));%0A        
-   
- 
 %7D%0A%0A
-    
         if (
@@ -2914,20 +2914,16 @@
         
-  
-  
 ((HasCon
@@ -2961,179 +2961,8 @@
 ion(
-getConfiguration());%0A            %7D%0A%0A            return bean;%0A        %7D%0A%0A        private Configuration getConfiguration() %7B%0A            return MapfishPrintConstructor.this.
 CONF
@@ -2987,32 +2987,33 @@
 NSTRUCTION.get()
+)
 ;%0A        %7D%0A    
@@ -3003,21 +3003,43 @@
 );%0A        %7D
+%0A%0A        return bean;
 %0A    %7D%0A%7D%0A

Fix build