<commit_before>package net.mgsx.game.core.storage;

import java.io.IOException;
import java.io.Writer;

import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.Json.Serializer;
import com.badlogic.gdx.utils.ObjectMap.Entries;
import com.badlogic.gdx.utils.ObjectMap.Entry;

import net.mgsx.game.core.GameRegistry;
import net.mgsx.game.core.GameScreen;
import net.mgsx.game.core.components.Initializable;
import net.mgsx.game.core.components.Movable;
import net.mgsx.game.core.components.Repository;
import net.mgsx.game.core.helpers.EntityHelper;
import net.mgsx.game.plugins.core.components.ProxyComponent;
import net.mgsx.game.plugins.core.components.Transform2DComponent;
import net.mgsx.game.plugins.spline.blender.BlenderCurve;

/**
 * Storage service.
 * 
 * A component could implements Serializable interface in that way :
 * <pre>
 * 
 * 
	public void write(Json json) 
	{
		json.writeField(this, "life");
		json.writeField(this, "points");
	}

	@Override
	public void read(Json json, JsonValue jsonData) 
	{
		json.readField(this, "life", jsonData);
		json.readField(this, "points", jsonData);
		time = 0; // init not persisted data
	}
	</pre>
 * 
 * or you can register a serializer :
 * 
 * {@link GameScreen#addSerializer(Class, Serializer)} :
 * <pre>
 * GameEngine.addSerializer(MyType.class, new MySerializer());
 * </pre>
 * or any builtin serializers :
 * <pre>
 * GameEngine.addSerializer(MyType.class, new IgnoreSerializer<MyType>());
 * GameEngine.addSerializer(MyType.class, new AnnotationSerializer<MyType>()); TODO ?
 * </pre>
 * @author mgsx
 *
 */
public class EntityGroupStorage 
{
	/**
	 * load entity group for editing, all entities in group will be Repository, any other
	 * referenced entities (from proxy ...) won't be repository.
	 * Entities are automatically added to the engine.
	 * @param assets
	 * @param registry
	 * @param fileName
	 * @return
	 */
	public static Array<Entity> loadForEditing(String fileName, LoadConfiguration config)
	{
		// first clone entity group and add repository flag.
		// then create transients (referenced from proxies.
		EntityGroup group = loadNow(fileName, config);
		Array<Entity> entities = new Array<Entity>();
		EntityGroup clones = new EntityGroup();
		for(Entity template : group.entities)
		{
			// clone template and add repository flag
			Entity entity = EntityHelper.clone(config.engine, template, group, clones, true);
			Repository repository = new Repository(); // no pool here (not required ?)
			entity.add(repository);
			
			// in case of proxy, create referenced entities recursively as transient (non repository)
			ProxyComponent proxy = ProxyComponent.components.get(entity);
			if(proxy != null){
				EntityGroup proxyGroup = config.assets.get(proxy.ref, EntityGroup.class);
				proxy.template = proxyGroup;
				proxy.clones = create(entities, config.assets, config.engine, proxyGroup, entity);
			}
			
			entities.add(entity);
		}
		return entities;
	}

	/**
	 * Load entities as transient, that is without persistence information. These entities
	 * won't be saved in patch files.
	 * 
	 * @param assets
	 * @param registry
	 * @param engine
	 * @param fileName
	 * @return
	 */
	public static Array<Entity> loadTransient(String fileName, LoadConfiguration config)
	{
		EntityGroup group = loadNow(fileName, config);
		Array<Entity> entities = new Array<Entity>();
		create(entities, config.assets, config.engine, group, null);
		return entities;
	}

	/**
	 * load entity group as proxy : all entities are loaded but not persisted.
	 * an additional proxy entity is created and persisted
	 * @param assets
	 * @param registry
	 * @param engine
	 * @param fileName
	 * @return all entities added to the engine, at least the proxy entity which is the
	 * only entity having proxy component, this is always the last component.
	 */
	public static Array<Entity> loadAsProxy(String fileName, Vector2 position, LoadConfiguration config) 
	{
		// case of proxy : we load entities as non persited but we create a proxy entity which will be stored.
		// create the special proxy entity
		Entity proxyEntity = config.engine.createEntity();
		ProxyComponent proxy = config.engine.createComponent(ProxyComponent.class);
		proxy.ref = fileName; // TODO could use AssetSerializer ?
		proxyEntity.add(proxy);
		proxyEntity.add(config.engine.createComponent(Repository.class));
		Transform2DComponent transform = config.engine.createComponent(Transform2DComponent.class);
		transform.position.set(position);
		proxyEntity.add(transform);
		
		// first instanciate group and remove any proxy components (de reference)
		EntityGroup group = loadNow(fileName, config);
		proxy.template = group;
		
		Array<Entity> entities = new Array<Entity>();
		proxy.clones = create(entities, config.assets, config.engine, group, proxyEntity);
		for(Entity entity : entities){
			entity.remove(ProxyComponent.class);
		}
		
		entities.add(proxyEntity);
		config.engine.addEntity(proxyEntity);
		
		return entities;
	}
	
	/**
	 * load an entity group ASAP forcing assets to be loaded now.
	 * @param assets
	 * @param registry
	 * @param fileName
	 * @return
	 */<commit_msg>ashley workaround<commit_after>package net.mgsx.game.core.storage;

import java.io.IOException;
import java.io.Writer;

import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.Json.Serializer;
import com.badlogic.gdx.utils.ObjectMap.Entries;
import com.badlogic.gdx.utils.ObjectMap.Entry;

import net.mgsx.game.core.GameRegistry;
import net.mgsx.game.core.GameScreen;
import net.mgsx.game.core.components.Initializable;
import net.mgsx.game.core.components.Movable;
import net.mgsx.game.core.components.Repository;
import net.mgsx.game.core.helpers.EntityHelper;
import net.mgsx.game.plugins.core.components.ProxyComponent;
import net.mgsx.game.plugins.core.components.Transform2DComponent;
import net.mgsx.game.plugins.spline.blender.BlenderCurve;

/**
 * Storage service.
 * 
 * A component could implements Serializable interface in that way :
 * <pre>
 * 
 * 
	public void write(Json json) 
	{
		json.writeField(this, "life");
		json.writeField(this, "points");
	}

	@Override
	public void read(Json json, JsonValue jsonData) 
	{
		json.readField(this, "life", jsonData);
		json.readField(this, "points", jsonData);
		time = 0; // init not persisted data
	}
	</pre>
 * 
 * or you can register a serializer :
 * 
 * {@link GameScreen#addSerializer(Class, Serializer)} :
 * <pre>
 * GameEngine.addSerializer(MyType.class, new MySerializer());
 * </pre>
 * or any builtin serializers :
 * <pre>
 * GameEngine.addSerializer(MyType.class, new IgnoreSerializer<MyType>());
 * GameEngine.addSerializer(MyType.class, new AnnotationSerializer<MyType>()); TODO ?
 * </pre>
 * @author mgsx
 *
 */
public class EntityGroupStorage 
{
	/**
	 * load entity group for editing, all entities in group will be Repository, any other
	 * referenced entities (from proxy ...) won't be repository.
	 * Entities are automatically added to the engine.
	 * @param assets
	 * @param registry
	 * @param fileName
	 * @return
	 */
	public static Array<Entity> loadForEditing(String fileName, LoadConfiguration config)
	{
		// first clone entity group and add repository flag.
		// then create transients (referenced from proxies.
		EntityGroup group = loadNow(fileName, config);
		Array<Entity> entities = new Array<Entity>();
		EntityGroup clones = new EntityGroup();
		for(Entity template : group.entities)
		{
			// clone template and add repository flag
			Entity entity = EntityHelper.clone(config.engine, template, group, clones, true);
			Repository repository = new Repository(); // no pool here (not required ?)
			entity.add(repository);
			
			// in case of proxy, create referenced entities recursively as transient (non repository)
			ProxyComponent proxy = ProxyComponent.components.get(entity);
			if(proxy != null){
				EntityGroup proxyGroup = config.assets.get(proxy.ref, EntityGroup.class);
				proxy.template = proxyGroup;
				proxy.clones = create(entities, config.assets, config.engine, proxyGroup, entity);
			}
			
			entities.add(entity);
		}
		return entities;
	}

	/**
	 * Load entities as transient, that is without persistence information. These entities
	 * won't be saved in patch files.
	 * 
	 * @param assets
	 * @param registry
	 * @param engine
	 * @param fileName
	 * @return
	 */
	public static Array<Entity> loadTransient(String fileName, LoadConfiguration config)
	{
		EntityGroup group = loadNow(fileName, config);
		Array<Entity> entities = new Array<Entity>();
		create(entities, config.assets, config.engine, group, null);
		return entities;
	}

	/**
	 * load entity group as proxy : all entities are loaded but not persisted.
	 * an additional proxy entity is created and persisted
	 * @param assets
	 * @param registry
	 * @param engine
	 * @param fileName
	 * @return all entities added to the engine, at least the proxy entity which is the
	 * only entity having proxy component, this is always the last component.
	 */
	public static Array<Entity> loadAsProxy(String fileName, Vector2 position, LoadConfiguration config) 
	{
		// case of proxy : we load entities as non persited but we create a proxy entity which will be stored.
		// create the special proxy entity
		Entity proxyEntity = config.engine.createEntity();
		ProxyComponent proxy = config.engine.createComponent(ProxyComponent.class);
		proxy.ref = fileName; // TODO could use AssetSerializer ?
		proxyEntity.add(proxy);
		proxyEntity.add(config.engine.createComponent(Repository.class));
		Transform2DComponent transform = config.engine.createComponent(Transform2DComponent.class);
		transform.position.set(position);
		proxyEntity.add(transform);
		
		// first instanciate group and remove any proxy components (de reference)
		EntityGroup group = loadNow(fileName, config);
		proxy.template = group;
		
		Array<Entity> entities = new Array<Entity>();
		proxy.clones = create(entities, config.assets, config.engine, group, proxyEntity);
		for(Entity entity : entities){
			if(ProxyComponent.components.has(entity)) // XXX workaround for 64 bag limit
				entity.remove(ProxyComponent.class);
		}
		
		entities.add(proxyEntity);
		config.engine.addEntity(proxyEntity);
		
		return entities;
	}
	
	/**
	 * load an entity group ASAP forcing assets to be loaded now.
	 * @param assets
	 * @param registry
	 * @param fileName
	 * @return
	 */
{'fraction_non_alphanumeric': 0.10870147255689425, 'fraction_numerical': 0.00142793395805444, 'mean_word_length': 4.305871212121212, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '5105216', 'n_tokens_mistral': 3534, 'n_tokens_neox': 3238, 'n_words': 920}