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 try { 077 while ((line = br.readLine()) != null) { 078 if (line.split("\t")[5].contains(String.valueOf(version))) { 079 // count tabs to calculate nodeDepth 080 int nodeDepth = 1; 081 while (line.charAt(0) == '\t') { 082 line = line.substring(1); 083 nodeDepth++; 084 } 085 086 if (nodeDepth > parentStack.size()) { 087 parentStack.push(child); 088 } 089 while (nodeDepth < parentStack.size()) { 090 parentStack.pop(); 091 } 092 093 // special case for parsing the Symbol Set codes since they're only 2 digits 094 if (nodeDepth == 1) { 095 String[] segments = line.split("\\t"); 096 symbolSet = segments[0]; 097 098 if (SYMBOL_BLACKLIST.contains(symbolSet)) { 099 continue; 100 } 101 102 child = getChild(parentStack.peek(), symbolSet, "000000"); 103 if (child == null) { 104 child = new Node(MSInfo.parseSymbolSetName(symbolSet, version), String.valueOf(version), symbolSet, "000000"); 105 parentStack.peek().addChild(child); 106 } 107 108 if (segments[1].equals("Unspecified")) { 109 // Ignore rest of line 110 continue; 111 } else { 112 // There is a subfolder on this line, add parent and continue parsing 113 parentStack.push(child); 114 } 115 } 116 117 // skip "{Reserved for future use}" codes 118 if (!line.toLowerCase().contains("{reserved for future use}")) { 119 String[] segments = line.split("\t+"); 120 String name; 121 if (nodeDepth == 1) { 122 name = segments[1]; 123 } else { 124 name = segments[0]; 125 } 126 127 // XXXXXX would indicate an error reading the file where it couldn't find 6 digits 128 String code = "XXXXXX"; 129 // extract 6-digit decimal code from remainder of line segments 130 for (int i = 1; i < segments.length; i++) { 131 if (segments[i].matches("\\d{6}")) { 132 code = segments[i]; 133 break; 134 } 135 } 136 137 if (SYMBOL_BLACKLIST.contains(symbolSet) || SYMBOL_BLACKLIST.contains(symbolSet + code)) { 138 continue; 139 } 140 141 child = getChild(parentStack.peek(), symbolSet, code); 142 if (child == null) { 143 child = new Node(name, String.valueOf(version), symbolSet, code); 144 parentStack.peek().addChild(child); 145 } 146 } 147 } 148 } 149 br.close(); 150 } catch (Exception e) { 151 throw new RuntimeException(e); 152 } 153 } 154 155 private Node getChild(Node parent, String symbolSet, String entityCode) { 156 for (Node child : parent.getChildren()){ 157 if (child.getSymbolSetCode().equals(symbolSet) && child.getCode().equals(entityCode)) 158 return child; 159 } 160 return null; 161 } 162}