#include "CharSequence.h"

#include <algorithm>
#include <numeric>

#include <alib/string>

namespace cli {

void CharSequence::fetch ( bool readNextLine ) {
	if ( ! readNextLine )
		return;

	std::string line;
	for ( std::string tmpLine; m_lineInterface->readline ( tmpLine, linePtr == nullptr ); ) {
		if ( std::all_of ( tmpLine.begin ( ), tmpLine.end ( ), ext::isspace ) ) {
			line += tmpLine;
			line += '\n';
			continue;
		}

		if ( ! tmpLine.empty ( ) && tmpLine.back ( ) == '\\' ) {
			tmpLine.back ( ) = '\n';
			line += tmpLine;
		} else {
			line += tmpLine;
			line += '\n';
			break;
		}
	}

	if ( std::all_of ( line.begin ( ), line.end ( ), ext::isspace ) )
		return;

	m_lines.push_back ( std::move ( line ) );

	this->linePtr = m_lines.back ( ).c_str ( );
}

int CharSequence::getCharacter ( ) const {
	if ( ! putbackBuffer.empty ( ) )
		return ( int ) putbackBuffer.back ( );
	else if ( linePtr == nullptr )
		return EOF;
	else
		return ( int ) * linePtr;
}

void CharSequence::advance ( bool readNextLine ) {
	if ( getCharacter ( ) == '\n' ) {
		++ m_line;
		m_position = 0;
	} else if ( getCharacter ( ) != EOF ) {
		++ m_position;
	}

	if ( ! putbackBuffer.empty ( ) ) {
		putbackBuffer.pop_back ( );
	} else if ( linePtr == nullptr ) {
			fetch ( readNextLine );
	} else {
		if ( * linePtr != '\0' )
			++ linePtr;
		if ( * linePtr == '\0' )
			fetch ( readNextLine );
	}
}

std::string CharSequence::getData ( ) const {
	return std::accumulate ( m_lines.begin ( ), m_lines.end ( ), std::string () );
}

} /* namespace cli */
