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.ErrorLogger; 016import armyc2.c5isr.renderer.utilities.MSInfo; 017import armyc2.c5isr.renderer.utilities.SymbolID; 018import armyc2.c5isr.renderer.utilities.SymbolUtilities; 019 020public class TreeManager { 021 private static final Set<String> SYMBOL_BLACKLIST = new HashSet<>(Arrays.asList( 022 // Symbols with no SVG or drawing in standard 023 "47", // Meteorological space is an empty Symbol Set currently 024 025 // Symbols with ambiguous draw rules 026 "45162004" // Tropical Storm Wind Areas 027 )); 028 029 public Node mil2525Tree; 030 031 /** Reads the symbols from msd.txt and builds a tree. 032 * @param context Application context in which to use the tree. 033 * @param versions mil std 2525 versions to add to tree 034 * @throws IOException if there is an error reading msd.txt 035 */ 036 public void buildTree(Context context, int[] versions) throws IOException { 037 mil2525Tree = new Node("Root", "XX", "XX", "XX"); 038 for (int version : versions){ 039 addToTree(context, version); 040 } 041 } 042 043 private void addToTree(Context context, int version) throws IOException { 044 Stack<Node> parentStack = new Stack<>(); 045 Node child = mil2525Tree; 046 String line; 047 String symbolSet = ""; 048 049 InputStream is; 050 if (version >= SymbolID.Version_2525E) { 051 is = context.getResources().openRawResource(R.raw.mse); 052 } else { 053 is = context.getResources().openRawResource(R.raw.msd); 054 } 055 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 056 057 try { 058 while ((line = br.readLine()) != null) { 059 060 boolean newSymbolSet = false; 061 String[] segments = line.split("\\t"); 062 //lookup doesn't have 13 values. Add 13 wherever there's a 15 for now. 063 if(segments[5].contains("15")) { 064 segments[5] = "13," + segments[5]; 065 066 line = ""; 067 068 for(int lcv = 0; lcv < segments.length; lcv++) 069 { 070 line += segments[lcv]; 071 if(lcv < segments.length-1) 072 line += "\t"; 073 } 074 } 075 076 if (segments[5].contains(String.valueOf(version))) { 077 // count tabs to calculate nodeDepth 078 int nodeDepth = 1; 079 080 if(SymbolUtilities.isNumber(line.substring(0,2))) { 081 newSymbolSet = true; 082 line = line.substring(2); 083 } 084 while (line.charAt(0) == '\t') { 085 line = line.substring(1); 086 nodeDepth++; 087 } 088 089 if (nodeDepth > parentStack.size()) { 090 parentStack.push(child); 091 } 092 while (nodeDepth < parentStack.size()) { 093 parentStack.pop(); 094 } 095 096 // special case for parsing the Symbol Set codes since they're only 2 digits 097 if(newSymbolSet){//(nodeDepth == 1 && !segments[0].isEmpty()) { 098 symbolSet = segments[0]; 099 100 if (SYMBOL_BLACKLIST.contains(symbolSet)) { 101 continue; 102 } 103 104 child = getChild(parentStack.peek(), symbolSet, "000000"); 105 if (child == null) { 106 child = new Node(MSInfo.parseSymbolSetName(symbolSet, version), String.valueOf(version), symbolSet, "000000"); 107 108 //new symbol set so go back to the root to add it to the root 109 while(parentStack.size() > 1) 110 parentStack.pop(); 111 112 parentStack.peek().addChild(child); 113 } 114 115 if (segments[1].equals("Unspecified")) { 116 // Ignore rest of line 117 continue; 118 } else { 119 // There is a subfolder on this line, add parent and continue parsing 120 parentStack.push(child); 121 } 122 } 123 124 // skip "{Reserved for future use}" codes 125 if (!line.toLowerCase().contains("{reserved for future use}")) { 126 segments = line.split("\\t"); 127 String name; 128 129 name = segments[0]; 130 131 // XXXXXX would indicate an error reading the file where it couldn't find 6 digits 132 String code = "XXXXXX"; 133 // extract 6-digit decimal code from remainder of line segments 134 for (int i = 1; i < segments.length; i++) { 135 if (segments[i].matches("\\d{6}")) { 136 code = segments[i]; 137 break; 138 } 139 } 140 141 if (SYMBOL_BLACKLIST.contains(symbolSet) || SYMBOL_BLACKLIST.contains(symbolSet + code)) { 142 continue; 143 } 144 145 child = getChild(parentStack.peek(), symbolSet, code); 146 if (child == null) { 147 child = new Node(name, String.valueOf(version), symbolSet, code); 148 parentStack.peek().addChild(child); 149 } 150 } 151 } 152 } 153 br.close(); 154 } catch (Exception e) { 155 throw new RuntimeException(e); 156 } 157 } 158 159 private Node getChild(Node parent, String symbolSet, String entityCode) { 160 for (Node child : parent.getChildren()){ 161 if (child.getSymbolSetCode().equals(symbolSet) && child.getCode().equals(entityCode)) 162 return child; 163 } 164 return null; 165 } 166}