/*
 * Testing AVL trees
 * 15-122 Principles of Imperative Computation, Spring 2011
 * William Lovas
 */

#use <conio>


/*** tree and bst pretty-printing ***/

void print_tree(tree T)
//@requires is_ordtree(T);
{
    if (T == NULL) {
        print(".");
    } else {
        print("(");
        print_tree(T->left);
        print(" ");
        print(elem_key(T->data));
        print(" ");
        print_tree(T->right);
        print(")");
    }
}

void print_bst(bst B)
//@requires is_bst(B);
{
    print_tree(B->root);
    println("");
}

/*** equality checking for elements, trees, and bsts ***/

bool elem_equal(elem e1, elem e2)
//@requires e1 != NULL && e2 != NULL;
{
    return string_equal(e1->word, e2->word)
        && e1->count == e2->count;
}

bool tree_equal(tree T1, tree T2)
//@requires is_ordtree(T1) && is_ordtree(T2);
{
    if (T1 == NULL && T2 == NULL) return true;
    if (T1 != NULL && T2 != NULL) {
        return T1->height == T2->height
            && tree_equal(T1->left, T2->left)
            && tree_equal(T1->right, T2->right)
            && elem_equal(T1->data, T2->data);
    }
    return false;
}

bool bst_equal(bst B1, bst B2)
//@requires is_bst(B1) && is_bst(B2);
{
    return tree_equal(B1->root, B2->root);
}


/*** some convenience constructors ***/

elem Elem(string w)
//@ensures \result != NULL;
{
    elem e = alloc(struct wcount);
    e->word = w;
    e->count = 0;
    return e;
}

tree Make(tree l, elem e, tree r)
//@requires is_ordered(l, NULL, e);
//@requires is_ordered(r, e, NULL);
//@ensures is_ordtree(\result);
{
  int hl = height(l);
  int hr = height(r);
  int h = hl > hr ? hl+1 : hr+1;
  tree T = alloc(struct tree);
  T->height = h;
  T->left = l;
  T->data = e;
  T->right = r;
  return T;
}

bst Make_bst(tree T)
//@requires is_ordtree(T);
//@ensures is_bst(\result);
{
    bst B = alloc(struct bst);
    B->root = T;
    return B;
}

tree Leaf(string s)
//@ensures is_ordtree(\result);
{
    return Make(NULL, Elem(s), NULL);
}

tree Node(tree L, string s, tree R)
//@requires is_ordered(L, NULL, Elem(s));
//@requires is_ordered(R, Elem(s), NULL);
//@ensures is_ordered(\result, NULL, NULL);
{
    return Make(L, Elem(s), R);
}


/* a function for testing a single insertion:
 *  - test is the name of the test, for reporting
 *  - B is the input BST
 *  - e is the element to insert
 *  - R is the expected result
 * if the result of inserting e into B is not R,
 * complain loudly.  print our expectations along
 * the way for clarity...
 */
void test_insert(string test, bst B, elem e, bst R)
//@requires is_bst(B) && e != NULL && is_bst(R);
{
    println(test);
    bst_insert(B, e);
    print(" expected: "); print_bst(R);
    print(" returned: "); print_bst(B);
    assert(bst_equal(B, R));
}


/*** the actual testing!  note: non-exhaustive.  can you do better? ***/

int main() {
    // insert into empty tree
    test_insert("insert into empty tree",
                Make_bst(NULL),
                Elem("5"),
                Make_bst(Leaf("5")));

    // insert in right subtree
    test_insert("insert into right subtree",
                Make_bst(Node(NULL, "5", NULL)),
                Elem("3"),
                Make_bst(Node(Leaf("3"), "5", NULL)));

    // insert in left subtree
    test_insert("insert into left subtree",
                Make_bst(Node(NULL, "5", NULL)),
                Elem("7"),
                Make_bst(Node(NULL, "5", Leaf("7"))));

    // insert in left subtree incurring single rotation
    test_insert("insert into left subtree incurring single rotation",
                Make_bst(Node(Leaf("3"), "5", NULL)),
                Elem("1"),
                Make_bst(Node(Leaf("1"), "3", Leaf("5"))));


    // insert in left subtree incurring double rotation
    test_insert("insert into left subtree incurring double rotation",
                Make_bst(Node(Leaf("3"), "5", NULL)),
                Elem("4"),
                Make_bst(Node(Leaf("3"), "4", Leaf("5"))));
    return 0;
}
