package org.sagebionetworks.web.client.transform;

import org.sagebionetworks.repo.model.AutoGenFactory;
import org.sagebionetworks.repo.model.Entity;
import org.sagebionetworks.repo.model.EntityInstanceFactory;
import org.sagebionetworks.schema.adapter.AdapterFactory;
import org.sagebionetworks.schema.adapter.JSONEntity;
import org.sagebionetworks.schema.adapter.JSONObjectAdapter;
import org.sagebionetworks.schema.adapter.JSONObjectAdapterException;

import com.google.inject.Inject;

/**
 * The basic implementation of the JSONEntityFactory.
 * 
 * @author John
 *
 */
public class JSONEntityFactoryImpl implements JSONEntityFactory {
	// This factory allows the creation of new class instances using only the class name.
	// Since reflection is not allowed in GWT, it uses an auto-generated swtich.
	AutoGenFactory internalFactory = null;
	EntityInstanceFactory entityInstanceFactory;
	// This factory creates any needed adapters
	AdapterFactory adapterFactory;
	
	@Inject
	public JSONEntityFactoryImpl(AdapterFactory adapterFactory){
		entityInstanceFactory = new EntityInstanceFactory();
		this.adapterFactory = adapterFactory;
	}

	/**
	 * Create a new entity from a JSON String.
	 */
	@Override
	public <T extends JSONEntity> T createEntity(String json, Class<? extends T> clazz) throws JSONObjectAdapterException {
		if(json == null) throw new IllegalArgumentException("Json string cannot be null");
		if(clazz == null) throw new IllegalArgumentException("Clazz cannot be null");
		// Use the factory to create a new instance from the class name
		return (T) createEntity(json, clazz.getName());
	}
	
	/**
	 * Create a new entity for the passed JSON and class name.
	 * @param json
	 * @param className
	 * @return
	 * @throws JSONObjectAdapterException 
	 */
	@Override
	public JSONEntity createEntity(String json, String className) throws JSONObjectAdapterException{
		if(json == null) throw new IllegalArgumentException("Json string cannot be null");
		if(className == null) throw new IllegalArgumentException("Classname cannot be null");
		// Use the factory to create the instance
		JSONEntity entity = this.newInstance(className);
		return initializeEntity(json, entity);
	}
	
	@Override
	public JSONEntity newInstance(String className) {
		try {
			return entityInstanceFactory.newInstance(className);
		} catch (Exception e) {
			//not found in entity instance factory, try the full autogen factory (lazy construction)
			if (internalFactory == null)
				internalFactory = new AutoGenFactory();
			return internalFactory.newInstance(className);	
		}
	}

	/**
	 * Initialize the passed new JSONEntity using the provided JSON string
	 */
	@Override
	public <T extends JSONEntity> T initializeEntity(String json, T newEntity) throws JSONObjectAdapterException {
		if(json == null) throw new IllegalArgumentException("Json string cannot be null");
		if(newEntity == null) throw new IllegalArgumentException("NewEntity cannot be null");
		// The adapter factory creates our adapter
		JSONObjectAdapter adapter = this.adapterFactory.createNew(json);
		newEntity.initializeFromJSONObject(adapter);
		return newEntity;
	}

	@Override
	public String createJsonStringForEntity(JSONEntity entity)	throws JSONObjectAdapterException {
		if(entity == null) throw new IllegalArgumentException("Entity cannot be null");
		// Get a new adapter
		JSONObjectAdapter adapter = this.adapterFactory.createNew();
		entity.writeToJSONObject(adapter);
		return adapter.toJSONString(); 
	}


	@Override
	public Entity createEntity(String json) throws JSONObjectAdapterException {
		// first we must parse the json to determine the type.
		JSONObjectAdapter adapter = this.adapterFactory.createNew(json);
		if(!adapter.has("entityType")) throw new IllegalArgumentException("Cannot determine the entity type because the 'entityType' is null");
		String entityType = adapter.getString("entityType");
		// create a new isntance
		Entity entity = (Entity) newInstance(entityType);
		entity.initializeFromJSONObject(adapter);
		return entity;
	}
}

@@ -152,70 +152,8 @@
 y;%0D%0A
-import org.sagebionetworks.repo.model.EntityInstanceFactory;%0D%0A
 impo
@@ -199,32 +199,32 @@
 dapterFactory;%0D%0A
+
 import org.sageb
@@ -793,62 +793,8 @@
 tory
- = null;%0D%0A%09EntityInstanceFactory entityInstanceFactory
 ;%0D%0A%09
@@ -953,50 +953,37 @@
 %0D%0A%09%09
-entityInstanceFactory = new EntityInstance
+internalFactory = new AutoGen
 Fact
@@ -2044,16 +2044,32 @@
  = this.
+internalFactory.
 newInsta
@@ -2204,280 +2204,20 @@
 %0D%0A%09%09
-try %7B%0D%0A%09%09%09return entityInstanceFactory.newInstance(className);%0D%0A%09%09%7D catch (Exception e) %7B%0D%0A%09%09%09//not found in entity instance factory, try the full autogen factory (lazy construction)%0D%0A%09%09%09if (internalFactory == null)%0D%0A%09%09%09%09internalFactory = new AutoGenFactory();%0D%0A%09%09%09
 return 
+this.
 inte
@@ -2255,14 +2255,8 @@
 me);
-%09%0D%0A%09%09%7D
 %0D%0A%09%7D
@@ -3633,16 +3633,16 @@
 ntance%0D%0A
-
 %09%09Entity
@@ -3660,16 +3660,32 @@
 Entity) 
+internalFactory.
 newInsta

revert JSONEntityFactoryImpl