/*
 * AutomatonFromStringLexer.cpp
 *
 *  Created on: Nov 23, 2013
 *      Author: Jan Travnicek
 */

#include "AutomatonFromStringLexer.h"
#include <exception/CommonException.h>
#include <alib/iterator>

namespace automaton {

AutomatonFromStringLexer::Token AutomatonFromStringLexer::next(std::istream& input) {
	AutomatonFromStringLexer::Token token;
	token.type = TokenType::ERROR;
	token.value = "";
	token.raw = "";
	char character;

L0:
	character = input.get();
	if ( input.eof ( ) || character == EOF ) { // for some reason the input stream was not setting eof bit for automata input without last newline
		token.type = TokenType::TEOF;
		return token;
	} else if(character == '\r' || character == '\n') {
		token.type = TokenType::NEW_LINE;
		token.value += character;
		token.raw += character;
		return token;
	} else if ( ext::isspace ( character ) ) {
		token.raw += character;
		goto L0;
	} else if(character == '<') {
		token.type = TokenType::OUT;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '>') {
		token.type = TokenType::IN;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '|') {
		token.type = TokenType::SEPARATOR;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '[') {
		token.type = TokenType::LEFT_BRACKET;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == ']') {
		token.type = TokenType::RIGHT_BRACKET;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '-') {
		token.type = TokenType::NONE;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == ',') {
		token.type = TokenType::COMMA;
		token.value += character;
		token.raw += character;
		return token;
	} else if(character == '#') {
		token.value += character;
		token.raw += character;
		goto L1;
	} else if ( ( character >= '0' ) && ( character <= '9' ) ) {
		token.type = TokenType::RANK;
		token.value += character;
		token.raw += character;
		goto L2;
	} else if(input.clear(), input.unget(), input >> ext::string ( "MISNFA" ) ) {
		token.type = TokenType::MULTI_INITIAL_STATE_NFA;
		token.value = "MISNFA";
		token.raw += "MISNFA";
		return token;
	} else if(input.clear(), input >> ext::string ( "MISENFA" ) ) {
		token.type = TokenType::MULTI_INITIAL_STATE_EPSILON_NFA;
		token.value = "MISENFA";
		token.raw += "MISENFA";
		return token;
	} else if(input.clear(), input >> ext::string ( "ENFA" ) ) {
		token.type = TokenType::EPSILON_NFA;
		token.value = "ENFA";
		token.raw += "ENFA";
		return token;
	} else if(input.clear(), input >> ext::string ( "NFA" ) ) {
		token.type = TokenType::NFA;
		token.value = "NFA";
		token.raw += "NFA";
		return token;
	} else if(input.clear(), input >> ext::string ( "DFA" ) ) {
		token.type = TokenType::DFA;
		token.value = "DFA";
		token.raw += "DFA";
		return token;
	} else if(input.clear(), input >> ext::string ( "DFTA" ) ) {
		token.type = TokenType::DFTA;
		token.value = "DFTA";
		token.raw += "DFTA";
		return token;
	} else if(input.clear(), input >> ext::string ( "NFTA" ) ) {
		token.type = TokenType::NFTA;
		token.value = "NFTA";
		token.raw += "NFTA";
		return token;
	} else {
		putback(input, token);
		token.raw = "";
		token.type = TokenType::ERROR;
		return token;
	}
L1:
	character = input.get();
	if(input.eof()) {
		token.type = TokenType::TEOF;
		return token;
	} else if(character == 'E') {
		token.type = TokenType::EPSILON;
		token.value += character;
		token.raw += character;
		return token;
	} else {
		input.clear ( );
		input.unget ( );
		putback(input, token);
		token.raw = "";
		token.type = TokenType::ERROR;
		return token;
	}

L2:
	character = input.get ( );
	if ( input.eof ( ) ) {
		return token;
	} else if ( ( character >= '0' ) && ( character <= '9' ) ) {
		token.value += character;
		token.raw += character;
		goto L2;
	} else {
		input.clear ( );
		input.unget ( );
		return token;
	}

}

} /* namespace automaton */
