/*************************************************/
/*  regex.cpp                                    */
/*************************************************/
/*            This file is part of:              */
/*                GODOT ENGINE                   */
/*************************************************/
/*       Source code within this file is:        */
/*  (c) 2007-2010 Juan Linietsky, Ariel Manzur   */
/*             All Rights Reserved.              */
/*************************************************/

#include "regex.h"

extern "C" {

#define _UNICODE
#include "trex.h"

};

void RegEx::_bind_methods() {

	ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile);
	ObjectTypeDB::bind_method(_MD("find","text", "start","end"),&RegEx::_bind_find, DEFVAL(0), DEFVAL(-1));
	ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures);
};

Error RegEx::compile(const String& p_pattern) {

	clear();
	const TRexChar* error;
	exp = trex_compile(p_pattern.c_str(), &error);
	ERR_FAIL_COND_V(!exp, FAILED);
	return OK;
};


int RegEx::_bind_find(const String& p_text, int p_start, int p_end) const {

	int start, end;
	bool ret = find(p_text, start, end, NULL, p_start, p_end);

	return ret?start:-1;
};

bool RegEx::find(const String& p_text, int& p_rstart, int &p_rend, List<String>* p_captures, int p_start, int p_end) const {

	ERR_FAIL_COND_V( !exp, false );
	text=p_text;

	const CharType* str = p_text.c_str();
	const CharType* start = str + p_start;
	const CharType* end = str + (p_end == -1?p_text.size():p_end);

	const CharType* out_begin;
	const CharType* out_end;

	bool ret = trex_searchrange(exp, start, end, &out_begin, &out_end);
	if (ret) {

		p_rstart = out_begin - str;
		p_rend = out_end - str;

		if (p_captures) {

			int count = get_capture_count();
			for (int i=0; i<count; i++) {

				int start, len;
				get_capture_limits(i, start, len);
				p_captures->push_back(p_text.substr(start, len));
			};
		};
	} else {

		p_rstart = -1;
	};

	return ret;
};


bool RegEx::match(const String& p_text, List<String>* p_captures, int p_start, int p_end) const {

	ERR_FAIL_COND_V( !exp, false );

	int start, end;
	return find(p_text, start, end, p_captures, p_start, p_end);
};

int RegEx::get_capture_count() const {

	ERR_FAIL_COND_V( exp == NULL, -1 );

	return trex_getsubexpcount(exp);
};

Error RegEx::get_capture_limits(int p_capture, int& p_start, int& p_len) const {

	ERR_FAIL_COND_V( exp == NULL, ERR_UNCONFIGURED );

	TRexMatch match;
	TRexBool res = trex_getsubexp(exp, p_capture, &match);
	ERR_FAIL_COND_V( !res, FAILED );
	p_start = (int)(match.begin - text.c_str());
	p_len = match.len;

	return OK;
};

String RegEx::get_capture(int p_idx) const {

	ERR_FAIL_COND_V( exp == NULL, "" );
	int start, len;
	Error ret = get_capture_limits(p_idx, start, len);
	ERR_FAIL_COND_V(ret != OK, "");
	if (len == 0)
		return "";
	return text.substr(start, len);
};

StringArray RegEx::_bind_get_captures() const {

	StringArray ret;
	int count = get_capture_count();
	for (int i=0; i<count; i++) {

		String c = get_capture(i);
		ret.push_back(c);
	};

	return ret;
};

bool RegEx::is_valid() const {

	return exp != NULL;
};

void RegEx::clear() {

	if (exp) {

		trex_free(exp);
		exp = NULL;
	};
};

RegEx::RegEx(const String& p_pattern) {

	exp = NULL;
	compile(p_pattern);
};

RegEx::RegEx() {

	exp = NULL;
};

RegEx::~RegEx() {

	clear();
};