#include "externals.hh"
#include "demo.hh"
#include "sync.hh"
#include "rendertarget.hh"
#include "globals.hh"
#include "ops.hh"
#include "opcomp.hh"
#include <ebcl/Files.hh>
#include <ebcl/SRDText.hh>

#warning remove this later
#include "syncoverrides.hh"


bool T_Demo::initialise(
		const uint32_t w ,
		const uint32_t h )
{
	width = w;
	height = h;
	return program && runInit( *program );
}

void T_Demo::render( )
{
	if ( Globals::Ops( ).hasNewProgram( ) ) {
		auto nProgram{ Globals::Ops( ).program( ) };
		if ( runInit( *nProgram ) ) {
			program = std::move( nProgram );
		}
	}

	auto& sync( Globals::Sync( ) );
	if ( playing ) {
		const float time = SDL_GetTicks( ) * 1e-3;
		if ( playingPrevious ) {
			sync.timeDelta( time - lastFrame );
			playing = !sync.finished( );
		}
		lastFrame = time;
	}
	playingPrevious = playing;

	if ( context && !context->aborted ) {
		try {
			context->run(  ops::T_OpContext::R_RENDER , sync.time( ) , width , height );
		} catch ( ops::X_OpFailure const& fail ) {
			printf( "FAILED TO RUN FRAME!\n\t%s\n" , fail.what( ) );
			context->aborted = true;
		}
	}
}

void T_Demo::handleDND(
		ImVec2 const& move ,
		const bool hasCtrl ,
		const bool hasShift ,
		const bool lmb		// Left mouse button
	)
{
}

void T_Demo::handleWheel(
		const float wheel ,
		const bool hasCtrl ,
		const bool hasShift
	)
{
}


bool T_Demo::runInit(
		ops::T_OpProgram& p )
{
	auto nContext{ NewOwned< ops::T_OpContext >( p ) };
	try {
		nContext->run( ops::T_OpContext::R_INIT , 0 , width , height );
	} catch ( ops::X_OpFailure const& fail ) {
		printf( "FAILED TO RUN INIT!\n\t%s\n" , fail.what( ) );
		nContext.clear( );
	}
	if ( !nContext ) {
		return false;
	}
	context = std::move( nContext );

	Globals::Sync( ).clearInputs( );
	const auto n( context->initialInputs.size( ) );
	assert( n == p.inputs.size( ) );
	for ( auto i = 0u ; i < n ; i ++ ) {
		Globals::Sync( ).addInput( p.inputs[ i ] ,
				context->initialInputs[ i ] );
#ifdef INVASIVE_TRACES
		printf( "#%d %s pos %d\n" , i , p.inputs[ i ].toOSString( ).data( ) ,
				Globals::Sync( ).inputPos( p.inputs[ i ] ) );
#endif //INVASIVE_TRACES
	}
	Globals::Sync( ).updateCurveCaches( );

#warning silly test here
	T_OwnPtr< sov::T_Float > ov{ NewOwned< sov::T_Float >(
			"dof-sharp-distance" , "Sharp distance" ) };
	ov->setMin( 0 );
	ov->setMax( 1000 );
	ov->setStep( .1 );
//	ov->setSlider( true );
	ov->setup( );

	T_SyncOverrideSection sos( "" );
	sos.subsections.add( NewOwned< T_SyncOverrideSection >( "Testing" ) );
	sos.subsections[ 0 ]->subsections.add( NewOwned< T_SyncOverrideSection >( "Yeah really" ) );
	sos.subsections[ 0 ]->subsections[ 0 ]->overrides.add( std::move( ov ) );

	auto ov2{ NewOwned< sov::T_Float4 >(
			"bloom-bw0" , "bloom-bw1" , "bloom-bw2" , "bloom-bw3" ,
			"Blur weights" ) };
	ov2->setMax( 1 );
	ov2->setSlider( );
	ov2->setup( );
	sos.subsections[ 0 ]->overrides.add( std::move( ov2 ) );

	Globals::Sync( ).mergeOverrides( sos );

	return true;
}