#include <iostream>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <sys/time.h>

#include "test_utils.hh"

using namespace std;

const char *parse_progname(const char *c)
{
    assert(c);
    const char * progname = strrchr(c, '/');
    if (progname)
        progname++;
    else
        progname = c;
    return progname;
}

int parse_int(const char *c, int *result)
{
    assert(c);
    assert(result);
    char *endptr;
    errno = 0;
    *result = strtol(c, &endptr, 0);
    const int local_errno = errno;
    if (local_errno || *endptr != '\0')
    {
        cerr << "Expected an integer, got \"" << c << "\", " << endl;
        if (local_errno)
            cerr << strerror(local_errno) << endl;
        return 1;
    }
    return 0;
}

int parse_unsigned(const char *c, unsigned *result)
{
    assert(c);
    assert(result);
    char *endptr;
    errno = 0;
    *result = strtoul(c, &endptr, 0);
    const int local_errno = errno;
    if (local_errno || *endptr != '\0')
    {
        cerr << "Expected an unsigned integer, got \"" << c << "\", " << endl;
        if (local_errno)
            cerr << strerror(local_errno) << endl;
        return 1;
    }
    return 0;
}

int parse_double(const char *c, double *result)
{
    assert(c);
    assert(result);
    char *endptr;
    errno = 0;
    *result = strtod(c, &endptr);
    const int local_errno = errno;
    if (local_errno || *endptr != '\0')
    {
        cerr << "Expected a double, got \"" << c << "\", " << endl;
        if (local_errno)
            cerr << strerror(local_errno) << endl;
        return 1;
    }
    return 0;
}

int parse_vector_of_doubles(char **c, const int n, std::vector<double>* v)
{
    if (n < 0)
    {
        cerr << "Error in parse_vector_of_doubles: negative argument count" << endl;
        return 1;
    }
    for (int i=0; i<n; ++i)
    {
        double d;
        if (parse_double(c[i], &d))
            return 1;
        v->push_back(d);
    }
    return 0;
}

double test_rng()
{
    return drand48();
}

std::string random_string(const unsigned len)
{
    std::string s(len, '\0');
    for (unsigned i=0; i<len; ++i)
        s[i] = static_cast<char>(test_rng()*127);
    return s;
}

static unsigned long long tv_to_usec(const struct timeval* tv)
{
    unsigned long long usec = tv->tv_usec;
    usec += tv->tv_sec*1000000ULL;
    return usec;
}

double time_of_run(void (*fcn)(void), const unsigned n)
{
    assert(fcn);
    assert(n);
    struct timeval tv0, tv1;
    gettimeofday(&tv0, NULL);
    for (unsigned i=0; i<n; ++i)
        fcn();
    gettimeofday(&tv1, NULL);
    unsigned long long udelta = tv_to_usec(&tv1) - tv_to_usec(&tv0);
    return (double)udelta/n;
}
