#include "externals.hh"
#include "ui-dialogs.hh"
#include "ui-utilities.hh"

#include <imgui_internal.h>


/*= A_ModalDialog ============================================================*/

A_ModalDialog::A_ModalDialog(
		char const* const id ) noexcept
	: id_{ id , uint32_t( strlen( id ) + 1 ) }
{}

A_ModalDialog::A_ModalDialog(
		T_String const& id ) noexcept
{
	if ( id && id[ id.length( ) - 1 ] == 0 ) {
		id_ = ebcl::T_Buffer< char >{ id.data( ) , id.size( ) };
	} else {
		id_ = id.toOSString( );
	}
}

A_ModalDialog::~A_ModalDialog( )
{ }

uint8_t A_ModalDialog::addButton(
		char const* name ) noexcept
{
	buttons_.addNew( name , strlen( name ) + 1 );
	return buttons_.size( ) - 1;
}

uint8_t A_ModalDialog::addButton(
		T_String const& name ) noexcept
{
	if ( name && name[ name.length( ) - 1 ] == 0 ) {
		buttons_.addNew( name.data( ) , name.size( ) );
	} else {
		buttons_.add( name.toOSString( ) );
	}
	return buttons_.size( );
}

void A_ModalDialog::initDialog( ) noexcept
{}

bool A_ModalDialog::draw( ) noexcept
{
	using namespace ImGui;
	if ( !open_ ) {
		assert( buttons_.size( ) );
		OpenPopup( &id_[ 0 ] );
		open_ = true;
	}

	initDialog( );
	if ( initialSize_ ) {
		SetNextWindowSize( *initialSize_ , ImGuiCond_Appearing );
	}

	BeginPopupModal( &id_[ 0 ] , nullptr , ImGuiWindowFlags_NoResize );
	const auto btMask{ drawDialog( ) };
	assert( btMask != 0 );

	const ImVec2 ws( GetWindowContentRegionMax( ) );
	auto const& style( GetStyle( ) );
	const float innerWidth{ ws.x - 2 * style.FramePadding.x };
	const auto nButtons{ buttons_.size( ) };
	const ImVec2 buttonSize{
		std::max( 40.f , ( innerWidth - nButtons * style.FramePadding.x ) / nButtons ) ,
		0.f
	};

	int32_t clicked{ -1 };
	for ( auto i = 0u ; i < buttons_.size( ) ; i ++ ) {
		const auto m{ 1 << i };
		const bool d{ ( btMask & m ) == 0 };
		if ( i ) {
			SameLine( 0 );
		}
		if ( d ) {
			PushDisabled( );
		}
		if ( Button( &buttons_[ i ][ 0 ] , buttonSize ) ) {
			assert( clicked == -1 );
			clicked = i;
		}
		if ( d ) {
			PopDisabled( );
		}
	}
	const bool close( clicked != -1 && onButton( clicked ) );
	if ( close ) {
		CloseCurrentPopup( );
	}
	EndPopup( );
	return !close;
}


/*= T_MessageBox =============================================================*/

void T_MessageBox::setButtons(
		const T_Buttons buttons ) noexcept
{
	assert( buttons );
	for ( auto i = 0u , nb = 0u ; i < 4 ; i ++ ) {
		const E_Button b{ (E_Button) i };
		const bool hasButton{ buttons & T_Buttons{ b } };
		if ( !hasButton ) {
			continue;
		}
		buttonMask_ |= ( 1 << nb );
		nb ++;
		buttons_.add( b );
		switch ( b ) {
		    case BT_OK: addButton( "OK" ); break;
		    case BT_CANCEL: addButton( "Cancel" ); break;
		    case BT_YES: addButton( "Yes" ); break;
		    case BT_NO: addButton( "No" ); break;
		}
	}
}

T_MessageBox::T_MessageBox(
		char const* const title ,
		char const* const text ,
		F_Handler handler ,
		const T_Buttons buttons ) noexcept
	: A_ModalDialog( title ) , text_{ text , strlen( text ) + 1 } ,
		handler_{ std::move( handler ) }
{
	setButtons( buttons );
	setInitialSize( 300.f , 100.f );
}

T_MessageBox::T_MessageBox(
		T_String const& title ,
		T_String const& text ,
		F_Handler handler ,
		const T_Buttons buttons ) noexcept
	: A_ModalDialog( title ) , handler_{ std::move( handler ) }
{
	if ( text && text[ text.length( ) - 1 ] == 0 ) {
		text_ = ebcl::T_Buffer< char >{ text.data( ) , text.size( ) };
	} else {
		text_ = text.toOSString( );
	}
	setButtons( buttons );
	setInitialSize( 300.f , 100.f );
}

uint8_t T_MessageBox::drawDialog( ) noexcept
{
	ImGui::TextWrapped( "%s" , &text_[ 0 ] );
	return buttonMask_;
}

bool T_MessageBox::onButton(
		uint8_t button ) noexcept
{
	assert( button < buttons_.size( ) );
	if ( handler_ ) {
		handler_( buttons_[ button ] );
	}
	return true;
}