//========================================================================================================
// Generic Tool Class
//
// Tools are the fundamental building blocks for function-trees, such as:
// - image-processing trees
// - shader trees
// etc.
//
// An ETool is an EObject with inputs, outputs and a "signal-propagation" mechanism
//
// AUTHOR:  Gabor Nagy
// DATE:    2024-Dec-03 18:23:06
//
// Copyright (C) 1996-2026 By Gabor Nagy. All rights reserved.
//========================================================================================================
#ifndef _ETool_h
#define _ETool_h


#include <EClass.h>

#include <Image/Image.h>

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif

typedef struct EToolClass_S*  EToolClassPtr;
typedef struct EToolClass_S   EToolClass;
typedef struct ETool_S        ETool;
typedef struct ETool_S*       EToolPtr;
EListA_t(EToolPtr);

#define E_ToolGetCurrentTime  E_GetMicroseconds


typedef struct EToolInterface_S   EToolInterface;
typedef struct EToolInterface_S*  EToolInterfacePtr;

typedef struct
{
	EEntityCore;

	EToolInterface*  Interface0;
	EToolInterface*  Interface1;
} EToolConnection;




#define E_IN   0x01
#define E_OUT  0x02

enum
{
	EToolSUCCESS = 0,
	EToolALREADY_CONNECTED,
	EToolIF0_ALREADY_HAS_AN_INPUT,
	EToolIF1_ALREADY_HAS_AN_INPUT,
	EToolDIRECTION_MISMATCH,
	EToolTYPE_MISMATCH
};


struct EToolInterface_S
{
	EResource          Resource;          // Name, Type structoffset etc. of resource in the current Tool
	EChangeFlags       Changed;
	ETime              ChangedTime;
	ETool*             Tool;              // Pointer back to the Tool to which interface belongs

	EToolConnection*   InputConnection;   // There can be only one input connection per interface
	EToolInterface*    InputInterface;    // There can be only one input connection per interface
	EChangeFlags       InputChanged;      // If the Tool of this interface is inactive when a signal comes in, these are updated, 
	ETime              InputChangedTime;  // so when the Tool is activated, it will know whether to update itself and how.

	EList(, EToolConnection*, OutputConnections);
	uint8_t            Direction;         // E_IN, E_OUT or both: tells whether this interface is an input, an output or both
};
EListA_t(EToolInterfacePtr);

typedef struct
{
	ETool*             Tool;  // Pointer the Tool to which Connections go

	EList(, EToolConnection*, Connections);
} EToolConnectionList;


#define EToolCore\
	EObjectCore(ETool);\
\
	EListA_s(, EToolInterfacePtr, Interfaces);\
\
/* This is a private member used for an optimization: it lists Connections per target tool, */\
/* so signals and connection changes can be propagated to other tools in a single call.     */\
	EList(, EToolConnectionList, ToolConnectionLists);\
\
	EBool  CacheResult, Active, SupportsInteractivePropagate, InteractivePropagate;\
	EFloat32_3  SchemPosition;\
	EpImage*    Icon;EpImage*  IconActive


#define EToolClassCore\
	EBaseClassCore(ETool);\
	int   (*Execute)(ETool* PTool, const EBool PGUIJustPoppedUp);\
	void  (*FreeCache)(ETool* PTool);\
	int   (*ConnectionChanged)(ETool* PTool);\
	int   (*InputChanged)(ETool* PTool, const EBool PAllowResultPropagation);\
	void  (*ActivateDeactivate)(ETool* PTool, const EBool PActivate)


struct EToolClass_S
{
	EToolClassCore;
};


struct ETool_S
{
	EToolCore;
};

#define EToolClass_Init(pDescriptor) do\
{\
	EBaseClass_Init(pDescriptor, EClassRESOURCES_STATIC, TRUE);\
	LClass->ActivateDeactivate = pDescriptor->ActivateDeactivate;\
} while(0)

#define EToolClass_InitNew(pDescriptor) do\
{\
	EBaseClass_InitNew(pDescriptor, EClassRESOURCES_STATIC, TRUE);\
	LClass->ActivateDeactivate = pDescriptor->ActivateDeactivate;\
} while(0)

extern EToolClass  ETool_class[];

extern ETool*           ETool_New(void* PCl);
extern EToolInterface*  ETool_InterfaceNew(ETool* PTool, const EResource* PResource);
EToolInterface*         ETool_AddInterface(ETool* PTool, const EResource* PResource, const char PDirection);
extern void             EToolInterface_Free(EToolInterface* PInterface);

extern EToolConnection*  EToolConnection_New(void);
extern void              EToolConnection_Free(EToolConnection* PConnection);
extern int               ETool_InterfacesConnect(EToolInterface* PInterface0, EToolInterface* PInterface1);
extern void              ETool_InterfacesDisconnect(EToolConnection* PConnection);

extern void  ETool_Execute(ETool* PTool, const EBool PPropagateResult, const EBool PGUIJustPoppedUp);
extern void  ETool_PropagateResult(ETool* PTool);


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration
#endif

#endif // _ETool_h
