<commit_before>package com.nedap.archie.flattener;

import com.nedap.archie.aom.*;
import com.nedap.archie.query.APathQuery;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.util.ArrayList;

/**
 * Flattener. For single use only, create a new flattener for every flatten-action you want to do!
 *
 * TODO: the parent/child naming is very confusing. Make a new name. Original/specialized? Root/specialized? something else? Check the specs!
 * TODO: new Node IDs should be assigned, i think. With a idDIGIT+(\.DIGIT+)+ syntax?
 * TODO: Archetype terminologies should be merged
 *
 * Created by pieter.bos on 21/10/15.
 */
public class Flattener {

    //to be able to store Template Overlays transparently during flattening
    private OverridingArchetypeRepository repository;

    private Archetype parent;
    private Archetype child;

    private Archetype result;
    private boolean makeOperationalTemplate;

    public Flattener(ArchetypeRepository repository) {
        this.repository = new OverridingArchetypeRepository(repository);
    }

    public Flattener makeOperationalTemplate(boolean makeTemplate) {
        this.makeOperationalTemplate = makeTemplate;
        return this;
    }

    public Archetype flatten(Archetype toFlatten) {
        if(parent != null) {
            throw new IllegalStateException("You've used this flattener before - single use instance, please create a new one!");
        }
        //validate that we can legally flatten first
        String parentId = toFlatten.getParentArchetypeId();
        if(parentId == null) {
            throw new IllegalArgumentException("Cannot flatten archetype without a parent");
        }

        this.parent = repository.getArchetype(toFlatten.getParentArchetypeId());
        if(parent == null) {
            throw new IllegalArgumentException("parent archetype not found in repository: " + toFlatten.getParentArchetypeId());
        }
        this.child = toFlatten.clone();//just to be sure, so we don't have to copy more things deeper down

        if(child instanceof Template) {
            Template childTemplate = (Template) child;
            for(TemplateOverlay overlay:childTemplate.getTemplateOverlays()) {
                //we'll flatten them later when we need them, otherwise, you run into problems with archetypes
                //not yet added to repository while we already need them
                repository.addArchetype(overlay);

               /* try {
                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

                    System.out.println(objectMapper.writeValueAsString(flattened));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }*/
            }
        }

        while(parent.getParentArchetypeId() != null && parent.isDifferential()) {
            //parent needs flattening first
            parent = getNewFlattener().flatten(parent);//TODO: this might end up in an infinite loop. Detect depth?
        }


        this.result = null;
        if(makeOperationalTemplate) {
            result = createOperationalTemplate(parent, child);
        } else {
            result = parent.clone();
        }

        //TODO: multiple steps?:on
        //1. redefine structure
        //2. fill archetype slots?
        flatten(result, child);//TODO: this way around, or the other one? :)
        return result;
    }

    private static Archetype createOperationalTemplate(Archetype parent, Archetype child) {
        Archetype toClone = parent.clone(); //clone so we do not overwrite the parent archetype. never
        OperationalTemplate result = new OperationalTemplate();
        result.setArchetypeId(child.getArchetypeId());
        result.setDefinition(toClone.getDefinition());
        result.setDifferential(false);
        result.setParentArchetypeId(null);
        result.setRmRelease(toClone.getRmRelease());
        result.setAdlVersion(toClone.getAdlVersion());
        result.setTerminology(toClone.getTerminology());
        result.setGenerated(true);
        result.setOtherMetaData(toClone.getOtherMetaData());<commit_msg>Allow overriding of term definitions in flattener<commit_after>package com.nedap.archie.flattener;

import com.nedap.archie.aom.*;
import com.nedap.archie.aom.terminology.ArchetypeTerm;
import com.nedap.archie.query.APathQuery;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.util.ArrayList;
import java.util.Map;

/**
 * Flattener. For single use only, create a new flattener for every flatten-action you want to do!
 *
 * TODO: the parent/child naming is very confusing. Make a new name. Original/specialized? Root/specialized? something else? Check the specs!
 * TODO: new Node IDs should be assigned, i think. With a idDIGIT+(\.DIGIT+)+ syntax?
 * TODO: Archetype terminologies should be merged
 *
 * Created by pieter.bos on 21/10/15.
 */
public class Flattener {

    //to be able to store Template Overlays transparently during flattening
    private OverridingArchetypeRepository repository;

    private Archetype parent;
    private Archetype child;

    private Archetype result;
    private boolean makeOperationalTemplate;

    public Flattener(ArchetypeRepository repository) {
        this.repository = new OverridingArchetypeRepository(repository);
    }

    public Flattener makeOperationalTemplate(boolean makeTemplate) {
        this.makeOperationalTemplate = makeTemplate;
        return this;
    }

    public Archetype flatten(Archetype toFlatten) {
        if(parent != null) {
            throw new IllegalStateException("You've used this flattener before - single use instance, please create a new one!");
        }
        //validate that we can legally flatten first
        String parentId = toFlatten.getParentArchetypeId();
        if(parentId == null) {
            throw new IllegalArgumentException("Cannot flatten archetype without a parent");
        }

        this.parent = repository.getArchetype(toFlatten.getParentArchetypeId());
        if(parent == null) {
            throw new IllegalArgumentException("parent archetype not found in repository: " + toFlatten.getParentArchetypeId());
        }
        this.child = toFlatten.clone();//just to be sure, so we don't have to copy more things deeper down

        if(child instanceof Template) {
            Template childTemplate = (Template) child;
            for(TemplateOverlay overlay:childTemplate.getTemplateOverlays()) {
                //we'll flatten them later when we need them, otherwise, you run into problems with archetypes
                //not yet added to repository while we already need them
                repository.addArchetype(overlay);

               /* try {
                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

                    System.out.println(objectMapper.writeValueAsString(flattened));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }*/
            }
        }

        while(parent.getParentArchetypeId() != null && parent.isDifferential()) {
            //parent needs flattening first
            parent = getNewFlattener().flatten(parent);//TODO: this might end up in an infinite loop. Detect depth?
        }


        this.result = null;
        if(makeOperationalTemplate) {
            result = createOperationalTemplate(parent, child);
        } else {
            result = parent.clone();
        }

        //TODO: multiple steps?:on
        //1. redefine structure
        //2. fill archetype slots?
        flatten(result, child);//TODO: this way around, or the other one? :)
        Map<String, Map<String, ArchetypeTerm>> resultTermDefinitions = result.getTerminology().getTermDefinitions();
        Map<String, Map<String, ArchetypeTerm>> childTermDefinitions = child.getTerminology().getTermDefinitions();
        for(String language:childTermDefinitions.keySet()) {
            if(!resultTermDefinitions.containsKey(language)) {
                resultTermDefinitions.put(language, childTermDefinitions.get(language));
            } else {
                for(String nodeId:childTermDefinitions.get(language).keySet()) {
                    resultTermDefinitions.get(language)
                            .put(nodeId, childTermDefinitions.get(language).get(nodeId));
                }
            }

        }
        return result;
    }

    private static Archetype createOperationalTemplate(Archetype parent, Archetype child) {
        Archetype toClone = parent.clone(); //clone so we do not overwrite the parent archetype. never
        OperationalTemplate result = new OperationalTemplate();
        result.setArchetypeId(child.getArchetypeId());
        result.setDefinition(toClone.getDefinition());
        result.setDifferential(false);
        result.setParentArchetypeId(null);
        result.setRmRelease(toClone.getRmRelease());
        result.setAdlVersion(toClone.getAdlVersion());
        result.setTerminology(toClone.getTerminology());
        result.setGenerated(true);
        result.setOtherMetaData(toClone.getOtherMetaData());
{'fraction_non_alphanumeric': 0.08752230034631125, 'fraction_numerical': 0.001679084898730192, 'mean_word_length': 2.766798418972332, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '416510', 'n_tokens_mistral': 2547, 'n_tokens_neox': 2421, 'n_words': 656}