#include "stdafx.h"

#include "StringExpander.hpp"

#include <vector>
#include <sstream>
#include <memory>


/*
	テストパターン
	PropertyStringExpander expander;
	expander.addProperty( "ABC", "123" );
	
	assert( expander.expandString( "" ) == "" );
	assert( expander.expandString( "123 456" ) == "123 456" );
	assert( expander.expandString( "%ABC%" ) == "123" );
	assert( expander.expandString( "%abc%" ) == "123" );
	assert( expander.expandString( "%DEF%" ) == "%DEF%" );
	assert( expander.expandString( "%%ABC%%" ) == "%123%" );
	assert( expander.expandString( "%%DEF%%" ) == "%%DEF%%" );
	assert( expander.expandString( "%ABC%%%DEF%%" ) == "123%%DEF%%" );
	assert( expander.expandString( "%ABC%% %DEF%%" ) == "123% %DEF%%" );
	assert( expander.expandString( "%ABC%% %DEF%% " ) == "123% %DEF%% " );

	assert( expander.expandString( "%1 %2 %* -path=\"%ABC%\"" ) == "%1 %2 %* -path=\"123\"" );
*/

StringExpander::StringExpander()
	: unresolveEmpty_( false )
{
}

tstring StringExpander::expandString( const tstring& v_template ) const throw()
{
	tstring result;
	tstring variableName;

	enum {
		NORMAL = 0,
		VARIABLE = 1
	} state = NORMAL;

	const int mx = v_template.length();
	int idx = 0;
	int back = 0;
	for (;;) {
		const tstring::value_type ch = (idx >= mx) ? 0 : v_template[idx++];
		if (state == NORMAL) {
			if (ch == '%') {
				back = idx;
				state = VARIABLE;
				variableName.clear();
			}
			else if (ch != 0) {
				result += ch;
			}
			else {
				break;
			}
		}
		else if (state == VARIABLE) {
			if (ch <= ' ' || ( ch == '%' && variableName.empty())) {
				result += '%';
				idx = back;
				state = NORMAL;
			}
			else if (ch == '%') {
				bool resolved = false;
				const tstring value = resolveParameter(variableName, &resolved);
				if (resolved) {
					result += value;
				}
				else if ( !unresolveEmpty_) {
					result += '%';
					result += variableName;
					result += '%';
				}
				state = NORMAL;
			}
			else {
				variableName += ch;
			}
		}
	}

	return result;
}

void StringExpander::setUnresolveEmpty(const bool v_mode)
{
	unresolveEmpty_ = v_mode;
}

////////////////

PropertyStringExpander::PropertyStringExpander() throw()
{
}

PropertyStringExpander::PropertyStringExpander(const PropertyStringExpander& v_other) throw()
	: propertyMap_(v_other.propertyMap_)
{
}

PropertyStringExpander& PropertyStringExpander::operator=(const PropertyStringExpander& v_other) throw()
{
	if (this != &v_other) {
		propertyMap_ = v_other.propertyMap_;
	}
	return *this;
}

PropertyStringExpander::~PropertyStringExpander() throw()
{
}

tstring PropertyStringExpander::getKeyName(const tstring& v_name) const throw()
{
	int bufsiz = v_name.length() + 1;
	std::vector<tstring::value_type> buf(bufsiz);
	_tcscpy_s(&buf[0], bufsiz, v_name.c_str());
	::CharUpper(&buf[0]);
	return tstring(&buf[0]);
}

void PropertyStringExpander::addProperty(const tstring& v_name, const tstring& v_value ) throw()
{
	propertyMap_[getKeyName(v_name)] = v_value; // 上書き許可
}

tstring PropertyStringExpander::resolveParameter(const tstring& v_name, bool* v_pResolved) const throw()
{
	tstring result;
	bool bFound = false;

	const tstring keyName(getKeyName(v_name));
	PropertyMap::const_iterator ite = propertyMap_.find(keyName);
	if (ite != propertyMap_.end()) {
		bFound = true;
		result = ite->second;
	}
	else {
		const DWORD strsize = ::GetEnvironmentVariable(keyName.c_str(), NULL, 0);
		if (strsize != 0) {
			std::vector<tstring::value_type> buf(strsize);
			::GetEnvironmentVariable(v_name.c_str(), &buf[0], strsize);
			result = tstring(&buf[0]);
			bFound = true;
		}
	}

	if (v_pResolved != NULL) {
		*v_pResolved = bFound;
	}
	return result;
}

