#include "WingHacks.h"
#include "ToolMenuEntry.h"
#include "BlueprintEditor.h"

// ============================================================
// Private member access via template explicit-instantiation loophole.
//
// The C++ standard says "the usual access checking rules do not
// apply to names used to specify explicit instantiations."  So
// &FToolMenuEntry::Action is legal as a template argument in an
// explicit instantiation, even though Action is private.
//
// The WingPrivateAccessor template captures the member pointer and exposes it
// through a friend function that we can call from normal code.
//
// See: https://bloglitb.blogspot.com/2011/12/access-to-private-members-safer.html
// ============================================================

template<typename Tag, typename Tag::type M>
struct WingPrivateAccessor
{
	friend typename Tag::type GetPtr(Tag) { return M; }
};

// ----- FToolMenuEntry::Action -----

struct Tag_FToolMenuEntry_Action
{
	using type = FToolUIActionChoice FToolMenuEntry::*;
	friend type GetPtr(Tag_FToolMenuEntry_Action);
};
template struct WingPrivateAccessor<Tag_FToolMenuEntry_Action, &FToolMenuEntry::Action>;

const FToolUIActionChoice& WingHacks::GetAction(const FToolMenuEntry& Entry)
{
	return Entry.*GetPtr(Tag_FToolMenuEntry_Action());
}

// ----- FToolMenuEntry::Command -----

struct Tag_FToolMenuEntry_Command
{
	using type = TSharedPtr<const FUICommandInfo> FToolMenuEntry::*;
	friend type GetPtr(Tag_FToolMenuEntry_Command);
};
template struct WingPrivateAccessor<Tag_FToolMenuEntry_Command, &FToolMenuEntry::Command>;

bool WingHacks::HasCommand(const FToolMenuEntry& Entry)
{
	return Entry.*GetPtr(Tag_FToolMenuEntry_Command()) != nullptr;
}

// ----- FBlueprintEditor::bWasOpenedInDefaultsMode -----

struct Tag_FBlueprintEditor_DefaultsMode
{
	using type = bool FBlueprintEditor::*;
	friend type GetPtr(Tag_FBlueprintEditor_DefaultsMode);
};
template struct WingPrivateAccessor<Tag_FBlueprintEditor_DefaultsMode, &FBlueprintEditor::bWasOpenedInDefaultsMode>;

bool WingHacks::WasOpenedInDefaultsMode(FBlueprintEditor* Editor)
{
	return Editor->*GetPtr(Tag_FBlueprintEditor_DefaultsMode());
}
