#ifndef __CONSTANTS__H__
#define __CONSTANTS__H__

#include <cerrno>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <optional>
#include <sstream>
#include <string>

using namespace std;

// TODO: move other relevant constants and configurable values here

/* Global static constants holder and utility functions */
class G {
public:
	/* timer to check memory */
	static constexpr int USAGE_TIMER = 20;

	/* format string colours */
	static constexpr int COLON_COLOUR = 6;
	static constexpr int CURSOR_COLOUR = 7;

	/* used to signal an unset position */
	static constexpr size_t NO_POS = static_cast<size_t>(-1);

	/* used in searching to signal search has reached end of the file */
	static constexpr size_t EOF_POS = static_cast<size_t>(-1000);

	// signal format for bold
	static constexpr size_t LOWEST_MODIFIER = 32;
	static constexpr size_t BOLD = 32;

	// signal format for underline
	static constexpr size_t UNDERLINE = 64;

	// used to signal a weak colour that will be overrided with another
	static constexpr size_t WEAK = 128;

	/* constants for directions */
	static constexpr size_t DIR_DOWN = 1;
	static constexpr size_t DIR_UP = 0;

	// TODO perhaps use the current width of terminal instead
	static constexpr size_t LINE_WIDTH = 80;

	// how many lines get searched at a time before release the log lines
	// lock
	static constexpr size_t SEARCH_RANGE = 1024;

	/* returns half the width of the screen, to implement left and right
	 * moving */
	static size_t h_shift() {
		return h_shift(nullopt);
	}

	/* renderer will update this value to half the number of cols to support
	 * left right moving. pass nullopt to read the stored value.
	 * start with a default of 40 assuming 80 col term. */
	static size_t h_shift(optional<size_t> value) {
		static size_t _val = 40;
		if (value) _val = *value;
		return _val;
	}

	// dash line for separating
	static constexpr const char* DASH = "---------------------------------------------";

	/* constants for matching mode */
	static constexpr int FILTER_NONE = 0;
	static constexpr int FILTER_AND = 1;
	static constexpr int FILTER_OR = 2;
	// number of filter types
	static constexpr int FILTER_TOTAL = 3;

	// return a prefix and errno with string of error
	static string errno_string(const string& prefix, int error) {
		stringstream ss;
		ss << prefix << " errno=" << error
		   << " " << strerror(error);
		return ss.str();
	}

	// return lowercase version of string
	static string to_lower(const string_view& data) {
		string ret;
		ret.reserve(data.length());
		for (const char& c : data) {
			ret += tolower(c);
		}
		return ret;
	}

	// clears the debug log on starting
	static void clear_log() {
		if (filesystem::exists("logserver.debug")) {
			ofstream fout("logserver.debug", ios::out);
		}
	}

	// writes a log message to debug log
	static void log(const string& s) {
		ofstream fout("logserver.debug", ios::app);
		fout << s << endl;
	}

	// turns a set to a vector
	template <typename T>
	static vector<T> set_to_vec(const set<T>& in) {
		vector<T> out;
		for (const auto& x : in) out.push_back(x);
		return out;
	}

	// gets full path for a possibly relative one
        static string realpath(const string_view& path) {
                string ret = "";
                char* delete_me = ::realpath(path.data(), nullptr);
                if (delete_me) ret = string(delete_me);
                free(delete_me);
                return ret;
        }

};

#endif  // __CONSTANTS__H__
