/*
 * (C) Copyright 1996-2017 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */


#include "eckit/io/Buffer.h"
#include "eckit/exception/Exceptions.h"
#include "eckit/utils/Regex.h"


//-----------------------------------------------------------------------------

namespace eckit {

//-----------------------------------------------------------------------------

Regex::Regex(const std::string& s,bool shell, bool extended):
	str_(s),
	extended_(extended)
{
	//Log::debug() << "Regex " << str_ << std::endl;
	if(shell) {
		long len = s.length()*3 + 1;
		Buffer buffer(len);
		char *re = buffer;

        std::string::size_type i = 0;
		int j = 0;

        if(shell) { re[j++] = '^'; }

		while(i < s.length())
		{
			switch(s[i])
			{
			case '?':
				re[j++] = '.';
				break;

			case '*':
				re[j++] = '.';
				re[j++] = '*';
				break;

			case '.':
				re[j++] = '\\';
				re[j++] = '.';
				break;

			case '[':
				re[j++] = '['; i++;
				while(i < s.length() && s[i] != ']')
					re[j++] = s[i++];
				re[j++] = ']';
				break;

			default:
				re[j++] = s[i];
				break;
			}
			i++;
			ASSERT(j < len);
		}
        if(shell) { re[j++] = '$'; }
		re[j] = 0;
		str_ = re;
	}
	//Log::debug() << "Regex " << str_ << std::endl;
	compile(str_.c_str());
}

Regex::~Regex()
{
	regfree(&re_);
}

void Regex::print(std::ostream& s) const
{
    s << "/" << str_ << "/";
}

bool Regex::match(const std::string& s) const
{
	regmatch_t pm;
	//Log::debug() << "Match " << s << " with " << str_ << " -> " << (regexec(&re_,s.c_str(),1,&pm,0) == 0) << std::endl;
	return regexec(&re_,s.c_str(),1,&pm,0) == 0;
}

void Regex::compile(const char* p)
{
	int n = regcomp(&re_, p, extended_ ? REG_EXTENDED : 0);
	if(n)
	{
		char buf[1024];
		regerror(n,&re_,buf,sizeof(buf));
		throw SeriousBug(buf);
	}
}

Regex::Regex(const Regex& other):
	str_(other.str_),
	extended_(other.extended_)
{
	compile(str_.c_str());
}

Regex& Regex::operator=(const Regex& other)
{
	regfree(&re_);
	str_ = other.str_;
	extended_ = other.extended_;
	compile(str_.c_str());
	return *this;
}

//-----------------------------------------------------------------------------

} // namespace eckit

