#include "contour_test.h"
#include <string>
#include <vector>
#include <iostream>

/************************************************
 **A few global variables for genuine ugliness.**
 ************************************************/

/** Generate only the file with this name (range). */
std::vector<std::pair<int, int>> test_only_this_one;
/** For every picture where we generate more things (multiple arrowheads, contours, etc.)
 * draw only these items (inclusive ranges). If empty we draw all.
 * It impacts all such tests, can be combined with test_only_this_one.*/
std::vector<std::pair<int, int>> draw_only_these;

/**Counts which item is drawn on a specific output image.
 * Incremented by shall_draw() below, zeroed by shouldnt_do() below.*/
thread_local int seq_ = 0;

/** Call this at the beginning of each test output image
 * to see if the test shall be skipped */
bool shouldnt_do(int i) noexcept {
    seq_ = 0;
    return test_only_this_one.size()
        && std::ranges::none_of(test_only_this_one,
                                [i](auto p) {return p.first<=i && i<=p.second; });
}
/** Call this at the beginning of each section with an (inclusive)
 * range of tests to see if all of them shall be skipped. */
bool shouldnt_do(int i, int j) noexcept {
    seq_ = 0;
    return test_only_this_one.size()
        && std::ranges::none_of(test_only_this_one,
                                [i, j](auto p) {return p.first<=j && i<=p.second; });
}
/** Call this before drawing every item on a test image to see if that shall be drawn or not. */
bool shall_draw() noexcept {
    seq_++;
    return draw_only_these.empty()
        || std::ranges::any_of(draw_only_these, [](std::pair<int, int> a) { return a.first<=seq_ && seq_<=a.second; });
}

//This throws on error
std::pair<int, int> parse_range(const std::string& a) {
    if (const size_t dash = a.find_last_of('-'); dash!=std::string::npos) {
        const int f = dash==0 ? 1 : std::stoi(a.substr(0, dash));
        const int t = dash==a.size()-1 ? 100000 : std::stoi(a.substr(dash+1));
        return {f, t};
    } else {
        const int e = std::stoi(a);
        return {e, e};
    }
}


int main(int n, char** argv) {
    int max_threads = 1;
    bool experiment = false;
    for (int i = 1; i<n; i++) {
        const std::string a{argv[i]};
        try {
            if (a=="-e")
                experiment = true;
            else if (a.starts_with("-j"))
                max_threads = std::stoi(a.substr(2));
            else if (a.starts_with("-o"))
                test_only_this_one.push_back(parse_range(a.substr(2)));
            else if (a.starts_with("-d"))
                draw_only_these.push_back(parse_range(a.substr(2)));
            else if (a.starts_with("-F"))
                CairoContext::font_face = a.substr(2);
            else
                throw 1; //sorry to use exceptions for flow control
        } catch (...) {
            std::cerr<<
                "Bad argument: "<<a<<"\n"
                "Possible arguments:\n"
                "-e        Run only the experiment\n"
                "-o<M>-<N> Generate only these output images. Can specify multiple -o.\n"
                "          To get test123.png, use -o123, to get test123_004, use -o1234\n"
                "-d<M>-<N> Generate only items of output images in this range. Can specify\n"
                "          multiple -d options. You can omit any of the numbers or just have\n"
                "          a single number.\n"
                "-F<font_face>\n"
                "          Set the font face to use when generating test images.\n";
            return 1;
        }
    }
    if (experiment) contour_test_experiment();
    else contour_test(max_threads);
    return 0;
}
