#include "mqsdx/MQCLI.hpp"
#include "MainForm.h"

#define MAKER_NAME "tiritomato"
#define PLUGIN_NAME "mqsdxTester           Copyright(C) 2013, tiritomato."
#define PLUGIN_STRING "mqsdxTester"

namespace mqsdxTester {

	public ref class MQxTesterDlg : MainForm {
	public:
		ref class Plugin : MQCLI::StationPlugin {
		public:
			Plugin():MQCLI::StationPlugin( MAKER_NAME, PLUGIN_NAME, PLUGIN_STRING, 0x200, 0x200 ), m_dlg( gcnew MQxTesterDlg() ) {
				m_dlg->m_ownerPlugin = this;
			}
			virtual BOOL Activate(MQDocument doc, BOOL flag) override {
				if ( m_dlg == nullptr ) return FALSE;
				return m_dlg->Activate(doc,flag);
			}
			virtual BOOL IsActivated(MQDocument doc) override {
				if ( m_dlg != nullptr ) return m_dlg->IsActivated();
				return FALSE;
			}
		private:
			MQxTesterDlg^ m_dlg;
		};

	private:
		MQDocument m_doc;
		Plugin^ m_ownerPlugin;
		bool m_isFirstActivate;
		MQxTesterDlg() {
			MainForm::FormBorderStyle = System::Windows::Forms::FormBorderStyle::SizableToolWindow;
			MainForm::FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this,&MQxTesterDlg::dlgFormClosing);
		}
		System::Void dlgFormClosing( System::Object^ object, System::Windows::Forms::FormClosingEventArgs^ e ) {
			if ( e->CloseReason == System::Windows::Forms::CloseReason::UserClosing ) {
				e->Cancel = true;
				Activate(m_doc, FALSE);
			}
		}
		void AddTextLine( System::String^ str ) { txtBox->AppendText (str + System::Environment::NewLine); }
		BOOL Activate(MQDocument doc, BOOL value) {
			m_doc = doc;
			if ( m_ownerPlugin == nullptr ) return FALSE;
			if ( value == FALSE ) {
				Form::Visible = false;
				m_ownerPlugin->WindowClose();
			}
			else if ( m_isFirstActivate ) {
				m_isFirstActivate = false;
				Show( gcnew MQCLI::MQWndHandle() );
			}
			else Form::Visible = true;
			
			if ( value != FALSE ) {
				if ( MessageBox::Show("mqsdxテストを実施しますか？","確認",System::Windows::Forms::MessageBoxButtons::OKCancel)
					== System::Windows::Forms::DialogResult::OK ) DoTest();
			}
			return value;
		}
		BOOL IsActivated() { if ( m_isFirstActivate ) return FALSE; return Form::Visible; }
		bool TestFailed(int line) {
			AddTextLine(System::String::Format("{0}行目:{1}", line, "予期せぬテスト結果が生じています。テストを中断します"));
			return false;
		}

		//test list
		bool DoTest() {
			txtBox->Clear();
			AddTextLine("boot test");
			AddTextLine("CurrentDirectory: " + System::IO::Directory::GetCurrentDirectory());

			const char* mat_names[] = {
				"matUVTransClone",
				"matUnique",
				"matUnique1",
				"matUnique2",
				"matTrailCountUp00",
				"matTrailCountUp02",
				"matTrailCountUp99",
				"matFloatNumber0.97",
				"matFloatNumber0.98",
				"matFloatNumber0.99"
			};
			const char* mat_clone_expect_names[] = {
				"matUVTransClone1",
				"matUnique3",
				"matUnique3",
				"matUnique3",
				"matTrailCountUp01",
				"matTrailCountUp03",
				"matTrailCountUp100",
				"matFloatNumber0.100",
				"matFloatNumber0.100",
				"matFloatNumber0.100"
			};
			AddTextLine("MQ0x::GetMaterialのNULLまたは未発見テスト");
			if ( MQ0x::GetMaterial( NULL, (const char*)NULL ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetMaterial( NULL, -1 ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetMaterial( m_doc, (const char*)NULL ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetMaterial( m_doc, -1 ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetMaterial( m_doc, "" ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetMaterial( m_doc, "mat99" ) != NULL ) return TestFailed(__LINE__);
			AddTextLine("MQ0x::GetMaterialの特定オブジェクト発見テスト");
			AddTextLine("このテストを正常に成功させるためには専用のmqoファイルがあらかじめロードされている必要があります");
			for ( int index = 0; index < sizeof(mat_names)/sizeof(mat_names[0]); index++ ) {
				MQMaterial mat = MQ0x::GetMaterial( m_doc, mat_names[index] );
				if ( mat == NULL ) {
					AddTextLine( System::String::Format( "名前が見つかりません。:{0}", gcnew System::String(mat_names[index]) ) );
					return TestFailed(__LINE__);
				}
				else if ( strcmp( mat_names[index], MQ0x::GetName( mat ).c_str() ) != 0 ) {
					return TestFailed(__LINE__);
				}
				UINT id = mat->GetUniqueID();
				MQMaterial mat_id = MQ0x::GetMaterial( m_doc, id );
				if ( mat_id == NULL ) {
					AddTextLine( System::String::Format( "IDで見つかりません。:{0}", gcnew System::String(mat_names[index]) ) );
					return TestFailed(__LINE__);
				}
				else if ( strcmp( mat_names[index], MQ0x::GetName( mat_id ).c_str() ) != 0 ) {
					AddTextLine( gcnew System::String(MQ0x::GetName( mat ).c_str()) );
					AddTextLine( gcnew System::String(MQ0x::GetName( mat_id ).c_str()) );
					AddTextLine( id.ToString() );
					return TestFailed(__LINE__);
				}
				std::string uniquename = MQ0x::GetCountUpCloneableUniqueName( m_doc, mat );
				if ( strcmp( mat_clone_expect_names[index], uniquename.c_str() ) != 0 ){
					AddTextLine("GetCountUpCloneableUniqueNameの不整合");
					AddTextLine( System::String::Format( "srcName:{0}", gcnew System::String(mat_names[index]) ) );
					AddTextLine( System::String::Format( "GetCountUpCloneableUniqueName():{0}", gcnew System::String(uniquename.c_str()) ) );
					AddTextLine( System::String::Format( "expected():{0}", gcnew System::String(mat_clone_expect_names[index]) ) );
					return TestFailed(__LINE__);
				}
				if ( MQ0x::GetMaterialTextureName( mat, MQMAPPING_TEXTURE ) != "" ) return TestFailed(__LINE__);
				if ( MQ0x::GetMaterialTextureName( mat, MQMAPPING_ALPHA ) != "" ) return TestFailed(__LINE__);
				if ( MQ0x::GetMaterialTextureName( mat, MQMAPPING_BUMP ) != "" ) return TestFailed(__LINE__);
			}
			AddTextLine("MQ0x::GetMaterialIndexの未発見テスト");
			if ( 0 <= MQ0x::GetMaterialIndex( NULL, (const char*)NULL ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetMaterialIndex( NULL, -1 ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetMaterialIndex( m_doc, (const char*)NULL ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetMaterialIndex( m_doc, -1 ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetMaterialIndex( m_doc, "" ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetMaterialIndex( m_doc, "mat99" ) ) return TestFailed(__LINE__);
			AddTextLine("MQ0x::GetMaterialIndexの特定オブジェクト発見テスト");
			AddTextLine("このテストを正常に成功させるためには専用のmqoファイルがあらかじめロードされている必要があります");
			for ( int index = 0; index < sizeof(mat_names)/sizeof(mat_names[0]); index++ ) {
				int mat_index = MQ0x::GetMaterialIndex( m_doc, mat_names[index] );
				MQMaterial mat = m_doc->GetMaterial(mat_index); // 有効チェック
				if ( mat == NULL ) {
					AddTextLine( System::String::Format( "名前が見つかりません。:{0}/{1}", mat_index, gcnew System::String(mat_names[index]) ) );
					return TestFailed(__LINE__);
				}
				UINT id = mat->GetUniqueID();
				int mat_id_index = MQ0x::GetMaterialIndex( m_doc, id );
				if ( mat_index != mat_id_index ) {
					AddTextLine( System::String::Format( "IDで見つかりません。:{0}", gcnew System::String(mat_names[index]) ) );
					return TestFailed(__LINE__);
				}
				if ( strcmp( mat_names[index], MQ0x::GetName( mat ).c_str() ) != 0 ) return TestFailed(__LINE__);
			}
			
			const char* obj_names[] = {
				"objUVTransClone",
				"objUnique",
				"objUnique1",
				"objUnique2",
				"objTrailCountUp00",
				"objTrailCountUp02",
				"objTrailCountUp99",
				"objFloatNumber0.97",
				"objFloatNumber0.98",
				"objFloatNumber0.99"
			};
			const char* obj_clone_expect_names[] = {
				"objUVTransClone1",
				"objUnique3",
				"objUnique3",
				"objUnique3",
				"objTrailCountUp01",
				"objTrailCountUp03",
				"objTrailCountUp100",
				"objFloatNumber0.100",
				"objFloatNumber0.100",
				"objFloatNumber0.100"
			};
			AddTextLine("MQ0x::GetObjectのNULLまたは未発見テスト");
			if ( MQ0x::GetObject( NULL, (const char*)NULL ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetObject( NULL, -1 ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetObject( m_doc, (const char*)NULL ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetObject( m_doc, -1 ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetObject( m_doc, "" ) != NULL ) return TestFailed(__LINE__);
			if ( MQ0x::GetObject( m_doc, "obj99" ) != NULL ) return TestFailed(__LINE__);
			AddTextLine("MQ0x::GetObjectの特定オブジェクト発見テスト");
			AddTextLine("このテストを正常に成功させるためには専用のmqoファイルがあらかじめロードされている必要があります");
			for ( int index = 0; index < sizeof(obj_names)/sizeof(obj_names[0]); index++ ) {
				MQObject obj = MQ0x::GetObject( m_doc, obj_names[index] );
				if ( obj == NULL ) {
					AddTextLine( System::String::Format( "名前が見つかりません。:{0}", gcnew System::String(obj_names[index]) ) );
					return TestFailed(__LINE__);
				}
				UINT id = obj->GetUniqueID();
				MQObject obj_id = MQ0x::GetObject( m_doc, id );
				if ( obj_id == NULL ) {
					AddTextLine( System::String::Format( "IDで見つかりません。:{0}", gcnew System::String(obj_names[index]) ) );
					return TestFailed(__LINE__);
				}
				if ( obj != obj_id ) return TestFailed(__LINE__); // address not match?
				if ( strcmp( obj_names[index], MQ0x::GetName( obj ).c_str() ) != 0 ) return TestFailed(__LINE__);
				if ( strcmp( obj_names[index], MQ0x::GetName( obj_id ).c_str() ) != 0 ) return TestFailed(__LINE__);
				if ( strcmp( obj_clone_expect_names[index], MQ0x::GetCountUpCloneableUniqueName( m_doc, obj ).c_str() ) != 0 ) return TestFailed(__LINE__);
			}
			AddTextLine("MQ0x::GetObjectIndexの未発見テスト");
			if ( 0 <= MQ0x::GetObjectIndex( NULL, (const char*)NULL ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetObjectIndex( NULL, -1 ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetObjectIndex( m_doc, (const char*)NULL ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetObjectIndex( m_doc, -1 ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetObjectIndex( m_doc, "" ) ) return TestFailed(__LINE__);
			if ( 0 <= MQ0x::GetObjectIndex( m_doc, "mat99" ) ) return TestFailed(__LINE__);
			AddTextLine("MQ0x::GetObjectIndexの特定オブジェクト発見テスト");
			AddTextLine("このテストを正常に成功させるためには専用のmqoファイルがあらかじめロードされている必要があります");
			for ( int index = 0; index < sizeof(obj_names)/sizeof(obj_names[0]); index++ ) {
				int obj_index = MQ0x::GetObjectIndex( m_doc, obj_names[index] );
				MQObject obj = m_doc->GetObject(obj_index); // 有効チェック
				if ( obj == NULL ) {
					AddTextLine( System::String::Format( "名前が見つかりません。:{0}/{1}", obj_index, gcnew System::String(obj_names[index]) ) );
					return TestFailed(__LINE__);
				}
				UINT id = obj->GetUniqueID();
				int obj_id_index = MQ0x::GetObjectIndex( m_doc, id );
				if ( obj_index != obj_id_index ) {
					AddTextLine( System::String::Format( "IDで見つかりません。:{0}", gcnew System::String(obj_names[index]) ) );
					return TestFailed(__LINE__);
				}
				if ( strcmp( obj_names[index], MQ0x::GetName( obj ).c_str() ) != 0 ) return TestFailed(__LINE__);
			}

			const char* mat_getPathChk[] = { "matRelPath", "matAbsPath" };
			for ( int index = 0; index < sizeof(mat_getPathChk)/sizeof(mat_getPathChk[0]); index++ ) {
				MQMaterial mat = MQ0x::GetMaterial( m_doc, mat_getPathChk[index] );
				if ( mat == NULL ) {
					AddTextLine( System::String::Format( "名前が見つかりません。:{0}/{1}", index, gcnew System::String(mat_getPathChk[index]) ) );
					return TestFailed(__LINE__);
				}
				AddTextLine( gcnew System::String(MQ0x::GetMaterialTextureName( mat, MQMAPPING_TEXTURE ).c_str()) );
				AddTextLine( gcnew System::String(MQ0x::GetMaterialTextureName( mat, MQMAPPING_ALPHA ).c_str()) );
				AddTextLine( gcnew System::String(MQ0x::GetMaterialTextureName( mat, MQMAPPING_BUMP ).c_str()) );
			}

			AddTextLine( "存在しない相対パスの絶対パス変換を試行します" );
			{
				char buf[MAX_PATH];
				if ( m_doc->FindMappingFile(buf,"tex.bmp",MQMAPPING_TEXTURE) == TRUE ) AddTextLine( gcnew System::String( buf ) );
				else AddTextLine("失敗しました");
				if ( m_doc->FindMappingFile(buf,"",MQMAPPING_TEXTURE) == TRUE ) AddTextLine( gcnew System::String( buf ) );
				else AddTextLine("失敗しました");
			}

#if 0x0310 <= MQPLUGIN_VERSION

			AddTextLine("Check GetUnusedMaterialName()/GetUnusedObjectName()");
			AddTextLine(gcnew System::String("Material(NULL):") + gcnew System::String(MQ0x::GetUnusedMaterialName(m_doc).c_str()));
			AddTextLine(gcnew System::String("Object(NULL):") + gcnew System::String(MQ0x::GetUnusedObjectName(m_doc).c_str()));

			{
				MQMaterial mat = MQ0x::GetMaterial( m_doc, "matUVTransClone" );
				if ( mat == NULL ) return TestFailed(__LINE__);
				std::string name = MQ0x::GetName( mat ).c_str();
				std::string uname1 = MQ0x::GetUnusedMaterialName( m_doc, mat );
				std::string uname2 = MQ0x::GetUnusedMaterialName( m_doc, name.c_str() );
				if ( strcmp( uname1.c_str(), uname2.c_str() ) != 0 ) TestFailed(__LINE__); 
				AddTextLine( System::String::Format( "Material({0}):{1}/{2}",
					gcnew System::String(name.c_str()),
					gcnew System::String(uname1.c_str()),
					gcnew System::String(uname2.c_str())
				) );
			}

			{
				MQObject obj = MQ0x::GetObject( m_doc, "objUVTransClone" );
				if ( obj == NULL ) return TestFailed(__LINE__);
				std::string name = MQ0x::GetName( obj ).c_str();
				std::string uname1 = MQ0x::GetUnusedObjectName( m_doc, obj );
				std::string uname2 = MQ0x::GetUnusedObjectName( m_doc, name.c_str() );
				if ( strcmp( uname1.c_str(), uname2.c_str() ) != 0 ) TestFailed(__LINE__); 
				AddTextLine( System::String::Format( "Object({0}):{1}/{2}",
					gcnew System::String(name.c_str()),
					gcnew System::String(uname1.c_str()),
					gcnew System::String(uname2.c_str())
				) );
			}

#endif

			AddTextLine("テスト結果に異常は報告されませんでした。");
			return true;
		}
	};



}

static bool initialResult = MQCLI::Initialize( gcnew mqsdxTester::MQxTesterDlg::Plugin() );