#include <lw/lib/BuiltinLoggers.hh>
using namespace lw;


namespace {

char const* const V_Name_ = "console";
inline T_String Name_( ) { return T_String::Pooled( V_Name_ ); }

}


/*= T_ConsoleLogWriterFactory ================================================*/

T_ConsoleLogWriterFactory::T_ConsoleLogWriterFactory( T_Console& console )
	: A_LogWriterFactory( Name_( ) ) , console_( console )
{ }

RP_LogWriterConfiguration T_ConsoleLogWriterFactory::createConfiguration( T_String const& name ) const
{
	RP_LogWriterConfiguration p( new T_LogWriterConfiguration( Name_( ) ) );
	p->setName( name );
	return p;
}

OP_LogWriter T_ConsoleLogWriterFactory::createLogWriter( OP_LogWriterConfiguration&& configuration ) const
{
	T_ConsoleLogWriter* p( new T_ConsoleLogWriter( std::move( configuration ) , console_ ) );
	return OwnRawPointer( p );
}


/*= T_ConsoleLogWriter =======================================================*/

T_ConsoleLogWriter::T_ConsoleLogWriter( OP_LogWriterConfiguration&& configuration , T_Console& console )
	: A_LogWriter( std::move( configuration ) ) , console_( console )
{ }

void T_ConsoleLogWriter::log( T_LogTimestamp const& timestamp ,
		E_LogLevel level , T_LogPath const& path ,
		T_LogStringData const& data , uint32_t size )
{
	using namespace std::chrono;

	char timeBuffer[ 128 ];
	std::time_t tst( T_LogTimestamp::clock::to_time_t( timestamp ) );
	std::strftime( timeBuffer , 128 , "%Y-%m-%d %H:%M:%S" , std::gmtime( &tst ) );
	const auto ms( ( duration_cast< milliseconds >( timestamp - T_LogTimestamp( ) ) ).count( ) % 1000 );

	T_TextBuilder sb;

	sb << timeBuffer << '.';
	if ( ms < 100 ) {
		sb << '0';
		if ( ms < 10 ) {
			sb << '0';
		}
	}
	sb << ms << ' ' << path.toString( ) << " - "
		<< E_TextStyle::UNDERLINE;
	switch ( level ) {
	    case E_LogLevel::TRACE:
	    case E_LogLevel::DEBUG:
	    case E_LogLevel::INFO:
		sb << E_TextColor::CYAN;
		break;
	    case E_LogLevel::NOTICE:
		break;
	    case E_LogLevel::WARNING:
		sb << E_TextColor::YELLOW;
		break;
	    case E_LogLevel::CRITICAL:
		sb << E_TextStyle::BOLD;
	    case E_LogLevel::ERROR:
		sb << E_TextColor::RED;
		break;
	}
	sb << level;
	sb.reset( );
	sb << " - " << T_String( &( (*data) [ 0 ] ) , size );

	console_.putLine( std::move( sb ) );
}