// Copyright 2013-2018 the openage authors. See copying.md for legal info.

#pragma once

#include <cstdarg>
#include <functional>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#if defined(__GNUC__)
#define ATTRIBUTE_FORMAT(i, j) __attribute__ ((format (printf, i, j)))
#else
#define ATTRIBUTE_FORMAT(i, j)
#endif

namespace openage {
namespace util {


/**
 * Quick-formatter for floats when working with string streams.
 * Usage: cout << FormatFloat{1.0, 10};
 */
template<unsigned decimals, unsigned w=0>
struct FloatFixed {
	float value;
};


template<unsigned decimals, unsigned w>
std::ostream &operator <<(std::ostream &os, FloatFixed<decimals, w> f) {
	static_assert(decimals < 50, "Refusing to print float with >= 50 decimals");
	static_assert(w < 70, "Refusing to print float with a width >= 70");

	os.precision(decimals);
	os << std::fixed;

	if (w) {
		os << std::setw(w);
	}

	os << f.value;

	return os;
}


/**
 * printf-style to-string formatting.
 */
std::string sformat(const char *fmt, ...) ATTRIBUTE_FORMAT(1, 2);


/**
 * printf-style valist-to-string formatting; the result is appended to output.
 */
size_t vsformat(const char *fmt, va_list ap, std::string &output);


/**
 * Copies the given string to the returned unique_ptr, including 0 byte.
 */
std::unique_ptr<char[]> copy_string(const char *s);


/**
 * Returns the number of whitespace characters on the right of the string.
 */
size_t rstrip(char *s);


/**
 * returns true if str matches the basic globbing pattern
 * in the pattern, '*' matches any number of characters, while all other
 * characters are interpreted as literal.
 */
bool string_matches_pattern(const char *str, const char *pattern);


/**
 * Split a string at a delimiter, push the result back in an iterator.
 * Why doesn't the fucking standard library have std::string::split(delimiter)?
 */
template<typename ret_t>
void split(const std::string &txt, char delimiter, ret_t result) {
	std::stringstream splitter;
	splitter.str(txt);
	std::string part;

	while (std::getline(splitter, part, delimiter)) {
		*result = part;
		result++;
	}
}


/**
 * Split a string at a delimiter into a vector.
 * Internally, uses the above iterator splitter.
 */
std::vector<std::string> split(const std::string &txt, char delim);


/**
 * Split a string at a delimiter into a vector.
 * size_hint is to give a predicted size of the vector already.
 *
 * tokenizes txt by splitting it up to substrings at the deliminiters.
 * "\n" is evaluated to '\n'; all other '\X' escape sequences are evaluated
 * to literal X, including the deliminiter.
 */
std::vector<std::string> split_escape(const std::string &txt,
                                      char delim, size_t size_hint=0);

}} // openage::util
