@startuml

!include ./config/diagramsConfig.puml
!include ./config/classConfig.puml

title
rootJS Architecture

end title

/' ----------------------------------------------------------------------- '/

/' Interfaces '/
' interface ROOT

/' Environment '/
class "ROOT::TApplication" as TApplication
class NodeApplication
class CallbackHandler
class NodeHandler

/' Javascript Prototypes '/
class TemplateFactory
' class TemplateCache

/' Encapsulation '/
abstract class Proxy

/' Encapsulation of ROOT functions '/
class FunctionProxyFactory
class FunctionProxy

/' Encapsulation of ROOT objects and primitives '/
class ObjectProxyFactory
class ObjectProxy

class TemplateProxy
class EnumProxy
class StructProxy
class ArrayProxy
class PointerProxy

abstract class PrimitiveProxy
class NumberProxy
class StringProxy
class BooleanProxy

/' Interfacing with ROOT's reflection mechanism - i.e. Cling '/

/' ----------------------------------------------------------------------- '/

/' Relations '/
TApplication <|-down- NodeApplication
NodeHandler -left-> NodeApplication
NodeHandler -right-> CallbackHandler

CallbackHandler ..> TemplateFactory : uses
CallbackHandler ..> ObjectProxyFactory : uses
CallbackHandler ..> FunctionProxyFactory : uses

NodeHandler ..> TemplateFactory : uses
NodeHandler ..> ObjectProxyFactory : uses
NodeHandler ..> FunctionProxyFactory : uses

Proxy <|-right- ObjectProxy
Proxy <|-left- FunctionProxy

FunctionProxyFactory .down.> FunctionProxy : creates
ObjectProxyFactory .down.> ObjectProxy : creates

ObjectProxy <|-- EnumProxy
ObjectProxy <|-- PointerProxy
ObjectProxy <|-- StructProxy
ObjectProxy <|-- ArrayProxy
ObjectProxy <|-- TemplateProxy
ObjectProxy <|-- PrimitiveProxy
PrimitiveProxy <|-- NumberProxy
PrimitiveProxy <|-- StringProxy
PrimitiveProxy <|-- BooleanProxy

/' ----------------------------------------------------------------------- '/

/' Callback Handling '/
class CallbackHandler {
  {static} +ctorCallback(args: FunctionCallbackInfo<Value>)
  {static} +staticCtorCallback(args: FunctionCallbackInfo<Value>)

  {static} +memberGetterCallback(property: Local<String>, info: PropertyCallbackInfo<Value>)
  {static} +memberSetterCallback(property: Local<String>, value: Local<Value>, info: PropertyCallbackInfo<Value>)
  {static} +memberFunctionCallback(args: FunctionCallbackInfo<Value>)

  {static} +staticGetterCallback(property: Local<String>, info: PropertyCallbackInfo<Value>)
  {static} +staticSetterCallback(property: Local<String>, value: Local<Value>, info: PropertyCallbackInfo<Value>)
  {static} +staticFunctionCallback(args: FunctionCallbackInfo<Value>)

  ' -CallbackHandler() <<constructor>>
}

class NodeHandler {
  {static} -initialized: bool
  rootJS: Persistent<Object>
  --
  {static} +initialize(exports: Local<Object>, module: Local<Object>)

  -exposeROOT()
  -exposeGlobalFunctions()
  -exposeGlobals()
  -exposeMacros()
  -exposeClasses()
  -exposeClass(clazz: TClassRef)

  +getExports(): Local<Object>
}


/' Facade '/
class NodeApplication {
 --
 {static} -Exit(args: void*)

 +NodeApplication(acn: char*, argc: int*, argv: char**) <<constructor>>
 -initROOTGlobals()
 -initROOTMessageCallback()
}

/' ----------------------------------------------------------------------- '/

/' Javascript Prototypes '/
class TemplateFactory {
  {static} -cache: map<string, Persistent<FunctionTemplate>>
  --
  -TemplateFactory() <<constructor>>
  {static} +createTemplate(clazz: TClassRef): Local<FunctionTemplate>
}

/' ----------------------------------------------------------------------- '/

/' Encapsulation '/
abstract class Proxy {
    #address: void*
    #type: TObject
    #scope: TClassRef
    --
    #Proxy(address: void*, type: TObject, scope: TClassRef) <<constructor>>
    {abstract} +setAddress(address: void*)
    +getAddress(): void*
    +getType(): TObject
    +getScope(): TClassRef

    +isGlobal(): bool

    {abstract} +isTemplate(): bool
    {abstract} +isConst(): bool
    {abstract} +isStatic(): bool
}

/' ----------------------------------------------------------------------- '/

/' Encapsulation of ROOT functions '/
class FunctionProxyFactory {
  -FunctionProxyFactory() <<constructor>>
  {static} +createFunctionProxy(function: TFunction, scope: TClassRef): FunctionProxy
  {static} +fromArgs(name: string, scope: TClassRef, args: FunctionCallbackInfo): FunctionProxy
}

class FunctionProxy {
  {static} -functions: map<TFunction*, CallFunc*>
  --
  {static} -processCall(method: TFunction*, args: void*, self: void*, result: void*): bool

  {static} -callConstructor(method: TFunction*, type: TClassRef, args: void*): void*
  {static} -callDestructor(type: TClassRef, self: void*): void

  {static} -callObject(method: TFunction*, self: void*, args: void*, resType: TClassRef): void*
  {static} <T> -callPrimitive(TFunction* method, void* self, void* args): T

  {static} +getCallFunc(method: TFunction*): CallFunc*
  {static} +getMethodsFromName(scope: TClassRef, name: string): vector<TFunction*>

  +FunctionProxy(address: void*, function: TFunction, scope: TClassRef) <<constructor>>
  +getType(): TFunction

  +validateArgs(args: FunctionCallbackInfo): ObjectProxy[]
  +call(args: ObjectProxy[]): ObjectProxy

}

/' ----------------------------------------------------------------------- '/

/' Encapsulation of ROOT objects and primitives '/
class ObjectProxyFactory {
  --
  -ObjectProxyFactory() <<constructor>>
  {static} +createObjectProxy(type: TDataMember, scope: TClassRef, holder: ObjectProxy): ObjectProxy
}

class ObjectProxy {
  #proxy: Persistent<Object>
  --
  +ObjectProxy(type: TDataMember, scope: TClassRef) <<constructor>>
  +getType(): TDataMember

  {abstract} +set(value: ObjectProxy)
  {abstract} +get(): Local<Value>

  {abstract} +setProxy(proxy: Local<Object>)
  {abstract} +getProxy(): Local<Object>

  {abstract} +isPrimitive(): bool
}

class BooleanProxy {
  --
  +BooleanProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class StringProxy {
  --
  +StringProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class NumberProxy {
  --
  +NumberProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class PrimitiveProxy {
  --
  +PrimitiveProxy(type: TDataMember, scope: TClassRef) <<constructor>>
  +isPrimitive(): bool
}

class ArrayProxy {
  --
  +ArrayProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class PointerProxy {
--
+PointerProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class StructProxy {
--
+StructProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class EnumProxy {
--
+EnumProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

class TemplateProxy {
--
+TemplateProxy(type: TDataMember, scope: TClassRef) <<constructor>>
}

@enduml
