package nbtool.data; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import nbtool.data.json.Json; import nbtool.data.json.Json.JsonValue; import nbtool.data.json.JsonArray; import nbtool.data.json.JsonObject; import nbtool.data.json.JsonString; import nbtool.data.log.Log; import nbtool.gui.logviews.misc.ViewParent; import nbtool.util.ClassFinder; import nbtool.util.Debug; import nbtool.util.ToolSettings; public class ViewProfile { /********** ViewProfile instance methods & constructors*/ public String name = null; public ViewState[][] states = null; public ViewProfile(String n) { assert(n != null && !n.isEmpty()); this.name = n; this.states = new ViewState[TYPES.length][]; } @SuppressWarnings("unchecked") public Class<? extends ViewParent>[] selected(String type) { int tindex = Arrays.asList(TYPES).indexOf(type); ArrayList<Class<? extends ViewParent>> sel = new ArrayList<>(); for (ViewState vs : states[tindex]) { if (vs.showing) sel.add(vs.viewClass); } return sel.toArray(new Class[sel.size()]); } @SuppressWarnings("unchecked") public Class<? extends ViewParent>[] viewsForLog(Log log) { ArrayList<Class<? extends ViewParent>> views = new ArrayList<Class<? extends ViewParent>>(); String ptype = log.logClass; assert(ptype != null); int tindex = Arrays.asList(TYPES).indexOf(ptype); if (tindex >= 0) { for (ViewState vs : states[tindex]) { if (vs.showing) views.add(vs.viewClass); } } // // if (ptype.startsWith("proto-")) { // views.addAll(Arrays.asList(this.selected(ToolSettings.PROTOBUF_S))); // } views.addAll(Arrays.asList(this.selected(ToolSettings.DEFAULT_S))); Debug.info("LogToViewUtility found %d views for log of type %s.", views.size(), ptype); return views.toArray(new Class[views.size()]); } @Override public String toString() { return name; } public static class ViewState { public boolean showing; public Class<? extends ViewParent> viewClass; ViewState(boolean s, Class<? extends ViewParent> cls) { showing = s; viewClass = cls; } @Override public String toString() { return viewClass.getName(); } } /********** ViewProfile static methods & setup*/ public static final String DEFAULT_PROFILE_NAME = "DEFAULT"; public static ViewProfile DEFAULT_PROFILE = null; public static final Map<String, ViewProfile> PROFILES = new HashMap<>(); private static ViewProfile makeDefaultProfile() { ViewProfile def = new ViewProfile(DEFAULT_PROFILE_NAME); for (int j = 0; j < TYPES.length; ++j) { Class<? extends ViewParent>[] possible = POSSIBLE_VIEWS.get(TYPES[j]); //Select all. def.states[j] = resolve(possible, null); } return def; } public static ViewProfile addWithName(String name) { assert(name != null && !name.isEmpty()); if (name.equalsIgnoreCase(DEFAULT_PROFILE_NAME)) { Debug.error("cannot overwrite default profile with {%s}", name); return null; } ViewProfile nvp = new ViewProfile(name); for (int j = 0; j < TYPES.length; ++j) { Class<? extends ViewParent>[] possible = POSSIBLE_VIEWS.get(TYPES[j]); //Select all. nvp.states[j] = resolve(possible, null); } PROFILES.put(name, nvp); return nvp; } private static void _setup_(JsonObject profiles) { for (Entry<JsonString, JsonValue> entry : profiles.entrySet()) { String name = entry.getKey().value; JsonObject viewMap = entry.getValue().asObject(); ViewProfile vp = new ViewProfile(name); for (int j = 0; j < TYPES.length; ++j) { Class<? extends ViewParent>[] possible = POSSIBLE_VIEWS.get(TYPES[j]); JsonValue array = viewMap.get(TYPES[j]); if (array != null) { Class<? extends ViewParent>[] lshown = classValuesFrom(array.asArray()); vp.states[j] = resolve(possible, lshown); } else { vp.states[j] = resolve(possible, null); } } PROFILES.put(name, vp); } } public static void setupProfiles(JsonObject profiles) { if (profiles != null) { _setup_(profiles); } if (!PROFILES.containsKey(DEFAULT_PROFILE_NAME)) { PROFILES.put(DEFAULT_PROFILE_NAME, ViewProfile.makeDefaultProfile()); } DEFAULT_PROFILE = PROFILES.get(DEFAULT_PROFILE_NAME); } @SuppressWarnings("unchecked") /* where carray is an array of JsonStrings encoding class names */ public static Class<? extends ViewParent>[] classValuesFrom(JsonArray carray) { ArrayList<Class<? extends ViewParent>> classes = new ArrayList<>(); for (JsonValue val : carray) { Class<? extends ViewParent> c = null; try { c = (Class<? extends ViewParent>) Class.forName(val.asString().value); } catch (Exception e) { Debug.error( "_____ PREVIOUSLY LOADED CLASS COULD NOT BE FOUND { %s }! _____", val.asString().value); e.printStackTrace(); } if (c != null) { classes.add(c); } } return classes.toArray(new Class[0]); } private static ViewState[] resolve(Class<? extends ViewParent>[] possible, Class<? extends ViewParent>[] lastShown) { ViewState[] ret = new ViewState[possible.length]; HashSet<Class<? extends ViewParent>> pset = new HashSet<Class<? extends ViewParent>>(Arrays.asList(possible)); int i = 0; if (lastShown != null) { /* create true VS for every class in lastShown */ for (Class<? extends ViewParent> cls : lastShown) { if (pset.contains(cls)) { ret[i++] = new ViewState(true, cls); pset.remove(cls); } } /* add false VS for every class left in pset */ for (Class<? extends ViewParent> cls : pset) { ret[i++] = new ViewState(false, cls); } } else { /* no last shown for this type, add true VS for all */ for (Class<? extends ViewParent> cls : pset) { ret[i++] = new ViewState(true, cls); } } assert(i == possible.length); return ret; } public static JsonObject serializeProfiles() { JsonObject allProfiles = Json.object(); for (Entry<String, ViewProfile> entry : PROFILES.entrySet()) { assert(entry.getKey().equals(entry.getValue().name)); ViewProfile vp = entry.getValue(); JsonObject vpO = Json.object(); for (String type : TYPES) { Class<? extends ViewParent>[] sel = vp.selected(type); JsonArray carray = Json.array(); for (Class<? extends ViewParent> cls : sel) { carray.add(cls.getName()); } vpO.put(type, carray); } allProfiles.put(vp.name, vpO); } return allProfiles; } public static final Map<String, Class<? extends ViewParent>[]> POSSIBLE_VIEWS = new HashMap<String, Class<? extends ViewParent>[]>(); public static String[] TYPES; /* NOTE: not _NBL_REQUIRED_START_ because it is a dependency of many other components */ /* Called directly in terminal main() */ @SuppressWarnings("unchecked") public static void findAllViews() { Debug.warn("ViewProfile finding all subclasses of ViewParent"); List<Class<?>> found = ClassFinder.findAllSubclasses(ViewParent.class); Map<String, List<Class<?>>> pv_map = new HashMap<>(); for (Class<?> cls : found) { ViewParent inst; String[] types = null; try { inst = (ViewParent) cls.getDeclaredConstructor().newInstance(); types = inst.displayableTypes(); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { e.printStackTrace(); Debug.error("*************************\n" + "\tfatal error checking no-args constructor of ViewParent subclass:\n" + "\t%s error: %s", cls.getName(), e.getMessage() ); System.exit(-1); } if (types == null) { Debug.error("class %s returns NULL displayableTypes !", cls.getName()); continue; } for (String t : types) { if (pv_map.containsKey(t)) { pv_map.get(t).add(cls); } else { LinkedList<Class<?>> newList = new LinkedList<>(); newList.add(cls); pv_map.put(t, newList); } } } for (String type : pv_map.keySet()) { POSSIBLE_VIEWS.put(type, pv_map.get(type).toArray(new Class[0])); } TYPES = POSSIBLE_VIEWS.keySet().toArray(new String[0]); Debug.info("%s", POSSIBLE_VIEWS.toString()); } }