#include <iostream>

#include "common/utils/SplitString.h"
#include "common/utils/Array.h"
#include "common/utils/HashMap.h"
#include "common/utils/List.h"
#include "client/math/Vector.h"
#include "client/math/Matrix.h"
#include "common/utils/HashedString.h"
#include "common/utils/Random.h"

typedef List<const char*, 16> StringList;

const char* RED = "\033[0;31m";
const char* GREEN = "\033[0;32m";

uint tests = 0;
uint successTests = 0;

void finalizeTest() {
    std::cout << ((successTests == tests) ? GREEN : RED);
    std::cout << successTests << " / " << tests << " succeeded\n";
    tests = 0;
    successTests = 0;
}

template<typename T>
void checkEqual(const T& wanted, const T& actual, const char* text) {
    if(wanted == actual) {
        tests++;
        successTests++;
        std::cout << GREEN << tests << ": " << text << "\n";
    } else {
        tests++;
        std::cout << RED << tests << ": " << text << " - ";
        std::cout << RED << "expected '" << wanted << "' got '" << actual << "'\n";
    }
}

void checkCommandParser(const char* rawCommand, const StringList& result, const char* text) {
    SplitString split(rawCommand);
    checkEqual(result.getLength(), split.getLength(), text);
    for(uint i = 0; i < result.getLength() && i < split.getLength(); i++) {
        checkEqual(String(result[i]), String(split[i]), text);
    }
}

void testCommandParser() {
    StringList list;

    list.clear().add("test");
    checkCommandParser("test", list, "command without arguments");

    list.clear().add("test").add("aaa");
    checkCommandParser("test aaa", list, "command with one argument");

    list.clear().add("test").add("aaa").add("bbbb");
    checkCommandParser("test aaa bbbb", list, "command with two arguments");

    list.clear().add("test").add("aaa").add("bbbb").add("ccccc");
    checkCommandParser("test aaa bbbb ccccc", list, "command with three arguments");

    list.clear().add("test");
    checkCommandParser("test    ", list, "command with spaces");

    list.clear().add("test").add("aaa").add("bbbb");
    checkCommandParser("test  aaa   bbbb", list, "command with arguments and spaces");

    list.clear().add("test").add("aaa bbbb");
    checkCommandParser("test \"aaa bbbb\"", list, "command with one argument and quotation marks");

    list.clear().add("test").add("aaa bbbb").add("ccc");
    checkCommandParser("test \"aaa bbbb\" ccc", list, "command with two arguments and quotation marks");

    list.clear().add("test").add("ddd").add("aaa bbbb").add("ccc");
    checkCommandParser("test ddd \"aaa bbbb\" ccc", list, "command with tree arguments and quotation marks");

    list.clear().add("test").add("");
    checkCommandParser("test \"\"", list, "command with empty argument");

    list.clear();
    checkCommandParser("test \"", list, "command syntax exception 1");
    checkCommandParser("test aaa\"", list, "command syntax exception 2");
    checkCommandParser("test aaa\"bbb\"", list, "command syntax exception 3");
    checkCommandParser("test aaa \"bbb\"ccc", list, "command syntax exception 4");

    finalizeTest();
}

long getNanos() {
    struct timespec time;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time);
    return time.tv_nsec + time.tv_sec * 1000000000;
}

int main() {
    //testCommandParser();
    return 0;
}