#include "stdafx.h"
#include "winuser.h"
#include "Logger.h"
#include <vcclr.h>

namespace Mix{ namespace Tool{

////////////////////////////////////////////////////////////////////////////////////////////////////
// グローバル変数
////////////////////////////////////////////////////////////////////////////////////////////////////

static HWND g_hLoggerWnd = NULL;
static unsigned int g_LoggerWndThreadID = 0;
static WNDPROC g_LoggerDefWndProc = NULL;

static int g_LoggerMsg = 0x1234;

static gcroot<System::Collections::Queue^> g_LoggerQueue = nullptr;

static gcroot<Mix::Tool::Logger::DelegateProcClear^> g_LoggerProcClear = nullptr;
static gcroot<Mix::Tool::Logger::DelegateProcPrint^> g_LoggerProcPrint = nullptr;

////////////////////////////////////////////////////////////////////////////////////////////////////
// ロガーイベントクラス
////////////////////////////////////////////////////////////////////////////////////////////////////

ref class LoggerEventArgs
{
public:
	Logger::Type type;
	System::String^ msg;

public:
	LoggerEventArgs( Logger::Type _type, System::String^ _msg )
	{
		type = _type;
		msg = _msg;
	}
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// ロガー
////////////////////////////////////////////////////////////////////////////////////////////////////

System::IntPtr Logger::Handle::get( void )
{
	System::IntPtr ret;

	if( g_hLoggerWnd != NULL )
	{
		ret = static_cast<System::IntPtr>( g_hLoggerWnd );
	}
	else
	{
		ret = System::IntPtr::Zero;
	}

	return ret;
}

void Logger::Handle::set( System::IntPtr value )
{
	if( value != System::IntPtr::Zero )
	{
		g_hLoggerWnd = reinterpret_cast<HWND&>( value );
		g_LoggerWndThreadID = ::GetWindowThreadProcessId( g_hLoggerWnd, NULL );

		if( static_cast<System::Collections::Queue^>( g_LoggerQueue ) == nullptr )
		{
			g_LoggerQueue = System::Collections::Queue::Synchronized( gcnew System::Collections::Queue() );
		}
	}
	else
	{
		g_hLoggerWnd = NULL;
		g_LoggerWndThreadID = 0;

		if( static_cast<System::Collections::Queue^>( g_LoggerQueue ) != nullptr )
		{
			delete g_LoggerQueue;
			g_LoggerQueue = nullptr;
		}
	}
}

int Logger::Msg::get( void )
{
	return g_LoggerMsg;
}

void Logger::Msg::set( int value )
{
	g_LoggerMsg = value;
}

void Logger::ProcClear::set( Mix::Tool::Logger::DelegateProcClear^ value )
{
	g_LoggerProcClear = value;
}

void Logger::ProcPrint::set( Mix::Tool::Logger::DelegateProcPrint^ value )
{
	g_LoggerProcPrint = value;
}

void Logger::Clear( void )
{
	if( g_LoggerWndThreadID == ::GetCurrentThreadId() )
	{
		if( static_cast<Mix::Tool::Logger::DelegateProcClear^>( g_LoggerProcClear ) != nullptr )
		{
			g_LoggerProcClear->Invoke();
		}
	}
	else
	{
		if( g_hLoggerWnd != NULL )
		{
			PostMessage( g_hLoggerWnd, ( WM_APP + g_LoggerMsg ), Logger::WPARAM_CLEAR, 0 );
		}
	}
}

void Logger::Print( Mix::Tool::Logger::Type type, System::String^ str )
{
	if( g_LoggerWndThreadID == ::GetCurrentThreadId() )
	{
		if( static_cast<Mix::Tool::Logger::DelegateProcPrint^>( g_LoggerProcPrint ) != nullptr )
		{
			g_LoggerProcPrint->Invoke( type, str );
		}
	}
	else
	{
		if( ( g_hLoggerWnd != NULL ) &&
			( static_cast<System::Collections::Queue^>( g_LoggerQueue ) != nullptr ) )
		{
			g_LoggerQueue->Enqueue( gcnew LoggerEventArgs( type, str ) );
			PostMessage( g_hLoggerWnd, ( WM_APP + g_LoggerMsg ), Logger::WPARAM_PRINT, 0 );
		}
	}
}

void Logger::WndProc( System::Windows::Forms::Message^ msg )
{
	if( msg->Msg == ( WM_APP + g_LoggerMsg ) )
	{
		switch( msg->WParam.ToInt32() )
		{
		case Logger::WPARAM_CLEAR:
			if( static_cast<Mix::Tool::Logger::DelegateProcClear^>( g_LoggerProcClear ) != nullptr )
			{
				g_LoggerProcClear->Invoke();
			}
			break;

		case Logger::WPARAM_PRINT:
			if( ( static_cast<System::Collections::Queue^>( g_LoggerQueue ) != nullptr ) &&
				( static_cast<Mix::Tool::Logger::DelegateProcPrint^>( g_LoggerProcPrint ) != nullptr ) )
			{
				LoggerEventArgs^ args = ( LoggerEventArgs^ )g_LoggerQueue->Dequeue();
				g_LoggerProcPrint->Invoke( args->type, args->msg );
			}
			break;
		}
	}
}

}}
