function tree_builder(newick_string) {
    return new _tree_builder(null, newick_string)
}
function _tree_builder(ref, newick_string) {
    if(ref == null) {
        ref = new Object
        ref.count = 0
        ref.cursor = 0
    }
    if(newick_string[ref.cursor] == '(') {
        ref.cursor += 1
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
        //== 1 == Another open parenthesis...
        if(newick_string[ref.cursor] == '(') {
            //thoughts_write("<p style=\"font-family:monospace\"><strong>nested open paren</strong> " + newick_string.substring(ref.cursor) + "</p>")
            this.left = new _tree_builder(ref, newick_string)
            this.left.parent = this
        }
        //== 2 == The name of a node on the LEFT side.
        name = newick_string.substring(ref.cursor).match("^[0-9A-Za-z_|]+")
        //NEXT LINE RESOLVES A FIREFOX BUG: FF REGEX RETURNS ARRAY OF STRINGS
        name = name instanceof Array ? name[0] : name
        //thoughts_write("<p style=\"font-family:monospace\"><strong>getting name</strong> " + inny.substring(ref.cursor) + "</p>")
        //NEXT LINE: FF WANTS null WEBKIT WANTS "null"
        if(name != null && name != "null") {
            
            //thoughts_write("<p style=\"font-family:monospace\"><strong>name</strong> " + name + "</p>")
            //thoughts_write("<p style=\"font-family:monospace\"><strong>name length</strong> " + name.length + "</p>")
            this.left = new Object
            this.left.name = name
            this.left.serial = ref.count++
            this.left.parent = this
            ref.cursor += name.length
        //} else {
            //thoughts_write("<p style=\"font-family:monospace\"><strong>no name for this node</strong></p>")
        }
    }
    white_space = newick_string.substring(ref.cursor).match("^\\s")
    ref.cursor += white_space == null ? 0 : white_space[0].length
    //thoughts_write("<p style=\"font-family:monospace\"><strong>expecting colon</strong> " + newick_string.substring(ref.cursor) + "</p>")
    if(newick_string[ref.cursor] == ':') {
        ref.cursor += 1
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
        //The next value is a double.
        //thoughts_write("<p style=\"font-family:monospace\"><strong>getting branch_length</strong> " + newick_string.substring(ref.cursor) + "</p>")
        branch_length_string = newick_string.substring(ref.cursor).match("^[0-9.+eE-]+")[0]
        if(branch_length_string == null) {
            thoughts_write("<p style=\"font-family:monospace\"><strong>Warning:</strong> Newick string is missing a branch_length value.</p>")
        }
        this.left.branch_length = branch_length_string
        ref.cursor += branch_length_string.length
    //} else {
        //thoughts_write("<p style=\"font-family:monospace\"><strong>no colon for this node</strong></p>")
    }
    white_space = newick_string.substring(ref.cursor).match("^\\s")
    ref.cursor += white_space == null ? 0 : white_space[0].length
    if(newick_string[ref.cursor] == ',') {
        ref.cursor += 1
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
        //== 1 == Another open parenthesis...
        if(newick_string[ref.cursor] == '(') {
            //thoughts_write("<p style=\"font-family:monospace\"><strong>just got open paren reading right node</strong> " + newick_string.substring(ref.cursor) + "</p>")
            this.right = new _tree_builder(ref, newick_string)
            this.right.parent = this
        }
        //== 2 == The name of a node on the RIGHT side.
        name = newick_string.substring(ref.cursor).match("^[0-9A-Za-z_|]+")
        //NEXT LINE RESOLVES A FIREFOX BUG: FF REGEX RETURNS ARRAY OF STRINGS
        name = name instanceof Array ? name[0] : name
        //thoughts_write("<p style=\"font-family:monospace\"><strong>getting name</strong> " + inny.substring(ref.cursor) + "</p>")
        //NEXT LINE: FF WANTS null WEBKIT WANTS "null"
        if(name != null && name != "null") {            
            this.right = new Object
            this.right.name = name
            this.right.serial = ref.count++
            this.right.parent = this
            ref.cursor += name.length
        }
    }
    white_space = newick_string.substring(ref.cursor).match("^\\s")
    ref.cursor += white_space == null ? 0 : white_space[0].length
    if(newick_string[ref.cursor] == ':') {
        ref.cursor += 1
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
        //The next value is a double.
        branch_length_string = newick_string.substring(ref.cursor).match("^[0-9.+eE-]+")
        branch_length_string = branch_length_string == null ? null : branch_length_string[0]
        if(branch_length_string == null) {
            thoughts_write("<p style=\"font-family:monospace\"><strong>Warning:</strong> Newick string is missing a branch_length value.</p>")
        }
        this.right.branch_length = branch_length_string
        ref.cursor += branch_length_string.length
    }
    white_space = newick_string.substring(ref.cursor).match("^\\s")
    ref.cursor += white_space == null ? 0 : white_space[0].length
    if(newick_string[ref.cursor] == ')') {
        ref.cursor += 1
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
    }
    white_space = newick_string.substring(ref.cursor).match("^\\s")
    ref.cursor += white_space == null ? 0 : white_space[0].length
    if(newick_string[ref.cursor] == ':') {
        ref.cursor += 1
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
        //The next value is a double.
        branch_length_string = newick_string.substring(ref.cursor).match("^[0-9.+eE-]+")
        branch_length_string = branch_length_string == null ? null : branch_length_string[0]
        if(branch_length_string == null) {
            thoughts_write("<p style=\"font-family:monospace\"><strong>Warning:</strong> Newick string is missing a branch_length value.</p>")
        }
        this.branch_length = branch_length_string
        this.serial = ref.count++
        ref.cursor += branch_length_string.length
    }
    white_space = newick_string.substring(ref.cursor).match("^\\s")
    ref.cursor += white_space == null ? 0 : white_space[0].length
    if(newick_string[ref.cursor] == ';') {
        ref.cursor += 1;
        white_space = newick_string.substring(ref.cursor).match("^\\s")
        ref.cursor += white_space == null ? 0 : white_space[0].length
        if(this.right == null) {
            if(this.left != null) {
                this.left = this.left.left
                this.right = this.left.right
                this.branch_length = this.left.branch_length
                this.fasta = this.left.fasta
                this.serial = this.left.serial
                this.parent = null
            }
        }
        this.serial = ref.count
    }
    if(ref.cursor >= newick_string.Length) {
            thoughts_write("<p style=\"font-family:monospace\"><strong>Warning:</strong> Newick string overrun?</p>")
    }
}

function tree_traversal(root) {
    return _tree_traversal(null, root)
}
function _tree_traversal(ref, root) {
    if(ref == null) {
        ref = []
    }
    if(root.left) {
        _tree_traversal(ref, root.left)
    }
    if(root.right) {
        _tree_traversal(ref, root.right)
    }
    ref.push(root)
    return ref
}

function tree_expose(root) {
    traverse = tree_traversal(root)
    for(var i in traverse) {
        node = traverse[i]
        thoughts = ""
        thoughts += ("<h3 style=\"font-family:monospace\">")
        thoughts += (node.serial + (node.name ? " : " : ""))
        thoughts += (node.name || "")
        thoughts += ("</h3>")
        thoughts += ("<ul style=\"font-family:monospace\">")
        if(node.left) {
            thoughts += ("<li>left: ")
            thoughts += (node.left.serial + (node.left.name ? " : " : ""))
            thoughts += ((node.left.name || "") + "</li>")
        }
        if(node.right) {
            thoughts += ("<li>right: ")
            thoughts += (node.right.serial + (node.right.name ? " : " : ""))
            thoughts += ((node.right.name || "") + "</li>")
        }
        if(node.parent) {
            thoughts += ("<li>parent: ")
            thoughts += (node.parent.serial + (node.parent.name ? " : " : ""))
            thoughts += ((node.parent.name || "") + "</li>")
        }
        if(node.branch_length) {
            thoughts += ("<li>branch_length: " + node.branch_length + "</li>");
        }
        thoughts += ("</ul>")
        thoughts_write(thoughts)
    }
    return traverse
}

function thoughts_write(what) {
    document.write(what)
}

