package fitnesse.wikitext.parser;

import util.Maybe;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Symbol {
    public static final Maybe<Symbol> nothing = new Maybe<Symbol>();
    public static final Symbol emptySymbol = new Symbol(SymbolType.Empty);

    private SymbolType type;
    private String content = "";
    private List<Symbol> children = new ArrayList<Symbol>();
    private HashMap<String, String> variables;
    private HashMap<String, String> properties;

    public Symbol(SymbolType type) { this.type = type; }

    public Symbol(SymbolType type, String content) {
        this.content = content;
        this.type = type;
    }

    public SymbolType getType() { return type; }
    public boolean isType(SymbolType type) { return this.type.matchesFor(type); }
    public boolean isStartCell() { return isType(Table.symbolType) || isType(SymbolType.EndCell); }
    public boolean isStartLine() { return isType(HorizontalRule.symbolType) || isType(Nesting.symbolType); }

    public boolean isLineType() {
        return isType(HeaderLine.symbolType) || isType(SymbolType.CenterLine) || isType(SymbolType.Meta) ||
                isType(SymbolType.NoteLine);
    }
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }

    public Symbol childAt(int index) { return getChildren().get(index); }
    public Symbol lastChild() { return childAt(getChildren().size() - 1); }
    public List<Symbol> getChildren() { return children; }
    
    public Symbol addToFront(Symbol child) {
        ArrayList<Symbol> newChildren = new ArrayList<Symbol>();
        newChildren.add(child);
        newChildren.addAll(children);
        children = newChildren;
        return this;
    }

    public Symbol add(Symbol child) {
        children.add(child);
        return this;
    }

    public Symbol add(String text) {
        children.add(new Symbol(SymbolType.Text, text));
        return this;
    }

    public Symbol childrenAfter(int after) {
        Symbol result = new Symbol(SymbolType.SymbolList);
        for (int i = after + 1; i < children.size(); i++) result.add(children.get(i));
        return result;
    }

    public boolean walkPostOrder(SymbolTreeWalker walker) {
        if (walker.visitChildren(this)) {
            for (Symbol child: children) {
                if (!child.walkPostOrder(walker)) return false;
            }
        }
        return walker.visit(this);
    }

    public boolean walkPreOrder(SymbolTreeWalker walker) {
        if (!walker.visit(this)) return false;
        if (walker.visitChildren(this)) {
            for (Symbol child: children) {
                if (!child.walkPreOrder(walker)) return false;
            }
        }
        return true;
    }

    public void evaluateVariables(String[] names, VariableSource source) {
        if (variables == null) variables = new HashMap<String, String>();
        for (String name: names) {
            Maybe<String> value = source.findVariable(name);
            if (!value.isNothing()) variables.put(name, value.getValue());
        }
    }

    public String getVariable(String name, String defaultValue) {
        return variables != null && variables.containsKey(name) ? variables.get(name) : defaultValue;
    }

    public Symbol putProperty(String key, String value) {
        if (properties == null) properties = new HashMap<String, String> ();
        properties.put(key, value);
        return this;
    }

    public boolean hasProperty(String key) {
        return properties != null && properties.containsKey(key);
    }

    public String getProperty(String key, String defaultValue) {
        return properties != null && properties.containsKey(key) ? properties.get(key) : defaultValue;
    }

    public String getProperty(String key) {
        return getProperty(key, "");
    }

    public SymbolType closeType() {
        return type == SymbolType.OpenBrace ? SymbolType.CloseBrace
                : type == SymbolType.OpenBracket ? SymbolType.CloseBracket
                : type == SymbolType.OpenParenthesis ? SymbolType.CloseParenthesis
                : type == Literal.symbolType ? SymbolType.CloseLiteral
                : type == Comment.symbolType ? SymbolType.Newline
                : SymbolType.Empty;
    }


}

@@ -32,27 +32,8 @@
 r;%0A%0A
-import util.Maybe;%0A
 impo
@@ -77,38 +77,61 @@
 til.
-HashMap;%0Aimport java.util.List
+List;%0Aimport java.util.Properties;%0A%0Aimport util.Maybe
 ;%0A%0Ap
@@ -431,39 +431,26 @@
 private 
-HashMap%3CString, String%3E
+Properties
  variabl
@@ -465,39 +465,26 @@
 private 
-HashMap%3CString, String%3E
+Properties
  propert
@@ -1531,20 +1531,16 @@
 dren; %7D%0A
-    
 %0A    pub
@@ -2913,39 +2913,26 @@
 s = new 
-HashMap%3CString, String%3E
+Properties
 ();%0A    
@@ -3260,16 +3260,24 @@
 bles.get
+Property
 (name) :
@@ -3409,32 +3409,18 @@
 new 
-HashMap%3CString, String%3E 
+Properties
 ();%0A
@@ -3747,16 +3747,24 @@
 ties.get
+Property
 (key) : 

Use Properties instead of HasMap in Symbol.java for readability.