/*
   Copyright (C) 2004 by James Gregory
   Part of the GalaxyHack project
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.
 
   See the COPYING file for more details.
*/

#include "BCCompiler.h"
#include "Globals.h"

ustring BCCompiler::ConvertToBC(const string& theLine) {
	string::const_iterator lIter = theLine.begin();
	string::const_iterator lEnd =  theLine.end();
	
	string::const_iterator lIterc = lIter;
	if (!FindNotComment(lIterc, lEnd))
		return ustring(1, TT_Comment);
		
	ustring bc;

	while (*lIter == '\t') {
		bc.push_back(TT_Tab);
		++lIter;
	}

	if (std::isspace(*lIter))
		throw runtime_error("Indentation should not include spaces, only tabs");

	if (theLine.find(':') != string::npos || theLine.find('@') != string::npos) {
		while (lIter != lEnd && NotSpace(*lIter) && *lIter != '#') {
			bc += *lIter;
			++lIter;
		}
		return bc;
	}
	
	while (lIter != lEnd) {
		if (std::isspace(*lIter)) {
			++lIter;
			continue;
		}

		const unsigned char tmpToken = WhatIsThisToken(lIter, lEnd);
		switch (tmpToken) {
		case TT_Integer:
			bc.push_back(TT_Integer);
			for (int i = 0; lIter != lEnd && isdigit(static_cast<int>(*lIter)); ++i) {
				if (i == maxScriptDigits)
					throw runtime_error("Scripts only support numbers of up to 6 digits");
				bc.push_back(*lIter);
				++lIter;
			}
			break;
			
		case TT_ScriptVar:
		case TT_SaveGroup:
		case TT_ScriptTimer:
		case TT_GScriptVar:
		case TT_GSaveGroup: {
			bc.push_back(tmpToken);
			int i = 0;
			for (; lIter != lEnd && isdigit(static_cast<int>(*lIter)); ++i) {
				if (i == nAIVars)
					throw runtime_error("Scripts only allow variables 0 - 9 of each type");
				bc.push_back(*lIter);
				++lIter;
			}
			if (i == 0)
				throw runtime_error("Script variables must have a number from 0 to 9");
		}
			break;
			
		//comment on end of line
		case TT_Comment:
			return bc;
			break;

		default:
			bc.push_back(tmpToken);
			break;
		}
	}
	
	return bc;
}

//You have to give this an iter on the first letter of the command
//it leaves the iter one past the end
const unsigned char BCCompiler::WhatIsThisToken(string::const_iterator& lIter, const string::const_iterator& lEnd) {
	//if an integer, return as such and leave iterator where it is
	if (isdigit(*lIter))
		return TT_Integer;

	//some tokens could be the first few letters of another token, so we start off with the whole string and gradually eat away at the end until it is recognisable as a token
	string tokenStr(lIter, lEnd);
	while (tokenStr.size()) {
		if (tokenLookup.find(tokenStr) != tokenLookup.end()) {
			lIter += tokenStr.size();
			return tokenLookup[tokenStr];
		}
		tokenStr = tokenStr.substr(0, tokenStr.size() - 1);
	}

	throw runtime_error("Unrecognised token");
}

