#pragma once
#include "../includes.h"

//Bad and likely buggy regex class that's just hackish enough to work.
//Doesn't actually support the full range of what it should, but should
//work well enough to do what I want, and be faster than a real
//implementation, too.

//Uses snazzy-looking recursion, therefore it must be acceptable.

class Regex;
struct PatternData {
	Regex* regex;
	string* pattern;
	//Only significant for regexes.  If 1, then must match all of the expressions in the regex, in order.  If 2, must match only one.
	char type;
	int min_count;
	int max_count;

	PatternData(Regex* new_regex);
	PatternData(string new_pattern);
	~PatternData();
};
typedef vector<PatternData*> type_subpattern_array;
class Regex {
	private:
		type_subpattern_array* _subpatterns;

	private:
		void add_pattern(string* expr, int min_count, int max_count) {
			if (expr->length()==0) return;
			_subpatterns->push_back(new PatternData(*expr));
			*expr = "";
		}
		
		void parse_regex(string* regex,  string::const_iterator* iter) {
			string next;
			char c0 = '\0';
			for ( ; *iter!=regex->end(); ++(*iter) ) {
				char c1 = **iter;
				if      (c1=='\0') {
					break;
				}
				else if (c1=='('&&c0!='\\') {
					add_pattern(&next,1,1);

					++(*iter);
					PatternData* new_data = new PatternData(new Regex(regex,iter));
					new_data->min_count = 1;
					new_data->max_count = 1;
					_subpatterns->push_back(new_data);
				}
				else if (c1=='|'&&c0!='\\') {
					add_pattern(&next,1,1);
				}
				else if ((c1=='+'||c1=='*')&&c0!='\\') {
					add_pattern(&next,1,1);
					_subpatterns->back()->min_count = (c1=='+')?1:0;
					_subpatterns->back()->max_count = -1;
				}
				else if (c1=='['&&c0!='\\') {
					add_pattern(&next,1,1);

					++(*iter);
					PatternData* new_data = new PatternData(new Regex(regex,iter));
					new_data->min_count = 1;
					new_data->max_count = 1;
					_subpatterns->push_back(new_data);
				}
				else if ((c1=='}'||c1==']'||c1==')')&&c0!='\\') {
					break;
				}
				else if (c1!='\\') {
					next += c1;
				}
				c0 = c1;
			}
			add_pattern(&next,1,1);
		}
	public:
		Regex(string* regex, string::iterator* iter=NULL) {
			_subpatterns = new type_subpattern_array();

			if (iter==NULL) {
				iter = &regex->begin(); //make the iterator point to something
				*iter = regex->begin(); //now can dereference it
			}
			parse_regex(regex,iter);
		}
		~Regex() {
			for (type_subpattern_array::iterator iter=_subpatterns->begin(); iter!=_subpatterns->end(); ++iter) {
				delete *iter;
			}
			delete _subpatterns;
		}

		bool find_in(const char* str, int* loc_start1, int* loc_end1) {
			return search(this,str,loc_start1,loc_end1);
		}
	private:
		bool search(Regex* regex, const char* str, int* loc_start1, int* loc_end1) {
			char c; int i = 0;
			while (c=str[i]) {
				bool found = false;

				int loc_start2 = *loc_start1;
				for (
					type_subpattern_array::const_iterator iter=regex->_subpatterns->begin();
					iter!=regex->_subpatterns->end();
					++iter
				) {
					PatternData* pd = *iter;

					if (pd->regex!=NULL) {
						printf("====PUSH====\n");
						found = search(pd->regex,str+i,&loc_start2,loc_end1);
						printf("====POP====\n");
						if (!found) break;
					}
					else {
						const char* pat_str = pd->pattern->c_str();
						printf("Am comparing strings:\n    \"%s\"\n    \"%s\"\n",pat_str,str+i);

						bool same = true;
						int j = 0;
						while (true) {
							if (pat_str[j]=='\0') break;
							if ((str+i)[j]=='\0') break;
							if (pat_str[j]!=(str+i)[j]) { same = false; break; }
							++j;
						}

						if (!same) {
							printf("  Didn't find it!\n\n");
						}
						else {
							printf("  Found it!\n\n");
							loc_start2 += strlen(pat_str)-1;
							found = true;
							break;
						}
					}
				}
				if (found) {
					*loc_end1 = loc_start2+1;
					return true;
				}

				++(*loc_start1);
				++i;
			}
			return false;
		}
};