001package armyc2.c5isr.renderer.symbolpicker; 002 003import android.content.Context; 004 005import java.io.BufferedReader; 006import java.io.IOException; 007import java.io.InputStream; 008import java.io.InputStreamReader; 009import java.util.Arrays; 010import java.util.HashSet; 011import java.util.Set; 012import java.util.Stack; 013 014import armyc2.c5isr.renderer.R; 015import armyc2.c5isr.renderer.utilities.MSInfo; 016import armyc2.c5isr.renderer.utilities.SymbolID; 017 018public class TreeManager { 019 private static final Set<String> SYMBOL_BLACKLIST = new HashSet<>(Arrays.asList( 020 // Symbols with no SVG or drawing in standard 021 "25342900", // Advance to contact 022 "25343000", // Capture 023 "25343100", // Conduct Exploitation 024 "25343200", // Control 025 "25343300", // Demonstration 026 "25343400", // Deny 027 "25343500", // Envelop 028 "25343600", // Escort 029 "25343700", // Exfiltrate 030 "25343800", // Infiltrate 031 "25343900", // Locate 032 "25350000", // Space debris 033 "25350100", "25350101", "25350102", "25350103", // Man made space debris 034 "25350200", "25350201", "25350202", "25350203", // Natural space debris 035 "46120313", // Hydrography Ports and Harbors Facilities 036 "46120301", // Hydrography Ports and Harbors Ports 037 "46120325", // Hydrography Ports and Harbors Shoreline Protection 038 "46120400", // Hydrography Aids to Navigation 039 "47", // Meteorological space 040 041 // Symbols with drawing in standard but no SVG 042 "10163601", // Floating Craft 043 044 // Symbols with ambiguous draw rules 045 "45162004" // Tropical Storm Wind Areas 046 )); 047 048 public Node mil2525Tree; 049 050 /** Reads the symbols from msd.txt and builds a tree. 051 * @param context Application context in which to use the tree. 052 * @param versions mil std 2525 versions to add to tree 053 * @throws IOException if there is an error reading msd.txt 054 */ 055 public void buildTree(Context context, int[] versions) throws IOException { 056 mil2525Tree = new Node("Root", "XX", "XX", "XX"); 057 for (int version : versions){ 058 addToTree(context, version); 059 } 060 } 061 062 private void addToTree(Context context, int version) throws IOException { 063 Stack<Node> parentStack = new Stack<>(); 064 Node child = mil2525Tree; 065 String line; 066 String symbolSet = ""; 067 068 InputStream is; 069 if (version >= SymbolID.Version_2525E) { 070 is = context.getResources().openRawResource(R.raw.mse); 071 } else { 072 is = context.getResources().openRawResource(R.raw.msd); 073 } 074 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 075 076 while ((line = br.readLine()) != null) { 077 // count tabs to calculate nodeDepth 078 int nodeDepth = 1; 079 while (line.charAt(0) == '\t') { 080 line = line.substring(1); 081 nodeDepth++; 082 } 083 084 if (nodeDepth > parentStack.size()) { 085 parentStack.push(child); 086 } 087 while (nodeDepth < parentStack.size()) { 088 parentStack.pop(); 089 } 090 091 // special case for parsing the Symbol Set codes since they're only 2 digits 092 if (nodeDepth == 1) { 093 String[] segments = line.split("\\t"); 094 symbolSet = segments[0]; 095 096 if (SYMBOL_BLACKLIST.contains(symbolSet)) { 097 continue; 098 } 099 100 child = getChild(parentStack.peek(), symbolSet, "000000"); 101 if (child == null) { 102 child = new Node(MSInfo.parseSymbolSetName(symbolSet,version), String.valueOf(version), symbolSet, "000000"); 103 parentStack.peek().addChild(child); 104 } 105 106 if (segments[1].equals("Unspecified")) { 107 // Ignore rest of line 108 continue; 109 } else { 110 // There is a subfolder on this line, add parent and continue parsing 111 parentStack.push(child); 112 } 113 } 114 115 // skip "{Reserved for future use}" codes 116 if (!line.toLowerCase().contains("{reserved for future use}")) { 117 String[] segments = line.split("\t+"); 118 String name; 119 if (nodeDepth == 1) { 120 name = segments[1]; 121 } else { 122 name = segments[0]; 123 } 124 125 // XXXXXX would indicate an error reading the file where it couldn't find 6 digits 126 String code = "XXXXXX"; 127 // extract 6-digit decimal code from remainder of line segments 128 for (int i = 1; i < segments.length; i++) { 129 if (segments[i].matches("\\d{6}")) { 130 code = segments[i]; 131 break; 132 } 133 } 134 135 if (SYMBOL_BLACKLIST.contains(symbolSet) || SYMBOL_BLACKLIST.contains(symbolSet + code)) { 136 continue; 137 } 138 139 child = getChild(parentStack.peek(), symbolSet, code); 140 if (child == null) { 141 child = new Node(name, String.valueOf(version), symbolSet, code); 142 parentStack.peek().addChild(child); 143 } 144 } 145 } 146 br.close(); 147 } 148 149 private Node getChild(Node parent, String symbolSet, String entityCode) { 150 for (Node child : parent.getChildren()){ 151 if (child.getSymbolSetCode().equals(symbolSet) && child.getCode().equals(entityCode)) 152 return child; 153 } 154 return null; 155 } 156}