package com.framsticks.params; import com.framsticks.params.types.CompositeParam; import com.framsticks.params.types.DecimalParam; import com.framsticks.params.types.FloatParam; import com.framsticks.params.types.StringParam; import com.framsticks.util.Casting; import org.apache.log4j.Logger; import javax.lang.model.element.TypeElement; import java.lang.reflect.*; import java.util.*; import java.util.List; /** * The class FramsClass represents the class / schema of connected parameters * (such as parameters within the class). It differs from C++ version by storing * information about the class that parameters belong to. * * Based loosely on c++ class Param located in cpp/gdk/param.* * * @author Jarek Szymczak , Mateusz Jarus (please * replace name and surname with my personal data) * * @author Piotr Sniegowski */ public final class FramsClass { private final static Logger LOGGER = Logger.getLogger(FramsClass.class.getName()); /** * The Class which represents group. */ /** The offset of the parameter (applied for newly added parameter). */ protected int fieldsNumber; /** The groups. */ protected List groups = new ArrayList(); /** * The param entry map (for fast accessing of parameters * by their name) */ protected Map paramEntryMap = new LinkedHashMap(); /** The param list (for accessing parameters by offset in O(1) time. */ protected List paramList = new ArrayList(); /** The param getId map (for fast lookup of offset based on name */ protected Map paramIdMap = new HashMap(); protected String id; protected String name; protected String description; public Collection getParamEntries() { return paramEntryMap.values(); } public FramsClass() { } public FramsClass(String id, String name, String description) { this.setId(id); this.setName(name); this.setDescription(description); } /** * Adds new param entry. * * @param param * the new param entry */ public FramsClass append(Param param) { paramEntryMap.put(param.getId(), param); //paramEntryMap.put(param.getInternalId(), param); paramList.add(param); try { Group group = groups.get(param.getGroup()); if (group != null) { group.addProperty(param); } } catch (IndexOutOfBoundsException ignored) { } return this; } /** * Adds new group. */ public FramsClass appendGroup(Group group) { groups.add(group); return this; } public String getDescription() { return description; } public int getGroupCount() { return groups.size(); } /** * Gets the group member. * * @param gi * the offset of group * @param pi * the offset of member within a group * @return the pi-th member of group gi */ public Param getGroupMember(int gi, int pi) { if (gi < 0 || pi < 0 || gi >= groups.size()) { return null; } Group group = groups.get(gi); return (group != null ? group.getProperty(pi) : null); } /** * Gets the group getName. * * @param gi * the offset of group * @return the group getName */ public String getGroupName(int gi) { if (gi < 0 || gi >= groups.size()) return null; return groups.get(gi).name; } public String getId() { return id; } public String getName() { return name; } public String getNiceName() { return name != null ? name : id; } /** * Gets the param entry. * * @param i * the offset of parameter * @return the param entry */ public Param getParamEntry(int i) { if (i < 0 || i >= paramList.size()) { return null; } return paramList.get(i); } /** * Gets the param entry. * * @param id * the getId of parameter * @return the param entry */ public Param getParamEntry(String id) { return paramEntryMap.get(id); } public int getParamCount() { return paramList.size(); } @Override public String toString() { return id; } public static FramsClass getFramsClass() { return new FramsClass("class", "class", null) .append(new ParamBuilder().setId("name").setName("Name").setType(StringParam.class).build()) .append(new ParamBuilder().setId("id").setName("id").setType(StringParam.class).build()) .append(new ParamBuilder().setId("desc").setName("Description").setType(StringParam.class).build()); } public void setId(String id) { this.id = id; } public void setName(String name) { this.name = name; } public void setDescription(String description) { this.description = description; } public static String getParamTypeForNativeType(Type type) { if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; Type rawType = p.getRawType(); if (rawType.equals(Map.class)) { Type containedType = p.getActualTypeArguments()[1]; //TODO uid should be passed along during construction if (containedType instanceof Class) { return "l " + ((Class) containedType).getCanonicalName() + " name"; } } return null; } if (type.equals(Integer.class)) { return "d"; } if (type.equals(String.class)) { return "s"; } if (type.equals(Double.class)) { return "f"; } if (type instanceof Class) { return "o " + ((Class) type).getCanonicalName(); } return null; } public static final String GENERATE_HELP_PREFIX = "automatically generated from: "; public static class Constructor { protected final FramsClass result; protected Class currentClass; public Constructor(Class src, String name) { result = new FramsClass(name, name, GENERATE_HELP_PREFIX + src.toString()); currentClass = src; while (currentClass != null) { try { currentClass.getMethod("constructFramsClass", Constructor.class).invoke(null, this); } catch (Exception ignored) { } currentClass = currentClass.getSuperclass(); } } public final FramsClass getResult() { return result; } public Constructor method(String name, Class ... arguments) { try { Method method = currentClass.getMethod(name, arguments); if (!Modifier.isPublic(method.getModifiers())) { return this; } String returnParamClass = getParamTypeForNativeType(method.getGenericReturnType()); if (returnParamClass == null) { return this; } Class[] args = method.getParameterTypes(); if (args.length == 0) { if (method.getName().startsWith("get")) { String fieldName = method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4); Param param = new ParamBuilder().setType(returnParamClass).setName(fieldName).setId(fieldName).setHelp(GENERATE_HELP_PREFIX + method.toString()).build(); assert param != null; result.append(param); return this; } return this; } return this; } catch (NoSuchMethodException e) { LOGGER.fatal("method " + name + " was not found in " + currentClass.toString()); } return this; } public Constructor field(String name) { try { Field field = currentClass.getField(name); if (!Modifier.isPublic(field.getModifiers())) { return this; } String paramClass = getParamTypeForNativeType(field.getGenericType()); if (paramClass == null) { return this; } Param param = new ParamBuilder().setType(paramClass).setName(field.getName()).setId(field.getName()).setHelp(GENERATE_HELP_PREFIX + field.toString()).build(); assert param != null; result.append(param); return this; } catch (NoSuchFieldException e) { LOGGER.fatal("field " + name + " was not found in " + currentClass.toString()); } return this; } } }