#include <environment/Environment.h>

#include <lexer/Lexer.h>
#include <parser/Parser.h>

#include <alib/exception>

#include <global/GlobalData.h>

namespace cli {

std::shared_ptr < abstraction::Value > Environment::getVariableInt ( const std::string & name ) const {
	std::reference_wrapper < const Environment > env = * this;
	while ( true ) {
		auto res = env.get ( ).m_variables.find ( name );

		if ( res != env.get ( ).m_variables.end ( ) )
			return res->second;

		if ( ! env.get ( ).m_upper )
			break;

		env = * env.get ( ).m_upper;
	}
	throw exception::CommonException ( "Variable of name " + name + " not found." );
}

std::string Environment::getBinding ( const std::string & name ) const {
	std::reference_wrapper < const Environment > env = * this;
	while ( true ) {
		auto res = m_bindings.find ( name );

		if ( res != m_bindings.end ( ) )
			return res->second;

		if ( ! env.get ( ).m_upper )
			break;

		env = * env.get ( ).m_upper;
	}
	throw exception::CommonException ( "Binded value of name " + name + " not found." );
}

cli::CommandResult Environment::execute ( std::shared_ptr < cli::LineInterface > lineInterface ) {
	cli::CommandResult state = cli::CommandResult::OK;

	while ( state == cli::CommandResult::OK || state == cli::CommandResult::ERROR )
		state = execute_line ( cli::CharSequence ( lineInterface ) );

	return state;
}

cli::CommandResult Environment::execute_line ( cli::CharSequence charSequence ) {
	try {
		cli::Parser parser = cli::Parser ( cli::Lexer ( std::move ( charSequence ) ) );
		std::unique_ptr < CommandList > command = parser.parse ( );
		cli::CommandResult res = command->run ( * this );

		if ( res == CommandResult::CONTINUE || res == CommandResult::BREAK )
			throw std::logic_error ( "There is no loop to continue/break." );

		return res;
	} catch ( ... ) {
		alib::ExceptionHandler::handle ( common::Streams::err );
		return cli::CommandResult::EXCEPTION;
	}
}

Environment & Environment::getGlobalScope ( ) {
	if ( ! ( bool ) m_upper )
		return * this;
	return getGlobalScope ( );
}

} /* namespace cli */
