FrontendMetadataGenerator.java

package eu.javaexperience.webgsdb.commons;

import hu.ddsi.java.database.FieldData;
import hu.ddsi.java.database.GenericStorageMappingData;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import eu.javaexperience.arrays.ArrayTools;
import eu.javaexperience.collection.CollectionTools;
import eu.javaexperience.gsdbrpc.RemoteGsdbTools;
import eu.javaexperience.gsdbrpc.WebDbModel;
import eu.javaexperience.gsdbrpc.WebGsdbTools;
import eu.javaexperience.gsdbrpc.annotations.CustomFieldManager;
import eu.javaexperience.gsdbrpc.annotations.RpcAttribute;
import eu.javaexperience.gsdbrpc.annotations.RpcAttributes;
import eu.javaexperience.gsdbrpc.annotations.InputType;
import eu.javaexperience.gsdbrpc.annotations.MayNotSee;
import eu.javaexperience.reflect.FieldSelectTools;
import eu.javaexperience.reflect.Mirror;
import eu.javaexperience.reflect.PrimitiveTools;
import eu.javaexperience.reflect.Mirror.ClassData;
import eu.javaexperience.rpc.JavaClassRpcCollector;
import eu.javaexperience.rpc.RpcFacility;
import eu.javaexperience.semantic.references.MayNotModified;
import eu.javaexperience.text.StringTools;

public abstract class FrontendMetadataGenerator
{
	protected Appendable out;
	protected Class<? extends WebDbModel>[] models;
	
	public FrontendMetadataGenerator(Appendable out, Class<? extends WebDbModel>... models)
	{
		this.out = out;
		this.models = models;
	}
	
	protected abstract String examineTranslationName(Field f);
	
	protected void appendReflectionMetaData(Appendable sb, Class cls) throws IOException
	{
		ClassData cd = Mirror.getClassData(cls);
		
		sb.append("\t\tWebGsdbTools.putFieldAttributes");
		sb.append("\n\t\t(");
		sb.append("\n\t\t\t"+cls.getCanonicalName()+".class,");
		int i=0;
		
		Map<String,Field> lastField = new HashMap<>();
		
		for(Field f:cd.select(FieldSelectTools.SELECT_ALL_INSTANCE_FIELD))
		{
			lastField.put(f.getName(), f);
		}
		
		for(Entry<String,Field>kv:lastField.entrySet())
		{
			Field f = kv.getValue();
	
			if(!Modifier.isPublic(f.getModifiers()))
			{
				continue;
			}
			
			if(++i > 1)
			{
				sb.append(",");
			}
			sb.append("\n\t\t\t");
			sb.append("\"").append(f.getName()).append("\", new FieldExtraAttributes(");
			sb.append(examineTranslationName(f));
			sb.append(")");
			
			if(null != f.getAnnotation(MayNotModified.class))
			{
				sb.append(".userCantModify()");
			}
			
			{
				InputType it = f.getAnnotation(InputType.class);
				if(null != it)
				{
					sb.append(".inputType(\"");
					sb.append(it.type());
					sb.append("\")");
				}
			}
			
			{
				MayNotSee it = f.getAnnotation(MayNotSee.class);
				if(null != it)
				{
					sb.append(".userMayNotSee()");
				}
			}
			
			{
				String add = renderCallAddExtraAddributes(f);
				if(null != add)
				{
					sb.append(add);
				}
			}
		}
		
		sb.append("\n\t\t);\n");
	}
	
	protected void appendModelFieldUrchin(Appendable sb, Class cls) throws InstantiationException, IllegalAccessException, IOException
	{
		String type = cls.getCanonicalName();
		sb.append("\t\tif(TeaVmTools.isUrchin())\n\t\t{\n\t\t\t");
		sb.append(type);
		sb.append(" m = new ");
		sb.append(type);
		sb.append("();\n\t\t");
		FieldData[] fds = GenericStorageMappingData.getOrCollectAllClassData(cls).allFd;
		for(FieldData fd:fds)
		{
			if(!RemoteGsdbTools.isWebgsdbUseField(fd.f))
			{
				continue;
			}
			
			sb.append("\tm.");
			sb.append(fd.f.getName());
			sb.append(" = ");
			
			Class<?> c = fd.f.getType();
			c = PrimitiveTools.toObjectClassType(c, c);
			
			if(c == Boolean.class)
			{
				sb.append("true");
			}
			else if(c == Byte.class)
			{
				sb.append("(byte) 1");
			}
			else if(c == Character.class)
			{
				sb.append("'c'");
			}
			else if(c == Short.class)
			{
				sb.append("(short) 1");
			}
			else if(c == Integer.class)
			{
				sb.append("1");
			}
			else if(c == Long.class)
			{
				sb.append("1l");
			}
			else if(c ==  Float.class)
			{
				sb.append("1.0f");
			}
			else if(c == Double.class)
			{
				sb.append("1.0d");
			}
			else
			{
				sb.append("null");
			}
			
			sb.append(";\n\t\t");
		}
		
		sb.append("}\n");
	}
	
	public void exportReflection() throws Throwable
	{
		//StringBuilder sb = new StringBuilder();
		
		out.append("import eu.jvx.js.lib.TeaVmTools;\nimport eu.javaexperience.webgsdb.WebGsdbTools;\nimport eu.javaexperience.webgsdb.commons.FieldExtraAttributes;\n\n\n");
		
		out.append("public class TeaVmMetadata\n{\n\tprotected static boolean init = false;\n\n\tpublic static void initTeaVmMetadata()\n\t{\n");
		out.append("\t\tif(init){return;} init = true;\n");
		
		for(Class<? extends WebDbModel> cls:models)
		{
			if(!cls.isInterface() && !Modifier.isAbstract(cls.getModifiers()))
			{
				appendReflectionMetaData(out, cls);
				out.append("\n");
				appendModelFieldUrchin(out, cls);
				out.append("\n\n");
			}
		}
		
		out.append("\n\t}");
		
		out.append("\n}");
	}

	protected String renderCallAddExtraAddributes(Field f)
	{
		StringBuilder sb = new StringBuilder();
		
		CustomFieldManager cfm = f.getAnnotation(CustomFieldManager.class);
		if(null != cfm)
		{
			
			Class<? extends FrontendFieldManager<? extends WebDbModel>> cls = cfm.managerClass();
			if(null != cls)
			{
				sb.append(".customFieldManager(");
				sb.append(cls.getCanonicalName());
				sb.append(".class)");
			}
		}
		
		{
			RpcAttribute fe = f.getAnnotation(RpcAttribute.class);
			if(null != fe)
			{
				appendAttribute(sb, fe);
			}
		}
		RpcAttributes fes = f.getAnnotation(RpcAttributes.class);
		if(null != fes)
		{
			for(RpcAttribute fe:fes.attributes())
			{
				if(null != fe)
				{
					appendAttribute(sb, fe);
				}
			}
		}
		
		if(0 == sb.length())
		{
			return null;
		}
		return sb.toString();
	}

	public static Class<? extends WebDbModel>[] getClasses(List<RpcFacility> apis)
	{
		return (Class[]) CollectionTools.convert(Class.class, apis, (e)->((JavaClassRpcCollector)e).getWrappedClass());
	}
	
	public static String wrapString(String s)
	{
		if(null == s)
		{
			return null;
		}
		
		return "\""+StringTools.escapeToJavaString(s)+"\"";
	}
	
	public static void appendAttribute(StringBuilder sb, RpcAttribute fa)
	{
		sb.append(".attr(");
		sb.append(wrapString(fa.key()));
		sb.append(", ");
		sb.append(wrapString(fa.value()));
		sb.append(")");
	}
}