#include "StdAfx.h"
#include "ncgPluginManager.h"
#include "ncgDebugger.h"

using namespace ncg;
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Reflection;
using namespace ncgReflections;

#include <Ogre.h>

ncgPluginManager::ncgPluginManager(void)
{
	_mainPanel = nullptr;
	_mainMenu = nullptr;

	_sPluginFld = gcnew System::String(".");
}

void ncgPluginManager::FindPlugins(){
	System::IO::DirectoryInfo ^dir = gcnew System::IO::DirectoryInfo(_sPluginFld);

	DbgWriteV(1,"[Plugin Finder <%s>]\n",dir->FullName);
	for each(System::IO::FileInfo ^file in dir->GetFiles()){
		//File is of type DLL
		if(file->Extension->Contains(".dll")){
			try {
				Assembly ^a = Assembly::LoadFile(file->FullName);		//Not sure if we need to do this, might be redundant since we load the files in the call method function
				AssemblyName ^an = gcnew AssemblyName(a->FullName);	
					
				//Search each dll for a specific class, in this case ncgBaseClass
				for each(Type ^t in a->GetExportedTypes()){
					if(t->Name == "ncgBaseClass"){
						DbgWriteV(1,"  - Found %s.dll\n",an->Name);
						ncgPlugin ^tmp = gcnew ncgPlugin();
						tmp->_name = gcnew String(an->Name);
						tmp->_nameSpace = gcnew String(t->Namespace);
						tmp->_baseClass = gcnew String("ncgBaseClass");
						tmp->_file = file;
						
						_pluginList.Add(tmp);
						break;
					} else {
					}
				}
			} catch(Exception ^ex){
				DbgWriteV(1,"  - Error in plugin finder: %s\n",ex->Message);
			}
		}
	}
}

System::Void ncgPluginManager::SendKeyDown(System::Object^  sender, System::Windows::Forms::KeyEventArgs^  e){
	
		for each(ncgPlugin^ p in GetPluginList()){
			try {
				MethodInfo ^mi = p->_type->GetMethod("SendKeyDown");							//Find the attachparams method
				
				//Assign plugin parameters to .dll
				{
					array<System::Windows::Forms::KeyEventArgs^> ^ar = gcnew array<System::Windows::Forms::KeyEventArgs^>(1);
					ar[0] = e;
					mi->Invoke(p->_instance,ar);
				}
			} catch (System::Exception ^ex){
				
				DbgWriteV(1,"Error[%s]: %s\n",p->_name,ex->Message);
			}
		}
	
}
System::Void ncgPluginManager::SendKeyUp(System::Object^  sender, System::Windows::Forms::KeyEventArgs^  e){
		for each(ncgPlugin^ p in GetPluginList()){
			try {
				MethodInfo ^mi = p->_type->GetMethod("SendKeyUp");							//Find the attachparams method
				
				//Assign plugin parameters to .dll
				{
					array<System::Windows::Forms::KeyEventArgs^> ^ar = gcnew array<System::Windows::Forms::KeyEventArgs^>(1);
					ar[0] = e;
					mi->Invoke(p->_instance,ar);
				}
			} catch (System::Exception ^ex){
				
				DbgWriteV(1,"Error[%s]: %s\n",p->_name,ex->Message);
			}
		}
}

void ncgPluginManager::LoadPlugin(System::String ^name){
	for each(ncgPlugin^ p in GetPluginList()){
		System::String ^shortName = p->_file->Name->Substring(0,p->_file->Name->LastIndexOf('.'));
		
		if(name->ToLower() == shortName->ToLower()){
			LoadPlugin(p);
		}
	}
}
void ncgPluginManager::LoadPlugin(ncgPlugin ^p){
	Ogre::SceneManager *sceneMgr = Ogre::Root::getSingleton ().getSceneManager ("ExampleSMInstance"); 

	DbgWriteV(1,"\n[Load Plugin: %s]\n", p->_name);
	if(_mainPanel == nullptr)DbgWriteV(1,"  - Warning, main panel not assigned to plugin loader.\n");
	if(_mainMenu == nullptr)DbgWriteV(1,"  - Warning, main menu not assigned to plugin loader.\n");
	
	try {
		System::String ^shortName = p->_file->Name->Substring(0,p->_file->Name->LastIndexOf('.'));
		DbgWriteV(1,"  - Loading DLL: %s\n", p->_file->Name);
		
		p->_assm = Assembly::LoadFile(p->_file->FullName);					//Load assembly(dll)
		p->_dllclass = gcnew String(p->_nameSpace + "." + p->_baseClass);	//
		p->_type = p->_assm->GetType(p->_dllclass);											//Get assembly type
		
		DbgWriteV(1,"  - Trying to run module base: %s\n", p->_dllclass);
		MethodInfo ^mi = p->_type->GetMethod("AttachParams");			//Find the attachparams method
		p->_instance = Activator::CreateInstance(p->_type);				//Create an instance of our assembly type and store it in the plugin list
	
		//Assign plugin parameters to .dll
		{
			ncgPluginParams params;
			params.mainPanel = _mainPanel;
			params.mainMenu = _mainMenu;
			params.dbgConsole = nullptr;
			params.scene = sceneMgr;
			params.sSceneName = gcnew System::String("ExampleSMInstance");
			array<ncgPluginParams ^> ^ar = gcnew array<ncgPluginParams^>(1);
			ar[0] = %params;
			mi->Invoke(p->_instance,ar);
		}

		MethodInfo ^mit = p->_type->GetMethod("InitPlugin");
		mit->Invoke(p->_instance,nullptr);
	} catch (System::Exception ^ex){
		DbgWriteV(1,"  - Error in base plugin loader: %s\n",ex->Message);
	}
}
void ncgPluginManager::LoadPlugins(){
	//Loop through all plugins and instantiate their base class.
	DbgWriteV(1,"[Load Plugin Array]\n");
	for each(ncgPlugin^ p in GetPluginList()){
		LoadPlugin(p);
	}
}
