/* We are going to test whether we can insert and delete. */

#include "test.h"

int nums[8] = {0,1,2,3,4,5,6,7};
char letters[2] = {'A','B'};

toku_range_tree *tree;
toku_range* buf;
unsigned buflen;

toku_interval* init_query(toku_interval* range, int left, int right) {
    range->left = (toku_point*)&nums[left];
    range->right = (toku_point*)&nums[right];
    return range;
}

toku_range* init_range(toku_range* range, int left, int right, int data) {
    init_query(&range->ends, left, right);
    if (data < 0)   range->data = 0;
    else            range->data = (TXNID)letters[data];
    return range;
}

void setup_tree(BOOL allow_overlaps, int left, int right, int data) {
    int r;
    toku_range range;
    r = toku_rt_create(&tree, int_cmp, char_cmp, allow_overlaps, malloc, free, realloc);
    CKERR(r);

    r = toku_rt_insert(tree, init_range(&range, left, right, data));CKERR(r);
}
void close_tree(void) {
    int r;
    r = toku_rt_close(tree);    CKERR(r);
}

void runsearch(int rexpect, toku_interval* query, toku_range* expect) {
    int r;
    unsigned found;
    r = toku_rt_find(tree, query, 0, &buf, &buflen, &found);
    CKERR2(r, rexpect);
    
    if (rexpect != 0) return;
    assert(found == 1);
    assert(int_cmp(buf[0].ends.left, expect->ends.left) == 0 &&
           int_cmp(buf[0].ends.right, expect->ends.right) == 0 &&
           char_cmp(buf[0].data, expect->data) == 0);
}

void runinsert(int rexpect, toku_range* toinsert) {
    int r;
    r = toku_rt_insert(tree, toinsert);
    CKERR2(r, rexpect);
}


void verify_overlap(BOOL allow_overlaps) {
    int r;
    BOOL allowed;

    r = toku_rt_get_allow_overlaps(tree, &allowed);
    CKERR(r);
    assert(allowed == allow_overlaps);
}

void tests(BOOL allow_overlaps) {
    toku_range expect;
    toku_interval query;
    toku_range toinsert;

    /*
        Single point overlaps

        * Tree: {|0-1|}, query of |1-2| returns |0-1|
        * Tree: {|1-2|}, query of |0-1| returns |1-2|
        * Tree: {|1-2|}, insert of of |0-1| success == allow_overlaps
        * Tree: {|0-1|}, insert of of |1-2| success == allow_overlaps
    */

    /* Tree: {|0-1|}, query of |1-2| returns |0-1| 
       In this test, I am also going to verify that the allow_overlaps bit
       is set appropriately. */
    setup_tree(allow_overlaps, 0, 1, 0);
    verify_overlap(allow_overlaps);
    runsearch(0, init_query(&query, 1, 2), init_range(&expect, 0, 1, 0));
    close_tree();

    /* Tree: {|1-2|}, query of |0-1| returns |1-2| */
    setup_tree(allow_overlaps, 1, 2, 0);
    runsearch(0, init_query(&query, 0, 1), init_range(&expect, 1, 2, 0));
    close_tree();

    /* Tree: {|1-2|}, insert of of |0-1| success == allow_overlaps */
    setup_tree(allow_overlaps, 1, 2, 0);
    runinsert((allow_overlaps ? 0 : EDOM), init_range(&toinsert, 0, 1, 0));
    close_tree();

    /* Tree: {|0-1|}, insert of of |1-2| success == allow_overlaps */
    setup_tree(allow_overlaps, 0, 1, 0);
    runinsert((allow_overlaps ? 0 : EDOM), init_range(&toinsert, 1, 2, 0));
    close_tree();

    /*
        Complete overlaps
    
        * Tree: {|0-3|}, query of |1-2| returns |0-3|
        * Tree: {|1-2|}, query of |0-3| returns |1-2|
        * Tree: {|1-2|}, insert of of |0-3| success == allow_overlaps
        * Tree: {|0-3|}, insert of of |1-2| success == allow_overlaps
    */

    /* Tree: {|0-3|}, query of |1-2| returns |0-3| */
    setup_tree(allow_overlaps, 0, 3, 0);
    runsearch(0, init_query(&query, 1, 2), init_range(&expect, 0, 3, 0));
    close_tree();

    /* Tree: {|1-2|}, query of |0-3| returns |1-2| */
    setup_tree(allow_overlaps, 1, 2, 0);
    runsearch(0, init_query(&query, 0, 3), init_range(&expect, 1, 2, 0));
    close_tree();

    /* Tree: {|1-2|}, insert of of |0-3| success == allow_overlaps */
    setup_tree(allow_overlaps, 1, 2, 0);
    runinsert((allow_overlaps ? 0 : EDOM), init_range(&toinsert, 0, 3, 0));
    close_tree();

    /* Tree: {|0-3|}, insert of of |1-2| success == allow_overlaps */
    setup_tree(allow_overlaps, 0, 3, 0);
    runinsert((allow_overlaps ? 0 : EDOM), init_range(&toinsert, 1, 2, 0));
    close_tree();

    /*
        Exact overlaps

        * Tree: {|0-3|}, query of |0-3| returns |0-3|
        * Tree: {|0-3|}, insert of of |0-3| success == allow_overlaps
    */

    /* Tree: {|0-3|}, query of |0-3| returns |0-3| */
    setup_tree(allow_overlaps, 0, 3, 0);
    runsearch(0, init_query(&query, 0, 3), init_range(&expect, 0, 3, 0));
    close_tree();

    /* Tree: {(|0-3|,0)}, insert of of (|0-3|,1) success == allow_overlaps */
    setup_tree(allow_overlaps, 0, 3, 0);
    runinsert((allow_overlaps ? 0 : EDOM), init_range(&toinsert, 0, 3, 1));
    close_tree();
}

int main(int argc, const char *argv[]) {
    parse_args(argc, argv);

    buflen = 2;
    buf = (toku_range*)toku_malloc(2 * sizeof(toku_range));
    tests(FALSE);
#ifndef TOKU_RT_NOOVERLAPS
    tests(TRUE);
#endif

    tree = NULL;
    toku_free(buf);
    buf = NULL;
    return 0;
}
