#include "WingManual.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTypes.h"

void WingManual::PrintHandlerPrototype(const FWingHandlerConfig& Handler)
{
	UWingServer::Print(Handler.Name);
	UWingServer::Print(TEXT("("));
	bool bFirst = true;
	for (TFieldIterator<FProperty> PropIt(Handler.Class.Get(), EFieldIterationFlags::None); PropIt; ++PropIt)
	{
		if (!bFirst) UWingServer::Print(TEXT(","));
		bFirst = false;
		if (PropIt->HasMetaData(TEXT("Optional"))) UWingServer::Print(TEXT("?"));
		UWingServer::Print(PropIt->GetName());
	}
	UWingServer::Print(TEXT(")\n"));
}

void WingManual::PrintHandlerArguments(const FWingHandlerConfig& Handler)
{
	// parameter details
	for (TFieldIterator<FProperty> PropIt(Handler.Class.Get(), EFieldIterationFlags::None); PropIt; ++PropIt)
	{
		FProperty* Prop = *PropIt;
		FString Name = Prop->GetName();
		FString Type = UWingTypes::TypeToText(Prop);
		bool bOptional = Prop->HasMetaData(TEXT("Optional"));
		const FString& Desc = Prop->GetMetaData(TEXT("Description"));

        if (bOptional)
        {
		    UWingServer::Printf(TEXT("   %s (optional %s)"), *Name, *Type);
        }
        else
        {
		    UWingServer::Printf(TEXT("   %s (%s)"), *Name, *Type);
        }
		if (!Desc.IsEmpty()) UWingServer::Printf(TEXT(" — %s"), *Desc);
		UWingServer::Print(TEXT("\n"));
	}
}

void WingManual::PrintHandlerDescription(const FWingHandlerConfig& Handler)
{
	if (Handler.Documentation.IsEmpty()) return;
	UWingServer::Print(WingUtils::WrapText(Handler.Documentation, 80, TEXT("   // ")));
}

void WingManual::PrintHandlerHelp(const FWingHandlerConfig& Handler)
{
	UWingServer::Print(TEXT("\n"));
    PrintHandlerPrototype(Handler);
    PrintHandlerArguments(Handler);
    PrintHandlerDescription(Handler);
	UWingServer::Print(TEXT("\n"));
}

void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* Handler, bool Abridged)
{
    if (Sections.IsEmpty()) return;

    const bool bPrintAll = Sections.Contains(Section::All);

    if (Abridged)
    {
        UWingServer::Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n"));
    }

    if (Handler && (Sections.Contains(Section::HandlerHelp) || bPrintAll))
    {
        PrintHandlerHelp(*Handler);
    }

	if (Sections.Contains(Section::Paths) || bPrintAll)
	{
        if (Abridged)
        {
            UWingServer::Print(TEXT(
                "\n PATHS: Here are some example paths:"
                "\n   /Game/Widgets/WB_Hotkeys,widget:Canvas·122"
                "\n   /Game/Testing/BP_Test,graph:Rescale·Actor,node:K2Node_CallFunction_0,pin:Scale"
                "\n   /Game/Chars/BP_Manny,component:Camera·Boom"
                "\n"
            ));
        }
        else
        {
            UWingServer::Print(TEXT(
                "\n PATHS:"
                "\n"
                "\n   Most commands require you to specify a path.  A path starts"
                "\n   with an asset name, followed by steps separated by ,"
                "\n   that navigate into the asset.  Some Examples:"
                "\n"
                "\n    /Game/Widgets/WB_Hotkeys,widget:Canvas.122"
                "\n    /Game/Testing/BP_Test,graph:Rescale.Actor,node:K2Node_CallFunction_0,pin:Scale"
                "\n    /Game/Chars/BP_Manny,component:Camera.Boom"
                "\n"
                "\n   The navigation steps supported are:"
                "\n"
                "\n    graph — move from a blueprint or material to a graph."
                "\n    node — move from a graph to a graph node"
                "\n    pin — move from a graph node to a pin"
                "\n    component — move from a blueprint to a component"
                "\n    levelblueprint — move from a world to a blueprint"
                "\n    widget — move from a widget blueprint to a widget"
                "\n"
                "\n   Notice that paths use sanitized identifiers.  See the section"
                "\n   on identifier sanitization below for more information."
                "\n"
                "\n   Steps do not always require a parameter.  For example, materials"
                "\n   only have one graph, so you can just say:"
                "\n"
                "\n    /Game/Materials/MyMaterial,graph"
                "\n"
            ));
        }
	}

	if (Sections.Contains(Section::Types) || bPrintAll)
	{
        if (Abridged)
        {
            UWingServer::Print(TEXT(
                "\n TYPES: Here are some examples of valid types:"
                "\n   Bool, String, Vector, Rotator, HitResult, Actor, Character,"
                "\n   PlayerController, EBlendMode, EMovementMode, BP_Manny, BP_Quinn,"
                "\n   Array<Int>, Set<String>, Map<Int,Actor>"
                "\n   Soft<ABP_Manny>, Class<Pawn>, SoftClass<Pawn>"
                "\n"
            ));
        }
        else
        {
            UWingServer::Print(TEXT(
                "\n TYPES:"
                "\n"
                "\n To change variable types, or to express function prototypes, you will"
                "\n use our syntax for types.  Here are some valid examples:"
                "\n"
                "\n   Bool, String, Vector, Rotator, HitResult, Actor, Character,"
                "\n   PlayerController, EBlendMode, EMovementMode, BP_Manny, BP_Quinn,"
                "\n   Array<Int>, Set<String>, Map<Int,Actor>"
                "\n   Soft<ABP_Manny>, Class<Pawn>, SoftClass<Pawn>"
                "\n"
                "\n Notice that it's 'Actor', not 'AActor'.  Type names are not"
                "\n case-sensitive.  When a blueprint like /Game/Testing/BP_Foo"
                "\n is used as a type, the typename is BP_Foo."
                "\n"
            ));
        }
	}

	if (Sections.Contains(Section::VariableDeclarations) || bPrintAll)
	{
        if (Abridged)
        {
            UWingServer::Print(TEXT(
                "\n VARIABLE DECLARATIONS: example variable declarations:"
                "\n     Array<Actor> Actors"
                "\n     Float F (InstanceEditable)"
                "\n     String S = This is the default value"
            ));
        }
        else
        {
            UWingServer::Print(TEXT(
                "\n VARIABLE DECLARATIONS:"
                "\n"
                "\n   We have our own syntax for variable declarations: a type,"
                "\n   a name, optional flags, and an optional default value,"
                "\n   always on one line:"
                "\n"
                "\n     Array<Actor> Actors"
                "\n     Float F (InstanceEditable)"
                "\n     String S = This is the default value"
                "\n"
                "\n   The commands Variables_Create, Variables_Modify,"
                "\n   and Variables_Remove can be used to edit: "
                "\n   blueprint variables, graph local variables, graph input"
                "\n   variables, graph output variables, and custom"
                "\n   event node input variables.  Event dispatchers are"
                "\n   also graphs, so they too can be edited."
                "\n"
            ));
        }
	}

	if (Sections.Contains(Section::EscapeSequences) || bPrintAll)
	{
        if (Abridged)
        {
            UWingServer::Print(TEXT(
                "\n USING HTML ESCAPE SEQUENCES:"
                "\n   When we output FNames, we use HTML escape sequences for the"
                "\n   following marks: \\\"'(),.:;<=>&   We also escape control"
                "\n   characters, and some (but not all) unicode characters."
                "\n   We also translate spaces to periods.  Examples:"
                "\n"
                "\n     FName(TEXT(\"No_Change\"))   --> No_Change"
                "\n     FName(TEXT(\"ίδιος\"))       --> ίδιος"
                "\n     FName(TEXT(\"✡✢❄\"))         --> &#10017;&#10018;&#10052;"
                "\n     FName(TEXT(\"Hello.There\")) --> Hello&period;There"
                "\n     FName(TEXT(\"Hello There\")) --> Hello.There"
                "\n     FName(TEXT(\"Hello\n\"))     --> Hello&NewLine;"
                "\n "
                "\n   When sending FNames to UE Wingman, you *must* escape the marks"
                "\n   listed above and control characters, but you *may* escape"
                "\n   any character.  To send an FName with a space in it, either"
                "\n   use &#32; or a period."
                "\n"
                "\n   Currently, this escaping *only* applies to FNames.  It"
                "\n   doesn't work to use escapes in asset names or file names."
                "\n"
            ));
        }
        else
        {
            UWingServer::Print(TEXT(
                "\n USING HTML ESCAPE SEQUENCES:"
                "\n   When we output FNames, we use HTML escape sequences for the"
                "\n   following marks: \\\"'(),.:;<=>&, and for certain other characters."
                "\n   We also translate spaces to periods."
                "\n"
                "\n   When sending FNames to UE Wingman, you *must* escape the marks"
                "\n   listed above, but you *may* escape any character.  To send an FName"
                "\n   with a space in it, either use &#32; or a period."
                "\n"
            ));
        }
	}

	if (Sections.Contains(Section::Whitespace) || bPrintAll)
	{
        UWingServer::Print(TEXT(
            "\n ABOUT WHITESPACE:"
            "\n   Do not put excess whitespace into paths, typenames, or"
            "\n   function prototypes, only use whitespace where it is required"
            "\n   by the syntax."
            "\n"
        ));
	}

	if (Sections.Contains(Section::MaterialEditing) || bPrintAll)
	{
        if (Abridged)
        {
            UWingServer::Print(TEXT(
                "\n MATERIAL EDITING:"
                "\n   We do not expose material expressions directly.  Instead, use"
                "\n   Property_Dump and Property_Set on the material graph nodes to"
                "\n   edit material expression properties."
                "\n"
            ));
        }
        else
        {
            UWingServer::Print(TEXT(
                "\n MATERIAL EDITING:"
                "\n"
                "\n   We do not expose material expressions directly.  Instead, you"
                "\n   will be editing the material graph.  However, if you Graph_Dump"
                "\n   a material graph, you will see that the nodes contain mxprop"
                "\n   properties, which actually come from the material expressions."
                "\n   You can edit these using Property_Set on the node."
                "\n"
            ));
        }
	}

	if (Sections.Contains(Section::ImportantCommands) || bPrintAll)
	{
        UWingServer::Print(TEXT(
            "\n COMMANDS YOU SHOULD KNOW ABOUT AND REMEMBER:"
            "\n   UserManual: this explanation"
            "\n   ShowCommands: a full list of all the commands"
            "\n   Blueprint_Dump: a summary of any blueprint"
            "\n   Graph_Dump: a fairly detailed listing of any Graph"
            "\n   Property_Dump: show information on many objects"
            "\n"
            "\n   You can use ShowCommands(Query=SomeCommand,Verbose=true)"
            "\n   to get detailed help for a specific command."
            "\n"
        ));
	}

    if (Abridged)
    {
        UWingServer::Printf(TEXT("\nUse command 'UserManual' to see the full manual.\n"));
    }
}
