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