package tools;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* This class is a tree diagram data structure designed for holding the
* keywords of Java instructions. This class is not used for anything except
* coloring syntax in the text editors.
* Useful information:
* http://sujitpal.blogspot.com/2006/05/java-data-structure-generic-tree.html
* @author Jiangcheng Oliver Chu
*/
public class InstructionTree {
private static Map<Character, ArrayList<String>> branches =
new HashMap<Character, ArrayList<String>>();
private static boolean isTreeLoaded = false;
public InstructionTree() {
super();
}
public InstructionTree(ArrayList<String> stringList) {
super();
if (isTreeLoaded) {
return;
}
ArrayList<Character> charList = collectBeginningCharacters(stringList);
createLeaves(charList, stringList);
//This tree can be loaded once and only once per program instance.
isTreeLoaded = true;
}
static boolean getIsTreeLoaded() {
return isTreeLoaded;
}
/**
* @return {position of leaf, length of leaf} Will return -1 for both if
* no leaf is found.
*/
int[] findNextMnemonicLeafInText(String text,int begin) {
int maxLength = text.length();
return findNextMnemonicLeafInTextRange(text, begin, maxLength);
}
/**
* @return {position of leaf, length of leaf}. Will return -1 for both if
* no leaf is found.
*/
int[] findNextMnemonicLeafInTextRange(String text, int begin, int end) {
int[] results = {-1, -1};
boolean checkNextCharForLeaf = false;
for (int i = begin; i < end; i++) {
char currentChar = text.charAt(i);
//We check for i == begin just in case the mnemonic starts at
//the beginning of a line or document, which is actually quite
//likely.
if (checkNextCharForLeaf || i == begin) {
checkNextCharForLeaf = false;
if (branches.containsKey(currentChar)) {
int leafLength =
checkForLeafAtPosition(text,currentChar,i+1);
if (leafLength != -1) {
//Do NOT check for a trailing space because all the
//zero-operand mnemonics do not need trailing spaces.
results[0] = i;
results[1] = leafLength + 1;
return results;
}
continue;
}
}
if (currentChar == ' ' || currentChar == '\n' ||
currentChar == '|') {
checkNextCharForLeaf = true;
}
}
return results;
}
/**
* @param text
* @param key
* @param pos
* @return Length of the leaf, or -1 if no leaf is found.
*/
private int checkForLeafAtPosition(String text,char key,int pos) {
ArrayList<String> leaves = branches.get(key);
for (String eachLeaf : leaves) {
int leafLength = eachLeaf.length();
String possibleLeaf = StrTools.slice(text, pos, pos + leafLength);
if (possibleLeaf.equals(eachLeaf)) {
return leafLength;
}
}
return -1;
}
private void createLeaves(ArrayList<Character> charList,
ArrayList<String> stringList) {
for (char eachChar : charList) {
for (String eachString: stringList) {
addLeafIfNeeded(eachChar, eachString);
}
}
//We must sort the strings so that the biggest ones get checked first.
for (char eachChar : charList) {
ArrayList<String> leaves = branches.get(eachChar);
leaves = StrSort.performCountingSort(leaves);
branches.put(eachChar, leaves);
}
}
private void addLeafIfNeeded(char character,String string) {
if (string.length() > 0) {
if (string.charAt(0) == character) {
ArrayList<String> currentLeaves;
if (branches.containsKey(character)) {
currentLeaves = (ArrayList<String>) branches.get(character);
} else {
currentLeaves = new ArrayList<String>();
}
currentLeaves.add(StrTools.slice(string, 1));
branches.put(character, currentLeaves);
}
}
}
private ArrayList<Character> collectBeginningCharacters(
ArrayList<String> stringList) {
ArrayList<Character> charList = new ArrayList<Character>();
for (String eachString : stringList) {
if (eachString.length() > 0) {
char currentChar = eachString.charAt(0);
if (!charList.contains(currentChar))
charList.add(currentChar);
}
}
return charList;
}
@Override
public String toString() {
if (isTreeLoaded) {
String output = "";
Set keys = branches.keySet();
for (Object eachKey : keys) {
char currentChar = (Character) eachKey;
ArrayList<String> leaves = branches.get(currentChar);
if (leaves.isEmpty()) {
output += currentChar + " - (no leaves)\n";
} else {
output += currentChar + " - " + leaves.get(0) + '\n';
int maxSize = leaves.size();
for (int i = 1; i < maxSize; i++) {
output += " - " + leaves.get(i) + '\n';
}
}
}
return output;
} else {
return "(Empty Tree)";
}
}
}