#pragma once

#include "Subsystems/EngineSubsystem.h"
#include "SkyPortalRunner.h"
#include "SkyPortalIO.h"


#include "SkyPortalSubsystem.generated.h"

#pragma region Definitions

UENUM(BlueprintType)
enum EPortalSide {
	LEFT UMETA(DisplayName = "Left side"),
	RIGHT UMETA(DisplayName = "Right side"),
	BOTH UMETA(DisplayName = "Both left and right"),
	TRAP UMETA(DisplayName = "Trap")
};








//// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderAddedDelegate, int32, SkylanderID, int32, Index);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSkylanderRemovedDelegate, int32, SkylanderID, int32, Index);

#pragma endregion



/*
* Handle all the blueprints functions and game logic.
*
*/
UCLASS(MinimalAPI)
class USkyPortalSubsystem : public UEngineSubsystem
{
	GENERATED_BODY()

public:

	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;

	/***********************************************************/
	/********************* Portal Actions *********************/
	/***********************************************************/

	/* The first function to run, before anything else.
	*  It will re-init and prepare the portal for receiving/sending inputs
	*
	*  @return false if portal is not found
	*/
	UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal"))
	SKYPORTAL_API bool PortalConnect();

	/* Make sure that the connection to the portal works and that the device that is connected is actually a portal.
	*
	* In case of success, will update the PortalId, wich is different for each portal model.
	*/
	UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal|Commands"))
	SKYPORTAL_API void PortalReady();

	/* Activate all the main functions of the portal, like figure detection or wireless signal.
	* This command should be used before any other commands with the exception of the Ready command
	*
	* When the portal is activated, it will periodically send out Status responses even when no Status request has been sent. If the portal has not been activated, or if it has been deactivated again, Status responses will still be sent when requested.
	* If a Deactivate request is received by a portal, all LEDs will turn off. They can be turned on again by their respective commands.
	*
	* @param bShouldActivate Optional : If false, send a Deactivate command.
	*/
	UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal|Commands"))
	SKYPORTAL_API void PortalActivate(const bool bShouldActivate = true);


	/* Change portal color, ideally should be called just at the start. For gameplay usage, use ChangePortalColorSide()
	*
	* @param	NextColor	New color
	*/
	UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "NextColor", Category = "SkyPortal|Commands|Cosmetic", HideAlphaChannel))
	SKYPORTAL_API void ChangePortalColor(const FLinearColor& NextColor = FLinearColor::Green);

	/*Send a **Status** command, to see if the portal is ready to receive new commands*/
	UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal"))
	SKYPORTAL_API bool IsPortalReady();

	UFUNCTION(BlueprintCallable, meta = (Category = "SkyPortal|NOT FUNCTIONING"))
	SKYPORTAL_API void PortalMusic(const USoundWave* Sound);

	/**/
	UFUNCTION(BlueprintCallable, CallInEditor, meta = (Category = "SkyPortal|Commands"))
	SKYPORTAL_API FPortalStatusData PortalStatus();

	


	/* Change the color of the portal, can separate side and even trap ligth
	 * @param	NextColor	New color
	 * @param	PortalSide	The actors to record
	 * @param	BlendTime	Blend between current color and NextColor, in milliseconds
	 */
	UFUNCTION(BlueprintCallable, CallInEditor, meta = (AutoCreateRefTerm = "NextColor", Category = "SkyPortal|Commands|Cosmetic", HideAlphaChannel))
	SKYPORTAL_API void ChangePortalColorSide(const FLinearColor& NextColor = FLinearColor::Green, const EPortalSide PortalSide = EPortalSide::BOTH, const float BlendTime = 500.0f);

	

	// Blueprint-assignable event property
	UPROPERTY(BlueprintAssignable, Category = "SkyPortal|Skylander")
	FOnSkylanderAddedDelegate OnSkylanderAdded;

	// Blueprint-assignable event property
	UPROPERTY(BlueprintAssignable, Category = "SkyPortal|Skylander")
	FOnSkylanderRemovedDelegate OnSkylanderRemoved;

	UPROPERTY(BlueprintReadOnly)
	FPortalStatusData StatusData;

	/* Different for each portal model.
	*
	* SSA :
	* GIANTS :
	* SWAP FORCE : 0000547 ? , 515
	* TRAP TEAM :
	* SUPERCHARGERS :
	* IMAGINATORS :
	*/
	UPROPERTY(BlueprintReadOnly)
	int PortalId;


	UPROPERTY(BlueprintReadOnly)
	USkyPortalIO* PortalHandle;

	/**/
	UPROPERTY()
	bool bPortalConnected_DEPRECATED = PortalHandle ? PortalHandle->bPortalReady : false;






private:


	// deprecated
	FPortalStatusData OLDParsePortalStatus(const FWriteBlock& ResponseBlock); // deprecated

	EPortalCommand GetPortalCommandFromChar(unsigned char Char); // deprecated

	

	/* Sleep the system
	*
	* @param sleepMs Sleep time (in milliseconds)
	*/
	static void Sleep(int sleepMs);

	bool FalsePositive() const;

	// Pointer to the status checker thread
	FPortalStatusChecker* StatusChecker;
	FRunnableThread* StatusCheckerThread;


protected:

};


