package org.openehealth.ipf.modules.hl7.parser;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.Version;
import ca.uhn.hl7v2.model.Group;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.model.Type;
import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
import ca.uhn.hl7v2.parser.ModelClassFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * CustomModelClassFactory implementation that fixes a HAPI 2.2 bug and adds caching.
 * It is strongly recommended to use this class instead of {@link ca.uhn.hl7v2.parser.CustomModelClassFactory}
 */
public class CustomModelClassFactory extends ca.uhn.hl7v2.parser.CustomModelClassFactory {

    private ModelClassFactory defaultFactory;
    private static final ConcurrentMap<String, Class<?>> classMap = new ConcurrentHashMap<>();

    public CustomModelClassFactory() {
        this(null);
    }

    public CustomModelClassFactory(Map<String, String[]> map) {
        this(new DefaultModelClassFactory(), map);
    }

    public CustomModelClassFactory(String packageName, ModelClassFactory defaultFactory) {
        super(packageName);
        this.defaultFactory = defaultFactory;
    }

    public CustomModelClassFactory(ModelClassFactory defaultFactory, Map<String, String[]> map) {
        super(defaultFactory, map);
        this.defaultFactory = defaultFactory;
    }

    @Override
    public Class<? extends Message> getMessageClass(String name, String version, boolean isExplicit) throws HL7Exception {
        String key = "message" + name + version;
        Class<? extends Message> clazz = (Class<? extends Message>)classMap.get(key);
        if (clazz == null) {
            clazz = super.getMessageClass(name, version, isExplicit);
            classMap.putIfAbsent(key, clazz);
        }
        return clazz;
    }

    @Override
    public Class<? extends Group> getGroupClass(String name, String version) throws HL7Exception {
        String key = "group" + name + version;
        Class<? extends Group> clazz = (Class<? extends Group>)classMap.get(key);
        if (clazz == null) {
            clazz = super.getGroupClass(name, version);
            classMap.putIfAbsent(key, clazz);
        }
        return clazz;
    }

    @Override
    public Class<? extends Segment> getSegmentClass(String name, String version) throws HL7Exception {
        String key = "segment" + name + version;
        Class<? extends Segment> clazz = (Class<? extends Segment>)classMap.get(key);
        if (clazz == null) {
            clazz = super.getSegmentClass(name, version);
            classMap.putIfAbsent(key, clazz);
        }
        return clazz;
    }

    @Override
    public Class<? extends Type> getTypeClass(String name, String version) throws HL7Exception {
        String key = "type" + name + version;
        Class<? extends Type> clazz = (Class<? extends Type>)classMap.get(key);
        if (clazz == null) {
            clazz = super.getTypeClass(name, version);
            classMap.putIfAbsent(key, clazz);
        }
        return clazz;
    }


    /**
     * Looks up its own event map. If no structure was found, the call is delegated to
     * the default ModelClassFactory. If nothing can be found, the eventName is returned
     * as structure. Fixes bug #213 in HAPI 2.2
     *
     * @see ca.uhn.hl7v2.parser.AbstractModelClassFactory#getMessageStructureForEvent(java.lang.String, ca.uhn.hl7v2.Version)
     */
    @Override
    public String getMessageStructureForEvent(String eventName, Version version) throws HL7Exception {
        Map<String, String> p = getEventMapForVersion(version);
        if (p == null)
            throw new HL7Exception("No map found for version " + version);
        String structure = p.get(eventName);
        if (structure == null) {
            structure = defaultFactory.getMessageStructureForEvent(eventName, version);
        }
        if (structure == null) {
            structure = eventName;
        }
        return structure;
    }

    public ModelClassFactory getDelegate() {
        return defaultFactory;
    }
}

@@ -46,121 +46,8 @@
 r;%0A%0A
-import java.util.Map;%0Aimport java.util.concurrent.ConcurrentHashMap;%0Aimport java.util.concurrent.ConcurrentMap;%0A%0A
 impo
@@ -72,24 +72,24 @@
 7Exception;%0A
+
 import ca.uh
@@ -343,63 +343,119 @@
 ry;%0A
+%0A
 import 
-org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory
+java.util.Map;%0Aimport java.util.concurrent.ConcurrentHashMap;%0Aimport java.util.concurrent.ConcurrentMap
 ;%0A%0A/
@@ -812,15 +812,8 @@
 ate 
-static 
 fina
@@ -1806,32 +1806,51 @@
 it);%0A           
+ if (clazz != null)
  classMap.putIfA
@@ -2237,32 +2237,51 @@
 on);%0A           
+ if (clazz != null)
  classMap.putIfA
@@ -2680,32 +2680,51 @@
 on);%0A           
+ if (clazz != null)
  classMap.putIfA
@@ -3109,24 +3109,43 @@
 %0A           
+ if (clazz != null)
  classMap.pu
@@ -4222,16 +4222,17 @@
 actory;%0A
-
     %7D%0A
+%0A
 %7D%0A

fix caching in model class factory