package com.github.dkharrat.nexusdata.metamodel;

import java.io.*;
import java.util.*;

import com.github.dkharrat.nexusdata.core.ManagedObject;

/**
 * An ObjectModel represents the collection of {@link Entity}s that defines the types of objects that exist in a
 * persistence store.
 */
public class ObjectModel {
    private final int version;
    private final String name;
    private final Map<String,Entity<?>> entities = new HashMap<String,Entity<?>>();

    /**
     * Creates a new object model.
     *
     * @param name      the name of the model
     * @param entities  the set of entities defined in this model
     * @param version   the version of this model
     */
    public ObjectModel(String name, Collection<Entity<?>> entities, int version) {
        this.name = name;
        this.version = version;
        initEntities(entities);
    }

    /**
     * Creates a new ObjectModel from a model file
     *
     * @param modelData     the input stream for the model file
     * @throws IOException  if there was a problem reading from the input stream
     */
    public ObjectModel(InputStream modelData) throws IOException {
        ObjectModelJsonParser.ParsedModel parsedModel = ObjectModelJsonParser.parseJsonModel(this, modelData);
        name = parsedModel.getName();
        version = parsedModel.getVersion();
        initEntities(parsedModel.getEntities());
    }

    private void initEntities(Collection<Entity<?>> entities) {
        for (Entity<?> entity : entities) {
            this.entities.put(entity.getName(), entity);
        }
    }

    /**
     * Returns the model version. Model versions are used to identify different versions of the same semantic model.
     * When making changes to a model that has already been published and is in use, make sure to increment the version
     * number to have persistence stores using older versions of the model to upgrade.
     *
     * @return  an integer representing the model's version
     */
    public int getVersion() {
        return version;
    }

    /**
     * Returns the model's name.
     *
     * @return the model's name.
     */
    public String getName() {
        return name;
    }

    /**
     * Returns the set of entities defined in this model.
     *
     * @return the set of entities defined in this model
     */
    public Set<Entity<?>> getEntities() {
        return new HashSet<Entity<?>>(entities.values());
    }

    /**
     * Returns the entity in this model by the entity's class type.
     *
     * @param type  the class type
     *
     * @return  the entity corresponding to the class type
     */
    @SuppressWarnings("unchecked")
    public <T extends ManagedObject> Entity<T> getEntity(Class<T> type) {
        return (Entity<T>) getEntity(type.getSimpleName());
    }

    /**
     * Returns the entity in this model by the entity's name.
     *
     * @param name  the name of the entity
     *
     * @return  the entity corresponding to the class type
     */
    @SuppressWarnings("unchecked")
    public <T extends ManagedObject> Entity<T> getEntity(String name) {
        return (Entity<T>)entities.get(name);
    }
}

@@ -1400,111 +1400,1186 @@
     
-private void initEntities(Collection%3CEntity%3C?%3E%3E entities) %7B%0A        for (Entity%3C?%3E entity : entities) %7B
+/**%0A     * Merges two unrelated models (as in not referencing each other) together to form a new single model. This is%0A     * useful for organizational purposes, where two unrelated models are stored in separate files. The models must not%0A     * conflict together (e.g. sharing the same entity name).%0A     *%0A     * @param models the set of models to merge%0A     * @param name the name of the newly merged model%0A     * @param version the version of the newly merged model%0A     *%0A     * @return a new ObjectModel from merging the specified models together%0A     */%0A    public static ObjectModel mergeModels(Set%3CObjectModel%3E models, String name, int version) %7B%0A        Set%3CEntity%3C?%3E%3E mergedEntities = new HashSet%3C%3E();%0A        for (ObjectModel model : models) %7B%0A            mergedEntities.addAll(model.getEntities());%0A        %7D%0A%0A        return new ObjectModel(name, mergedEntities, version);%0A    %7D%0A%0A    private void initEntities(Collection%3CEntity%3C?%3E%3E entities) %7B%0A        for (Entity%3C?%3E entity : entities) %7B%0A            if (entities.contains(entity.getName())) %7B%0A                throw new RuntimeException(%22Entity %22 + entity.getName() + %22 already exists in this model.%22);%0A            %7D
 %0A   

add method to merge models