/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test
#if SK_SUPPORT_GPU

#include "GrRedBlackTree.h"
#include "SkRandom.h"
#include "Test.h"

typedef GrRedBlackTree<int> Tree;

DEF_TEST(GrRedBlackTreeTest, reporter) {
    Tree tree;

    SkRandom r;

    int count[100] = {0};
    // add 10K ints
    for (int i = 0; i < 10000; ++i) {
        int x = r.nextU() % 100;
        Tree::Iter xi = tree.insert(x);
        REPORTER_ASSERT(reporter, *xi == x);
        ++count[x];
    }

    tree.insert(0);
    ++count[0];
    tree.insert(99);
    ++count[99];
    REPORTER_ASSERT(reporter, *tree.begin() == 0);
    REPORTER_ASSERT(reporter, *tree.last() == 99);
    REPORTER_ASSERT(reporter, --(++tree.begin()) == tree.begin());
    REPORTER_ASSERT(reporter, --tree.end() == tree.last());
    REPORTER_ASSERT(reporter, tree.count() == 10002);

    int c = 0;
    // check that we iterate through the correct number of
    // elements and they are properly sorted.
    for (Tree::Iter a = tree.begin(); tree.end() != a; ++a) {
        Tree::Iter b = a;
        ++b;
        ++c;
        REPORTER_ASSERT(reporter, b == tree.end() || *a <= *b);
    }
    REPORTER_ASSERT(reporter, c == tree.count());

    // check that the tree reports the correct number of each int
    // and that we can iterate through them correctly both forward
    // and backward.
    for (int i = 0; i < 100; ++i) {
        int c;
        c = tree.countOf(i);
        REPORTER_ASSERT(reporter, c == count[i]);
        c = 0;
        Tree::Iter iter = tree.findFirst(i);
        while (iter != tree.end() && *iter == i) {
            ++c;
            ++iter;
        }
        REPORTER_ASSERT(reporter, count[i] == c);
        c = 0;
        iter = tree.findLast(i);
        if (iter != tree.end()) {
            do {
                if (*iter == i) {
                    ++c;
                } else {
                    break;
                }
                if (iter != tree.begin()) {
                    --iter;
                } else {
                    break;
                }
            } while (true);
        }
        REPORTER_ASSERT(reporter, c == count[i]);
    }
    // remove all the ints between 25 and 74. Randomly chose to remove
    // the first, last, or any entry for each.
    for (int i = 25; i < 75; ++i) {
        while (0 != tree.countOf(i)) {
            --count[i];
            int x = r.nextU() % 3;
            Tree::Iter iter;
            switch (x) {
            case 0:
                iter = tree.findFirst(i);
                break;
            case 1:
                iter = tree.findLast(i);
                break;
            case 2:
            default:
                iter = tree.find(i);
                break;
            }
            tree.remove(iter);
        }
        REPORTER_ASSERT(reporter, 0 == count[i]);
        REPORTER_ASSERT(reporter, tree.findFirst(i) == tree.end());
        REPORTER_ASSERT(reporter, tree.findLast(i) == tree.end());
        REPORTER_ASSERT(reporter, tree.find(i) == tree.end());
    }
    // remove all of the 0 entries. (tests removing begin())
    REPORTER_ASSERT(reporter, *tree.begin() == 0);
    REPORTER_ASSERT(reporter, *(--tree.end()) == 99);
    while (0 != tree.countOf(0)) {
        --count[0];
        tree.remove(tree.find(0));
    }
    REPORTER_ASSERT(reporter, 0 == count[0]);
    REPORTER_ASSERT(reporter, tree.findFirst(0) == tree.end());
    REPORTER_ASSERT(reporter, tree.findLast(0) == tree.end());
    REPORTER_ASSERT(reporter, tree.find(0) == tree.end());
    REPORTER_ASSERT(reporter, 0 < *tree.begin());

    // remove all the 99 entries (tests removing last()).
    while (0 != tree.countOf(99)) {
        --count[99];
        tree.remove(tree.find(99));
    }
    REPORTER_ASSERT(reporter, 0 == count[99]);
    REPORTER_ASSERT(reporter, tree.findFirst(99) == tree.end());
    REPORTER_ASSERT(reporter, tree.findLast(99) == tree.end());
    REPORTER_ASSERT(reporter, tree.find(99) == tree.end());
    REPORTER_ASSERT(reporter, 99 > *(--tree.end()));
    REPORTER_ASSERT(reporter, tree.last() == --tree.end());

    // Make sure iteration still goes through correct number of entries
    // and is still sorted correctly.
    c = 0;
    for (Tree::Iter a = tree.begin(); tree.end() != a; ++a) {
        Tree::Iter b = a;
        ++b;
        ++c;
        REPORTER_ASSERT(reporter, b == tree.end() || *a <= *b);
    }
    REPORTER_ASSERT(reporter, c == tree.count());

    // repeat check that correct number of each entry is in the tree
    // and iterates correctly both forward and backward.
    for (int i = 0; i < 100; ++i) {
        REPORTER_ASSERT(reporter, tree.countOf(i) == count[i]);
        int c = 0;
        Tree::Iter iter = tree.findFirst(i);
        while (iter != tree.end() && *iter == i) {
            ++c;
            ++iter;
        }
        REPORTER_ASSERT(reporter, count[i] == c);
        c = 0;
        iter = tree.findLast(i);
        if (iter != tree.end()) {
            do {
                if (*iter == i) {
                    ++c;
                } else {
                    break;
                }
                if (iter != tree.begin()) {
                    --iter;
                } else {
                    break;
                }
            } while (true);
        }
        REPORTER_ASSERT(reporter, count[i] == c);
    }

    // remove all entries
    while (!tree.empty()) {
        tree.remove(tree.begin());
    }

    // test reset on empty tree.
    tree.reset();
}

#endif