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

#include "SkCommandLineFlags.h"
#include "SkGraphics.h"
#include "SkOSFile.h"
#include "SkRunnable.h"
#include "SkTArray.h"
#include "SkTemplates.h"
#include "SkThreadPool.h"
#include "SkTime.h"
#include "Test.h"

#if SK_SUPPORT_GPU
#include "GrContext.h"
#endif

using namespace skiatest;

// need to explicitly declare this, or we get some weird infinite loop llist
template TestRegistry* TestRegistry::gHead;

class Iter {
public:
    Iter(Reporter* r) : fReporter(r) {
        r->ref();
        this->reset();
    }

    void reset() {
        fReg = TestRegistry::Head();
    }

    ~Iter() {
        fReporter->unref();
    }

    Test* next() {
        if (fReg) {
            TestRegistry::Factory fact = fReg->factory();
            fReg = fReg->next();
            Test* test = fact(NULL);
            test->setReporter(fReporter);
            return test;
        }
        return NULL;
    }

private:
    Reporter* fReporter;
    const TestRegistry* fReg;
};

class DebugfReporter : public Reporter {
public:
    DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose)
        : fNextIndex(0)
        , fPending(0)
        , fTotal(0)
        , fAllowExtendedTest(allowExtendedTest)
        , fAllowThreaded(allowThreaded)
        , fVerbose(verbose) {
    }

    void setTotal(int total) {
        fTotal = total;
    }

    virtual bool allowExtendedTest() const SK_OVERRIDE {
        return fAllowExtendedTest;
    }

    virtual bool allowThreaded() const SK_OVERRIDE {
        return fAllowThreaded;
    }

    virtual bool verbose() const SK_OVERRIDE {
        return fVerbose;
    }

protected:
    virtual void onStart(Test* test) {
        const int index = sk_atomic_inc(&fNextIndex);
        sk_atomic_inc(&fPending);
        SkDebugf("[%3d/%3d] (%d) %s\n", index+1, fTotal, fPending, test->getName());
    }
    virtual void onReportFailed(const SkString& desc) {
        SkDebugf("\tFAILED: %s\n", desc.c_str());
    }

    virtual void onEnd(Test* test) {
        if (!test->passed()) {
            SkDebugf("---- %s FAILED\n", test->getName());
        }

        sk_atomic_dec(&fPending);
        if (fNextIndex == fTotal) {
            // Just waiting on straggler tests.  Shame them by printing their name and runtime.
            SkDebugf("          (%d) %5.1fs %s\n",
                     fPending, test->elapsedMs() / 1e3, test->getName());
        }
    }

private:
    int32_t fNextIndex;
    int32_t fPending;
    int fTotal;
    bool fAllowExtendedTest;
    bool fAllowThreaded;
    bool fVerbose;
};

DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
                               "Multiple matches may be separated by spaces.\n" \
                               "~ causes a matching test to always be skipped\n" \
                               "^ requires the start of the test to match\n" \
                               "$ requires the end of the test to match\n" \
                               "^ and $ requires an exact match\n" \
                               "If a test does not match any list entry,\n" \
                               "it is skipped unless some list entry starts with ~");
DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
DEFINE_bool2(single, z, false, "run tests on a single thread internally.");
DEFINE_bool2(verbose, v, false, "enable verbose output.");
DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
             "Run threadsafe tests on a threadpool with this many threads.");

SkString Test::GetTmpDir() {
    const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
    return SkString(tmpDir);
}

SkString Test::GetResourcePath() {
    const char* resourcePath = FLAGS_resourcePath.isEmpty() ? NULL : FLAGS_resourcePath[0];
    return SkString(resourcePath);
}

// Deletes self when run.
class SkTestRunnable : public SkRunnable {
public:
  // Takes ownership of test.
  SkTestRunnable(Test* test, int32_t* failCount) : fTest(test), fFailCount(failCount) {}

  virtual void run() {
      fTest->run();
      if(!fTest->passed()) {
          sk_atomic_inc(fFailCount);
      }
      SkDELETE(this);
  }

private:
    SkAutoTDelete<Test> fTest;
    int32_t* fFailCount;
};

int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
    SkCommandLineFlags::SetUsage("");
    SkCommandLineFlags::Parse(argc, argv);

#if SK_ENABLE_INST_COUNT
    gPrintInstCount = true;
#endif

    SkGraphics::Init();

    {
        SkString header("Skia UnitTests:");
        if (!FLAGS_match.isEmpty()) {
            header.appendf(" --match");
            for (int index = 0; index < FLAGS_match.count(); ++index) {
                header.appendf(" %s", FLAGS_match[index]);
            }
        }
        SkString tmpDir = Test::GetTmpDir();
        if (!tmpDir.isEmpty()) {
            header.appendf(" --tmpDir %s", tmpDir.c_str());
        }
        SkString resourcePath = Test::GetResourcePath();
        if (!resourcePath.isEmpty()) {
            header.appendf(" --resourcePath %s", resourcePath.c_str());
        }
#ifdef SK_DEBUG
        header.append(" SK_DEBUG");
#else
        header.append(" SK_RELEASE");
#endif
#ifdef SK_SCALAR_IS_FIXED
        header.append(" SK_SCALAR_IS_FIXED");
#else
        header.append(" SK_SCALAR_IS_FLOAT");
#endif
        SkDebugf("%s\n", header.c_str());
    }

    DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose);
    Iter iter(&reporter);

    // Count tests first.
    int total = 0;
    int toRun = 0;
    Test* test;

    SkTDArray<const char*> matchStrs;
    for(int i = 0; i < FLAGS_match.count(); ++i) {
        matchStrs.push(FLAGS_match[i]);
    }

    while ((test = iter.next()) != NULL) {
        SkAutoTDelete<Test> owned(test);

        if(!SkCommandLineFlags::ShouldSkip(matchStrs, test->getName())) {
            toRun++;
        }
        total++;
    }
    reporter.setTotal(toRun);

    // Now run them.
    iter.reset();
    int32_t failCount = 0;
    int skipCount = 0;

    SkAutoTDelete<SkThreadPool> threadpool(SkNEW_ARGS(SkThreadPool, (FLAGS_threads)));
    SkTArray<Test*> unsafeTests;  // Always passes ownership to an SkTestRunnable
    for (int i = 0; i < total; i++) {
        SkAutoTDelete<Test> test(iter.next());
        if (SkCommandLineFlags::ShouldSkip(matchStrs, test->getName())) {
            ++skipCount;
        } else if (!test->isThreadsafe()) {
            unsafeTests.push_back() = test.detach();
        } else {
            threadpool->add(SkNEW_ARGS(SkTestRunnable, (test.detach(), &failCount)));
        }
    }

    // Run the tests that aren't threadsafe.
    for (int i = 0; i < unsafeTests.count(); i++) {
        SkNEW_ARGS(SkTestRunnable, (unsafeTests[i], &failCount))->run();
    }

    // Blocks until threaded tests finish.
    threadpool.free();

    SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
             toRun, failCount, skipCount);
    const int testCount = reporter.countTests();
    if (FLAGS_verbose && testCount > 0) {
        SkDebugf("Ran %d Internal tests.\n", testCount);
    }
#if SK_SUPPORT_GPU

#if GR_CACHE_STATS
    GrContext *gr = GpuTest::GetContext();

    gr->printCacheStats();
#endif

#endif

    SkGraphics::Term();
    GpuTest::DestroyContexts();

    return (failCount == 0) ? 0 : 1;
}

#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
int main(int argc, char * const argv[]) {
    return tool_main(argc, (char**) argv);
}
#endif
