import io
import BinaryTreeIO
import BinaryTree

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}

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

// access to standard output and input
var ostream is public, readable:= io.output
var istream is public, readable:= io.input

// helper method to read line of text from standard input
method getLine->String is confidential{
    var line:String := ""
    var nxt := istream.next
    while{nxt != "\n"} do {
        line := line ++ nxt
        nxt := istream.next}
    return line}

// plays one round of the animal game
// @post @return updated binary tree of quetsions and answers
// @param animalTree is the binary tree read from the file
method playRound(animalTree:BinaryStringTree)->BinaryStringTree is confidential{
    var answer:String := ""

    // goes through tree until it hits an answer
    // if user responds "y" to question, goes right
    // otherwise goes left
    while{!animalTree.isLeaf} do{
        ostream.write("{animalTree.getString}\n")
        answer := getLine
        if(answer == "y") then {animalTree := animalTree.getRightChild}
        else{animalTree := animalTree.getLeftChild}
    }

    ostream.write("Were you thinking of a {animalTree.getString}?\n")
    var finalAnswer:String := getLine

    // user's answer is already in tree, return animal tree
    // without modifications
    if(finalAnswer == "y") then{
        ostream.write("Great!\n")
        return animalTree.getRoot}

    // user is thinking of animal not yet in tree
    // prompts user to enter question & answer to specify animal
    // inserts new question and answer into tree and returns
    // modified tree
    else{
        ostream.write("What was the animal?\n")
        var animal:String := getLine
        ostream.write("What question separates {animal} from {animalTree.getString}?\n")
        var question:String := getLine
        ostream.write("What is the correct answer for this animal?\n")
        var correctAnswer:String := getLine
        var parent:BinaryStringTree := animalTree.getParent
        var newTree:BinaryStringTree
        if(correctAnswer == "y") then{
            newTree := 
                BinaryTree.withValue(question)left(animalTree)
                    right(BinaryTree.withValue(animal))}
        else{newTree := 
                 BinaryTree.withValue(question)
                     left(BinaryTree.withValue(animal))right(animalTree)}
        if(answer == "y") then {parent.setRight(newTree)}
        else{parent.setLeft(newTree)}
        return newTree.getRoot}
}

// reads in animal tree from file & continues to play rounds while user 
// inputs "y"
// writes updated tree to file at end of game
method play->Void is public{
    var animalTree:BinaryStringTree := BinaryTreeIO.readTree("animals.tree")
    ostream.write("Welcome to the Animals game!\n")
    ostream.write("Shall we play a game? (y/n)\n")

    var ans:String := getLine
    while{ans == "y"} do{
        animalTree := playRound(animalTree)
        ostream.write("Shall we play a game?(y/n)\n")
        ans := getLine}
    ostream.write("Bye!\n")
    BinaryTreeIO.writeTree("animals.tree", animalTree)}

play