//#include <vcclr.h>
#include "orbitersdk.h"
#include "Vessel2Base.h"
#include "Vessel2.h"
#include "Vessel.h"

using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::InteropServices;
using namespace Orbiter;

[assembly:AssemblyVersionAttribute("1.0.0.0")];

namespace Orbiter
{
	namespace Wrapper
	{
		ref class Vessel;
		Vessel2::Vessel2(OBJHANDLE hVessel, int flightmodel, Interfaces::Vessel2^ vessel2):VESSEL2 (hVessel, flightmodel)
		{
			Interfaces::Vessel2Callback v2c=vessel2->CallbackSetting::get();
			if ((int)(v2c & Interfaces::Vessel2Callback::ADCtrlMode)>0) bADCtrlMode=true; else bADCtrlMode=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::Animate)>0) bAnimate=true; else bAnimate=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::ConsumeBufferedKey)>0) bConsumeBufferedKey=true; else bConsumeBufferedKey=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::ConsumeDirectKey)>0) bConsumeDirectKey=true; else bConsumeDirectKey=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::DockEvent)>0) bDockEvent=true; else bDockEvent=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::DrawHUD)>0) bDrawHUD=true; else bDrawHUD=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::FocusChanged)>0) bFocusChanged=true; else bFocusChanged=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::HUDMode)>0) bHUDMode=true; else bHUDMode=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::LoadGenericCockpit)>0) bLoadGenericCockpit=true; else bLoadGenericCockpit=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::LoadPanel)>0) bLoadPanel=true; else bLoadPanel=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::LoadStateEx)>0) bLoadStateEx=true; else bLoadStateEx=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::LoadVC)>0) bLoadVC=true; else bLoadVC=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::MFDMode)>0) bMFDMode=true; else bMFDMode=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::NavMode)>0) bNavMode=true; else bNavMode=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::PanelMouseEvent)>0) bPanelMouseEvent=true; else bPanelMouseEvent=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::PanelRedrawEvent)>0) bPanelRedrawEvent=true; else bPanelRedrawEvent=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::PlaybackEvent)>0) bPlaybackEvent=true; else bPlaybackEvent=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::PostCreation)>0) bPostCreation=true; else bPostCreation=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::PostStep)>0) bPostStep=true; else bPostStep=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::PreStep)>0) bPreStep=true; else bPreStep=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::RCSMode)>0) bRCSMode=true; else bRCSMode=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::SaveState)>0) bSaveState=true; else bSaveState=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::SetClassCaps)>0) bSetClassCaps=true; else bSetClassCaps=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::SetStateEx)>0) bSetStateEx=true; else bSetStateEx=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::VCMouseEvent)>0) bVCMouseEvent=true; else bVCMouseEvent=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::VCRedrawEvent)>0) bVCRedrawEvent=true; else bVCRedrawEvent=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::VisualCreated)>0) bVisualCreated=true; else bVisualCreated=false;
			if ((int)(v2c & Interfaces::Vessel2Callback::VisualDestroyed)>0) bVisualDestroyed=true; else bVisualDestroyed=false;

			this->vessel2=vessel2;
			vessel2->This::set(gcnew Wrapper::Vessel((VESSEL *)this));
			vessel2->Base::set(gcnew Wrapper::Vessel2Base(this));
		}

		Vessel2::~Vessel2()
		{
			vessel2->DisposeThis();
			vessel2->This::set(nullptr);
			vessel2->Base::set(nullptr);
			vessel2=nullptr;
		}		

		void Vessel2::clbkSetClassCaps (FILEHANDLE cfg)
		{
			if (bSetClassCaps) vessel2->SetClassCaps((IntPtr)cfg);
			else VESSEL2::clbkSetClassCaps(cfg);
		}
		void Vessel2::clbkSaveState (FILEHANDLE scn)
		{
			if (bSaveState) vessel2->SaveState((IntPtr)scn);
			else VESSEL2::clbkSaveState(scn);
		}
		void Vessel2::clbkLoadStateEx (FILEHANDLE scn, void *status)
		{
			if (bLoadStateEx) vessel2->LoadStateEx((IntPtr)scn, (IntPtr)status);
			else VESSEL2::clbkLoadStateEx(scn, status);
		}
		void Vessel2::clbkSetStateEx (const void *status)
		{
			if (bSetStateEx)
			{
				Interfaces::VesselStatus2^ state=gcnew Interfaces::VesselStatus2;
				VESSELSTATUS2 *intState=(VESSELSTATUS2 *) status;
				state->arot=gcnew Interfaces::Vector3(intState->arot.x,intState->arot.y,intState->arot.z);
				state->tbase=(IntPtr)intState->base;
				state->flag=intState->flag;
				state->port=intState->port;
				state->rbody=(IntPtr)intState->rbody;
				state->rpos=gcnew Interfaces::Vector3(intState->rpos.x,intState->rpos.y,intState->rpos.z);
				state->rvel=gcnew Interfaces::Vector3(intState->rvel.x,intState->rvel.y,intState->rvel.z);
				state->status=intState->status;
				state->surf_hdg=intState->surf_hdg;
				state->surf_lat=intState->surf_lat;
				state->surf_lng=intState->surf_lng;
				state->version=intState->version;
				state->vrot=gcnew Interfaces::Vector3(intState->vrot.x,intState->vrot.y,intState->vrot.z);
				state->xpdr=intState->xpdr;
				DWORD i;
				if (intState->nfuel>0)
				{
					state->fuel=gcnew array<Interfaces::FuelEntry>(intState->nfuel);
					for(i=0;i<intState->nfuel;i++)
					{
						state->fuel[i].idx=intState->fuel[i].idx;
						state->fuel[i].level=intState->fuel[i].level;
					}
				}
				else state->fuel=nullptr;
				if (intState->nthruster>0)
				{
					state->thruster=gcnew array<Interfaces::ThrusterEntry>(intState->nthruster);
					for(i=0;i<intState->nthruster;i++)
					{
						state->thruster[i].idx=intState->thruster[i].idx;
						state->thruster[i].level=intState->thruster[i].level;
					}
				}
				else state->thruster=nullptr;
				if (intState->ndockinfo>0)
				{
					state->dockinfo=gcnew array<Interfaces::DockEntry>(intState->ndockinfo);
					for(i=0;i<intState->ndockinfo;i++)
					{
						state->dockinfo[i].idx=intState->dockinfo[i].idx;
						state->dockinfo[i].ridx=intState->dockinfo[i].ridx;
						state->dockinfo[i].rvessel=(IntPtr)intState->dockinfo[i].rvessel;
					}
				}
				else state->dockinfo=nullptr;
				vessel2->SetStateEx(*state);
			}
			else VESSEL2::clbkSetStateEx(status);
		}
		void Vessel2::clbkPostCreation ()
		{
			if (bPostCreation) vessel2->PostCreation();
			else VESSEL2::clbkPostCreation();
		}
		void Vessel2::clbkFocusChanged (bool getfocus, OBJHANDLE hNewVessel, OBJHANDLE hOldVessel)
		{
			if (bFocusChanged) vessel2->FocusChanged(getfocus, (IntPtr) hNewVessel, (IntPtr) hOldVessel);
			else VESSEL2::clbkFocusChanged(getfocus, hNewVessel, hOldVessel);
		}
		void Vessel2::clbkPreStep (double simt, double simdt, double mjd)
		{
			if (bPreStep) vessel2->PreStep(simt, simdt, mjd);
			else VESSEL2::clbkPreStep(simt, simdt, mjd);
		}
		void Vessel2::clbkPostStep (double simt, double simdt, double mjd)
		{
			if (bPostStep) vessel2->PostStep(simt, simdt, mjd);
			else VESSEL2::clbkPostStep(simt, simdt, mjd);
		}
		bool Vessel2::clbkPlaybackEvent (double simt, double event_t, const char *event_type, const char *event)
		{
			if (bPlaybackEvent) return vessel2->PlaybackEvent(simt, event_t, Marshal::PtrToStringAnsi((IntPtr)(void *)event_type), Marshal::PtrToStringAnsi((IntPtr)(void *)event));
			else return VESSEL2::clbkPlaybackEvent(simt, event_t, event_type, event);
		}
		void Vessel2::clbkVisualCreated (VISHANDLE vis, int refcount)
		{
			if (bVisualCreated) vessel2->VisualCreated((IntPtr) vis, refcount);
			else VESSEL2::clbkVisualCreated(vis, refcount);
		}
		void Vessel2::clbkVisualDestroyed (VISHANDLE vis, int refcount)
		{
			if (bVisualDestroyed) vessel2->VisualDestroyed((IntPtr) vis, refcount);
			else VESSEL2::clbkVisualDestroyed(vis, refcount);
		}
		void Vessel2::clbkDrawHUD (int mode, const HUDPAINTSPEC *hps, HDC hDC)
		{
			if (bDrawHUD)
			{
				Interfaces::HudPaintSpecification hpspec=(Interfaces::HudPaintSpecification)Marshal::PtrToStructure((IntPtr)(void *)hps, Interfaces::HudPaintSpecification::typeid);
				vessel2->DrawHUD(mode, hpspec, (IntPtr) hDC);
			}
			else VESSEL2::clbkDrawHUD(mode, hps, hDC);
		}
		void Vessel2::clbkRCSMode(int mode)
		{
			if (bRCSMode) vessel2->RCSMode(mode);
			else VESSEL2::clbkRCSMode(mode);
		}
		void Vessel2::clbkADCtrlMode (DWORD mode)
		{
			if (bADCtrlMode) vessel2->ADCtrlMode(mode);
			else VESSEL2::clbkADCtrlMode(mode);
		}
		void Vessel2::clbkHUDMode (int mode)
		{
			if (bHUDMode) vessel2->HUDMode(mode);
			else VESSEL2::clbkHUDMode(mode);
		}
		void Vessel2::clbkMFDMode (int mfd, int mode)
		{
			if (bMFDMode) vessel2->MFDMode(mfd, mode);
			else VESSEL2::clbkMFDMode(mfd, mode);
		}
		void Vessel2::clbkNavMode (int mode, bool active)
		{
			if (bNavMode) vessel2->NavMode(mode, active);
			else VESSEL2::clbkNavMode(mode, active);
		}
		void Vessel2::clbkDockEvent (int dock, OBJHANDLE mate)
		{
			if (bDockEvent) vessel2->DockEvent(dock, (IntPtr) mate);
			else VESSEL2::clbkDockEvent(dock, mate);
		}
		void Vessel2::clbkAnimate (double simt)
		{
			if (bAnimate) vessel2->Animate(simt);
			else VESSEL2::clbkAnimate(simt);
		}
		int  Vessel2::clbkConsumeDirectKey (char *keystate)
		{
			if (bConsumeDirectKey) return vessel2->ConsumeDirectKey((IntPtr)keystate);
			else return VESSEL2::clbkConsumeDirectKey(keystate);
		}
		int  Vessel2::clbkConsumeBufferedKey (DWORD key, bool down, char *keystate)
		{
			if (bConsumeBufferedKey) return vessel2->ConsumeBufferedKey (key, down, (IntPtr)keystate);
			else return VESSEL2::clbkConsumeBufferedKey(key, down, keystate);
		}
		bool Vessel2::clbkLoadGenericCockpit ()
		{
			if (bLoadGenericCockpit) return vessel2->LoadGenericCockpit();
			else return VESSEL2::clbkLoadGenericCockpit();
		}
		bool Vessel2::clbkLoadPanel (int id)
		{
			if (bLoadPanel) return vessel2->LoadPanel(id);
			else return VESSEL2::clbkLoadPanel(id);
		}
		bool Vessel2::clbkPanelMouseEvent (int id, int event, int mx, int my)
		{
			if (bPanelMouseEvent) return vessel2->PanelMouseEvent(id, event, mx, my);
			else return VESSEL2::clbkPanelMouseEvent(id, event, mx, my);
		}
		bool Vessel2::clbkPanelRedrawEvent (int id, int event, SURFHANDLE surf)
		{
			if (bPanelRedrawEvent) return vessel2->PanelRedrawEvent(id, event, (IntPtr) surf);
			else return VESSEL2::clbkPanelRedrawEvent(id, event, surf);
		}
		bool Vessel2::clbkLoadVC (int id)
		{
			if (bLoadVC) return vessel2->LoadVC(id);
			else return VESSEL2::clbkLoadVC(id);
		}
		bool Vessel2::clbkVCMouseEvent (int id, int event, VECTOR3 &p)
		{
			if (bVCMouseEvent)
			{
				Interfaces::Vector3^ mp=gcnew Interfaces::Vector3(p.x, p.y, p.z);
				bool result=vessel2->VCMouseEvent(id, event, mp);
				p.x=mp->X;
				p.y=mp->Y;
				p.z=mp->Z;
				return result;
			}
			else return VESSEL2::clbkVCMouseEvent(id, event, p);
		}
		bool Vessel2::clbkVCRedrawEvent (int id, int event, SURFHANDLE surf)
		{
			if (bVCRedrawEvent) return vessel2->VCRedrawEvent(id, event, (IntPtr) surf);
			else return VESSEL2::clbkVCRedrawEvent(id, event, surf);		
		}

		void Vessel2::SetClassCaps (IntPtr configuration){VESSEL2::clbkSetClassCaps((FILEHANDLE)(void *)configuration);}
		void Vessel2::SaveState (IntPtr scenario){VESSEL2::clbkSaveState((FILEHANDLE)(void *)scenario);}
		void Vessel2::LoadStateEx (IntPtr scenario, IntPtr status)
		{
			VESSEL2::clbkLoadStateEx((FILEHANDLE)(void *)scenario, (void *)status);
		}
		void Vessel2::SetStateEx (Interfaces::VesselStatus2 status)
		{
			VESSELSTATUS2 *state=new VESSELSTATUS2;
			state->base=(OBJHANDLE)(void *)status.tbase;
			state->rbody=(OBJHANDLE)(void *)status.rbody;
			state->flag=(DWORD)status.flag;
			state->version=(DWORD)status.version;
			state->xpdr=(DWORD)status.xpdr;
			state->port=status.port;			
			state->arot=_V(status.arot->X,status.arot->Y,status.arot->Z);
			state->rvel=_V(status.rvel->X,status.rvel->Y,status.rvel->Z);
			state->rpos=_V(status.rpos->X,status.rpos->Y,status.rpos->Z);
			state->vrot=_V(status.vrot->X,status.vrot->Y,status.vrot->Z);
			state->status=status.status;
			state->surf_hdg=status.surf_hdg;
			state->surf_lat=status.surf_lat;
			state->surf_lng=status.surf_lng;
			if (status.dockinfo!=nullptr)
			{
				state->ndockinfo=status.dockinfo->Length;			
				state->dockinfo=new VESSELSTATUS2::DOCKINFOSPEC[state->ndockinfo];
				for(DWORD i=0;i<state->ndockinfo;i++)
				{
					state->dockinfo[i].idx=(DWORD)status.dockinfo[i].idx;
					state->dockinfo[i].ridx=(DWORD)status.dockinfo[i].ridx;
					state->dockinfo[i].rvessel=(OBJHANDLE)(void *)status.dockinfo[i].rvessel;
				};
			}
			else
			{
				state->ndockinfo=0;
				state->dockinfo=0;
			}
			if (status.thruster!=nullptr)
			{
				state->nthruster=status.thruster->Length;
				state->thruster=new VESSELSTATUS2::THRUSTSPEC[state->nthruster];
				for(DWORD i=0;i<state->nthruster;i++)
				{
					state->thruster[i].idx=(DWORD)status.thruster[i].idx;
					state->thruster[i].level=status.thruster[i].level;
				}
			}
			else
			{
				state->nthruster=0;
				state->thruster=0;
			}
			if (status.fuel!=nullptr)
			{
				state->nfuel=status.fuel->Length;
				state->fuel=new VESSELSTATUS2::FUELSPEC[state->nfuel];
				for(DWORD i=0;i<state->nfuel;i++)
				{
					state->fuel[i].idx=(DWORD)status.fuel[i].idx;
					state->fuel[i].level=status.fuel[i].level;
				}
			}
			else
			{
				state->nfuel=0;
				state->fuel=0;
			}
			VESSEL2::clbkSetStateEx(state);
			delete [] state->dockinfo;
			delete [] state->thruster;
			delete [] state->fuel;
			delete state;
		}
		void Vessel2::PostCreation (){VESSEL2::clbkPostCreation();}
		void Vessel2::FocusChanged (bool getFocus, IntPtr newVessel, IntPtr oldVessel){VESSEL2::clbkFocusChanged(getFocus, (OBJHANDLE)(void *)newVessel, (OBJHANDLE)(void *)oldVessel);}
		void Vessel2::PreStep (double simt, double simdt, double mjd){VESSEL2::clbkPreStep(simt, simdt, mjd);}
		void Vessel2::PostStep (double simt, double simdt, double mjd){VESSEL2::clbkPostStep(simt, simdt, mjd);}
		bool Vessel2::PlaybackEvent (double simt, double event_t, String^ event_type, String^ event_name)
		{
			IntPtr sEvent_type=Marshal::StringToHGlobalAnsi(event_type);
			IntPtr sEvent_name=Marshal::StringToHGlobalAnsi(event_name);
			bool result=VESSEL2::clbkPlaybackEvent(simt, event_t, (char *)(void *)sEvent_type, (char *)(void *)sEvent_name);
			Marshal::FreeHGlobal(sEvent_type);
			Marshal::FreeHGlobal(sEvent_name);
			return result;
		}
		void Vessel2::VisualCreated (IntPtr vis, int refCount){VESSEL2::clbkVisualCreated((VISHANDLE)(void *)vis, refCount);}
		void Vessel2::VisualDestroyed (IntPtr vis, int refCount){VESSEL2::clbkVisualDestroyed((VISHANDLE)(void *)vis, refCount);}
		void Vessel2::DrawHUD (int mode, Interfaces::HudPaintSpecification hps, IntPtr hDC)
		{
			HUDPAINTSPEC *hpspec=new HUDPAINTSPEC;
			Marshal::StructureToPtr(hps, (IntPtr)hpspec, true);
			VESSEL2::clbkDrawHUD(mode, hpspec, (HDC)(void *)hDC);
			delete hpspec;
		}
		void Vessel2::RCSMode (int mode){VESSEL2::clbkRCSMode(mode);}
		void Vessel2::ADCtrlMode (int mode){VESSEL2::clbkADCtrlMode(mode);}
		void Vessel2::HUDMode (int mode){VESSEL2::clbkHUDMode(mode);}
		void Vessel2::MFDMode (int mfd, int mode){VESSEL2::clbkMFDMode(mfd, mode);}
		void Vessel2::NavMode (int mode, bool active){VESSEL2::clbkNavMode(mode, active);}
		void Vessel2::DockEvent (int dock, IntPtr mate){VESSEL2::clbkDockEvent(dock, (OBJHANDLE)(void *)mate);}
		void Vessel2::Animate (double simt){VESSEL2::clbkAnimate(simt);}
		int  Vessel2::ConsumeDirectKey (IntPtr keyState){return VESSEL2::clbkConsumeDirectKey((char *)(void *)keyState);}
		int  Vessel2::ConsumeBufferedKey (int key, bool down, IntPtr keyState){return VESSEL2::clbkConsumeBufferedKey(key, down, (char *)(void *)keyState);}
		bool Vessel2::LoadGenericCockpit (){return VESSEL2::clbkLoadGenericCockpit();}
		bool Vessel2::LoadPanel (int id){return VESSEL2::clbkLoadPanel(id);}
		bool Vessel2::PanelMouseEvent (int id, int mouseEvent, int mx, int my){return VESSEL2::clbkPanelMouseEvent(id, mouseEvent, mx, my);}
		bool Vessel2::PanelRedrawEvent (int id, int mouseEvent, IntPtr surface){return VESSEL2::clbkPanelRedrawEvent(id, mouseEvent, (SURFHANDLE)(void *)surface);}
		bool Vessel2::LoadVC (int id){return VESSEL2::clbkLoadVC(id);}
		bool Vessel2::VCMouseEvent (int id, int mouseEvent, Interfaces::Vector3^ p)
		{
			VECTOR3 mp=_V(p->X, p->Y, p->Z);
			bool result=VESSEL2::clbkVCMouseEvent(id, mouseEvent, mp);
			p->X=mp.x;
			p->Y=mp.y;
			p->Z=mp.z;
			return result;
		}
		bool Vessel2::VCRedrawEvent (int id, int mouseEvent, IntPtr surface){return VESSEL2::clbkVCRedrawEvent(id, mouseEvent, (SURFHANDLE)(void *)surface);}
	}
}

