package com.nedap.archie.aom;

import com.nedap.archie.aom.terminology.ArchetypeTerm;
import com.nedap.archie.aom.terminology.ArchetypeTerminology;
import com.nedap.archie.query.APathQuery;
import com.nedap.archie.rules.RuleStatement;

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

/**
 * Note: this Archetype does not conform to the UML model completely:
 * - it extends AuthoredResource - needed because otherwise we would have multiple inheritance
 * - it contains fields from AuthoredArchetype - needed because it saves complicated casting in java to call these methods otherwise
 *
 * Created by pieter.bos on 15/10/15.
 */
public class Archetype extends AuthoredResource {

    private String parentArchetypeId;
    private boolean differential = false;
    private ArchetypeHRID archetypeId;

    private CComplexObject definition;
    private ArchetypeTerminology terminology;
    private RulesSection rules = null;

    private String adlVersion;
    private String buildUid;
    private String rmRelease;
    private Boolean generated;

    public String getParentArchetypeId() {
        return parentArchetypeId;
    }

    public void setParentArchetypeId(String parentArchetypeId) {
        this.parentArchetypeId = parentArchetypeId;
    }

    public boolean isDifferential() {
        return differential;
    }

    public void setDifferential(boolean differential) {
        this.differential = differential;
    }

    public ArchetypeHRID getArchetypeId() {
        return archetypeId;
    }

    public void setArchetypeId(ArchetypeHRID archetypeId) {
        this.archetypeId = archetypeId;
    }

    public CComplexObject getDefinition() {
        return definition;
    }

    public void setDefinition(CComplexObject definition) {
        definition.setArchetype(this);
        this.definition = definition;
    }

    public RulesSection getRules() {
        return rules;
    }

    public void setRules(RulesSection rules) {
        this.rules = rules;
    }

    public ArchetypeTerminology getTerminology() {
        return terminology;
    }

    public void setTerminology(ArchetypeTerminology terminology) {
        this.terminology = terminology;
    }

    private Map<String, String> otherMetaData = new ConcurrentHashMap<>();

    public String getAdlVersion() {
        return adlVersion;
    }

    public void setAdlVersion(String adlVersion) {
        this.adlVersion = adlVersion;
    }

    public String getBuildUid() {
        return buildUid;
    }

    public void setBuildUid(String buildUid) {
        this.buildUid = buildUid;
    }

    public String getRmRelease() {
        return rmRelease;
    }

    public void setRmRelease(String rmRelease) {
        this.rmRelease = rmRelease;
    }

    public Boolean getGenerated() {
        return generated;
    }

    public void setGenerated(Boolean generated) {
        this.generated = generated;
    }

    public Map<String, String> getOtherMetaData() {
        return otherMetaData;
    }

    public void setOtherMetaData(Map<String, String> otherMetaData) {
        this.otherMetaData = otherMetaData;
    }

    public void addOtherMetadata(String text, String value) {
        if (value != null) {
            otherMetaData.put(text, value);
        }//TODO: just a value is possible according to grammar (null values). But no in a ConcurrentHashMap. Change to different map implementation?
    }

    /**
     * Translation helper function. To be overriden by Operational Templates
     *
     * @param object   the object to get the term definition for
     * @param language the language to get the term definition for
     * @return the ArchetypeTerm corresponding to the given CObject in the given language
     */
    public ArchetypeTerm getTerm(CObject object, String language) {
        return getTerminology().getTermDefinition(language, object.getNodeId());
    }

    /**
     * Get the terminology definition for a certain code used in a certain path in a terminology. Use this instead of
     * the ArchetypeTerminology and things work in Operation Templates out of the box. Overridden in OperationalTemplate
     *
     * @param object   the object to get the term definition for
     * @param code     the object to get the term definition for. Usually an ac- or at-code
     * @param language the language to get the term definition for
     * @return the ArchetypeTerm corresponding to the given CObject in the given language
     */
    public ArchetypeTerm getTerm(CObject object, String code, String language) {
        return getTerminology().getTermDefinition(language, code);
    }


    public ArchetypeTerminology getTerminology(CObject object) {
        return getTerminology();
    }

    public Archetype clone() {
        return (Archetype) super.clone();
    }

    /** TODO: should this only be on complex objects? */
    public <T extends ArchetypeModelObject> T itemAtPath(String path) {
        return new APathQuery(path).find(getDefinition());
    }


    @Override
    public String toString() {
        return"archetype: " + getArchetypeId();
    }

}

@@ -187,53 +187,38 @@
 ry;%0A
+%0A
 import 
-com.nedap.archie.rules.RuleStatement;%0A
+java.util.Collections;
 %0Aimp
@@ -231,16 +231,20 @@
 va.util.
+Hash
 Map;%0Aimp
@@ -261,33 +261,8 @@
 til.
-concurrent.ConcurrentHash
 Map;
@@ -1024,24 +1024,90 @@
 generated;%0A%0A
+    private Map%3CString, String%3E otherMetaData = new HashMap%3C%3E();%0A%0A
     public S
@@ -2240,84 +2240,8 @@
  %7D%0A%0A
-    private Map%3CString, String%3E otherMetaData = new ConcurrentHashMap%3C%3E();%0A%0A
     
@@ -3236,147 +3236,8 @@
    %7D
-//TODO: just a value is possible according to grammar (null values). But no in a ConcurrentHashMap. Change to different map implementation?
 %0A   

Allow null values in otherMetaData map in Archetype