import io
import BinaryTree

type File = {
     write(_:String)->Void
     read->String
     close->Void
     next->String}

type BinaryStringTree = {
    setLeft(_:BinaryStringTree)->Void
    setRight(_:BinaryStringTree)->Void
    clear->Void
    isEmpty->Boolean
    isLeaf->Boolean
    isLeftChild->Boolean
    isRightChild->Boolean
    isRoot->Boolean
    height->Number
    depth->Number
    getString->String
    getLeftChild->BinaryStringTree
    getRightChild->BinaryStringTree
    getParent->BinaryStringTree
    getRoot->BinaryStringTree
    setParent(_:BinaryStringTree)->Void
    ==(_:BinaryStringTree)->Boolean}

def empty:BinaryStringTree is public, readable = BinaryTree.new

//=================================================

// Helper method for writeTree, writes the binary tree to file in
// pre-order traversal
// @pre out refers to a legitimate file, root exists
// @post writes tree to file
// @param out is the file for the animal tree
// @param root is the root of the animal tree

method toFileHelper(out:File, root:BinaryStringTree)->Void is confidential{
    if(root.isLeaf) then {out.write("A{root.getString}\n")}
    else{
        out.write("Q{root.getString}\n")
        toFileHelper(out, root.getLeftChild)
        toFileHelper(out, root.getRightChild)}
}


// Helper method for readTree, reads through file and creates binary tree
// based on questions and answers
// @pre in is a legitimate file
// @post returns tree constructed from file
// @param in is the input file for the animal tree

method readFileHelper(in:File)->BinaryStringTree is confidential{
    var line:String := ""
    var nxt := in.next
    while{nxt != "\n"} do {
        line := line ++ nxt
        nxt := in.next}
    if(line.size > 0) then {
        if(line.at(1) == "Q") then{
            return BinaryTree.withValue(line.substringFrom(2)to(line.size))
                left(readFileHelper(in))right(readFileHelper(in))}
        else{if(line.at(1) == "A") then{
            return BinaryTree.withValue(line.substringFrom(2)to(line.size))}
        }
    }
    BinaryTree.new}


// opens output file and calls recursive emthod to write to it
// @pre filename refers to a legitimate file, root exists
// @post writes file containing questions and answers for tree
// @param filename is the name of the file to write to
// @param root is the root of the animal tree

method writeTree(filename:String, root:BinaryStringTree)->Void is public{
    var outfile := io.open(filename, "w+")
    toFileHelper(outfile, root)
    outfile.close}


// opens input file and calls recursive method to read and create tree
// @pre filename refers to legitimate file
// @post returns tree created from file
// @param filename is the name of the file to read from

method readTree(filename:String)->BinaryStringTree is public{
   var infile := io.open(filename, "r")
   readFileHelper(infile)}