#ifndef GLOB_HPP
#define GLOB_HPP

enum class Glob_Result
{
	OOM_ERROR,
	ENCODING_ERROR,
	SYNTAX_ERROR,
	UNMATCHED,
	MATCHED,
};

// https://github.com/tsoding/glob.h
Glob_Result glob(const char *pattern, const char *text);

#endif // GLOB_HPP

#ifdef GLOB_IMPLEMENTATION

Glob_Result glob(const char *pattern, const char *text)
{
	while (*pattern != '\0' && *text != '\0')
	{
		switch (*pattern)
		{
		case '?':
		{
			pattern += 1;
			text += 1;
		}
		break;

		case '*':
		{
			Glob_Result result = glob(pattern + 1, text);
			if (result != Glob_Result::UNMATCHED)
				return result;
			text += 1;
		}
		break;

		case '[':
		{
			bool matched = false;
			bool negate = false;

			pattern += 1; // skipping [
			if (*pattern == '\0')
				return Glob_Result::SYNTAX_ERROR; // unclosed [

			if (*pattern == '!')
			{
				negate = true;
				pattern += 1;
				if (*pattern == '\0')
					return Glob_Result::SYNTAX_ERROR; // unclosed [
			}

			char prev = *pattern;
			matched |= prev == *text;
			pattern += 1;

			while (*pattern != ']' && *pattern != '\0')
			{
				switch (*pattern)
				{
				case '-':
				{
					pattern += 1;
					switch (*pattern)
					{
					case ']':
						matched |= '-' == *text;
						break;
					case '\0':
						return Glob_Result::SYNTAX_ERROR; // unclosed [
					default:
					{
						matched |= prev <= *text && *text <= *pattern;
						prev = *pattern;
						pattern += 1;
					}
					}
				}
				break;
				default:
				{
					prev = *pattern;
					matched |= prev == *text;
					pattern += 1;
				}
				}
			}

			if (*pattern != ']')
				return Glob_Result::SYNTAX_ERROR; // unclosed [
			if (negate)
				matched = !matched;
			if (!matched)
				return Glob_Result::UNMATCHED;

			pattern += 1;
			text += 1;
		}
		break;

		case '\\':
			pattern += 1;
			if (*pattern == '\0')
				return Glob_Result::SYNTAX_ERROR; // unfinished escape
																					// fallthrough
		default:
		{
			if (*pattern == *text)
			{
				pattern += 1;
				text += 1;
			}
			else
			{
				return Glob_Result::UNMATCHED;
			}
		}
		}
	}

	if (*text == '\0')
	{
		while (*pattern == '*')
			pattern += 1;
		if (*pattern == '\0')
			return Glob_Result::MATCHED;
	}

	return Glob_Result::UNMATCHED;
}
#endif // GLOB_IMPLEMENTATION