#include "glob.h"

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;
}