unit Myc.Fmx.AstEditor.Visualizer;

interface

uses
    System.SysUtils,
    System.Classes,
    FMX.Controls,
    Myc.Data.Value,
    Myc.Ast.Nodes,
    Myc.Ast.Visitor,
    Myc.Fmx.AstEditor.Render, // Virtual Engine
    Myc.Fmx.AstEditor.Node, // View Nodes
    Myc.Fmx.AstEditor.Workspace; // Host

type
    // Implementation of the Factory/Visitor for the Virtual Tree
    // Uses TAstVisitor<TAstViewNode> which now uses closures for dispatch.
    TAstVisualizer = class(TAstVisitor<TAstViewNode>, IAstVisualizer)
    private
        FExprDepth: Integer;
        FParentNode: TVisualNode;
        FWorkspace: TWorkspace;

        function CallAccept(const Node: IAstNode): TAstViewNode;

        // IAstVisualizer Implementation
        function GetExprDepth: Integer;
        function GetParentNode: TVisualNode;
        function GetWorkspace: TWorkspace;

    protected
        // Setup registry using closures
        procedure SetupHandlers; override;

        // --- Visitor Implementations (Strict IAstNode signature) ---
        function VisitConstant(const Node: IAstNode): TAstViewNode;
        function VisitIdentifier(const Node: IAstNode): TAstViewNode;
        function VisitKeyword(const Node: IAstNode): TAstViewNode;

        // Lists
        function VisitParameterList(const Node: IAstNode): TAstViewNode;
        function VisitArgumentList(const Node: IAstNode): TAstViewNode;
        function VisitExpressionList(const Node: IAstNode): TAstViewNode;
        function VisitRecordFieldList(const Node: IAstNode): TAstViewNode;
        function VisitRecordField(const Node: IAstNode): TAstViewNode;

        // Control Flow
        function VisitIfExpression(const Node: IAstNode): TAstViewNode;
        function VisitCondExpression(const Node: IAstNode): TAstViewNode;
        function VisitBlockExpression(const Node: IAstNode): TAstViewNode;
        function VisitRecurNode(const Node: IAstNode): TAstViewNode;
        function VisitNop(const Node: IAstNode): TAstViewNode;

        // Functions
        function VisitLambdaExpression(const Node: IAstNode): TAstViewNode;
        function VisitFunctionCall(const Node: IAstNode): TAstViewNode;
        function VisitMacroExpansionNode(const Node: IAstNode): TAstViewNode;

        // Declarations
        function VisitVariableDeclaration(const Node: IAstNode): TAstViewNode;
        function VisitAssignment(const Node: IAstNode): TAstViewNode;
        function VisitMacroDefinition(const Node: IAstNode): TAstViewNode;

        // Metaprogramming
        function VisitQuasiquote(const Node: IAstNode): TAstViewNode;
        function VisitUnquote(const Node: IAstNode): TAstViewNode;
        function VisitUnquoteSplicing(const Node: IAstNode): TAstViewNode;

        // Data Access
        function VisitIndexer(const Node: IAstNode): TAstViewNode;
        function VisitMemberAccess(const Node: IAstNode): TAstViewNode;
        function VisitRecordLiteral(const Node: IAstNode): TAstViewNode;

        // Series
        function VisitCreateSeries(const Node: IAstNode): TAstViewNode;
        function VisitAddSeriesItem(const Node: IAstNode): TAstViewNode;
        function VisitSeriesLength(const Node: IAstNode): TAstViewNode;

        // Pipes
        function VisitPipeInput(const Node: IAstNode): TAstViewNode;
        function VisitPipeSelectorList(const Node: IAstNode): TAstViewNode;
        function VisitPipeInputList(const Node: IAstNode): TAstViewNode;
        function VisitPipe(const Node: IAstNode): TAstViewNode;

    public
        constructor Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer);
        destructor Destroy; override;

        function Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer;

        property ExprDepth: Integer read GetExprDepth;
        property ParentNode: TVisualNode read GetParentNode;
        property Workspace: TWorkspace read GetWorkspace;
    end;

implementation

uses
    System.StrUtils,
    Myc.Fmx.AstEditor.Handlers,
    Myc.Fmx.AstEditor.Handlers.Data,
    Myc.Fmx.AstEditor.Handlers.Control,
    Myc.Fmx.AstEditor.Handlers.Primitives,
    Myc.Fmx.AstEditor.Handlers.Lists;

function IsStandardOperator(const Name: string): Boolean;
begin
    Result := MatchStr(Name, ['+', '-', '*', '/', 'div', 'mod', '=', '<>', '<', '>', '<=', '>=', 'and', 'or', 'xor', 'not', 'shl', 'shr']);
end;

{ TAstVisualizer }

constructor TAstVisualizer.Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer);
begin
    inherited Create; // Calls SetupHandlers
    FWorkspace := AWorkspace;
    FParentNode := AParentNode;
    FExprDepth := AExprDepth;
end;

destructor TAstVisualizer.Destroy;
begin
    inherited;
end;

procedure TAstVisualizer.SetupHandlers;
begin
    // Core Primitives
    Register(akConstant, VisitConstant);
    Register(akIdentifier, VisitIdentifier);
    Register(akKeyword, VisitKeyword);
    Register(akNop, VisitNop);

    // Lists
    Register(akParameterList, VisitParameterList);
    Register(akArgumentList, VisitArgumentList);
    Register(akExpressionList, VisitExpressionList);
    Register(akRecordFieldList, VisitRecordFieldList);
    Register(akRecordField, VisitRecordField);

    // Control Flow
    Register(akIfExpression, VisitIfExpression);
    Register(akCondExpression, VisitCondExpression);
    Register(akBlockExpression, VisitBlockExpression);
    Register(akRecur, VisitRecurNode);

    // Functions
    Register(akLambdaExpression, VisitLambdaExpression);
    Register(akFunctionCall, VisitFunctionCall);
    Register(akMacroExpansion, VisitMacroExpansionNode);

    // Declarations
    Register(akVariableDeclaration, VisitVariableDeclaration);
    Register(akAssignment, VisitAssignment);
    Register(akMacroDefinition, VisitMacroDefinition);

    // Metaprogramming
    Register(akQuasiquote, VisitQuasiquote);
    Register(akUnquote, VisitUnquote);
    Register(akUnquoteSplicing, VisitUnquoteSplicing);

    // Data Access
    Register(akIndexer, VisitIndexer);
    Register(akMemberAccess, VisitMemberAccess);
    Register(akRecordLiteral, VisitRecordLiteral);

    // Series
    Register(akCreateSeries, VisitCreateSeries);
    Register(akAddSeriesItem, VisitAddSeriesItem);
    Register(akSeriesLength, VisitSeriesLength);

    // Pipes
    Register(akPipeInput, VisitPipeInput);
    Register(akPipeSelectorList, VisitPipeSelectorList);
    Register(akPipeInputList, VisitPipeInputList);
    Register(akPipe, VisitPipe);
end;

function TAstVisualizer.CallAccept(const Node: IAstNode): TAstViewNode;
var
    dataValue: TDataValue;
begin
    if not Assigned(Node) then
        exit(nil);

    dataValue := Node.Accept(Self);

    if dataValue.Kind = vkGeneric then
        Result := dataValue.AsGeneric<TAstViewNode>
    else
        Result := nil;
end;

function TAstVisualizer.Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer;
begin
    Result := TAstVisualizer.Create(FWorkspace, ParentNode, ExprDepth);
end;

function TAstVisualizer.GetExprDepth: Integer;
begin
    Result := FExprDepth;
end;

function TAstVisualizer.GetParentNode: TVisualNode;
begin
    Result := FParentNode;
end;

function TAstVisualizer.GetWorkspace: TWorkspace;
begin
    Result := FWorkspace;
end;

// --- Visitor Implementations (Cast-heavy for efficiency) ---

function TAstVisualizer.VisitConstant(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TConstantNodeHandler.Create(Node.AsConstant));
end;

function TAstVisualizer.VisitIdentifier(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TIdentifierNodeHandler.Create(Node.AsIdentifier));
end;

function TAstVisualizer.VisitKeyword(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TKeywordNodeHandler.Create(Node.AsKeyword));
end;

function TAstVisualizer.VisitNop(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node.AsNop));
end;

// Lists

function TAstVisualizer.VisitParameterList(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TParameterListHandler.Create(Node.AsParameterList));
end;

function TAstVisualizer.VisitArgumentList(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TArgumentListHandler.Create(Node.AsArgumentList));
end;

function TAstVisualizer.VisitExpressionList(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TExpressionListHandler.Create(Node.AsExpressionList));
end;

function TAstVisualizer.VisitRecordFieldList(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TRecordFieldListHandler.Create(Node.AsRecordFieldList));
end;

function TAstVisualizer.VisitRecordField(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TRecordFieldHandler.Create(Node.AsRecordField));
end;

// Control Flow

function TAstVisualizer.VisitBlockExpression(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TBlockExpressionNodeHandler.Create(Node.AsBlockExpression));
end;

function TAstVisualizer.VisitIfExpression(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TIfExpressionNodeHandler.Create(Node.AsIfExpression));
end;

function TAstVisualizer.VisitCondExpression(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TCondExpressionNodeHandler.Create(Node.AsCondExpression));
end;

function TAstVisualizer.VisitRecurNode(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TRecurNodeHandler.Create(Node.AsRecur));
end;

// Functions

function TAstVisualizer.VisitLambdaExpression(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TLambdaExpressionNodeHandler.Create(Node.AsLambdaExpression));
end;

function TAstVisualizer.VisitFunctionCall(const Node: IAstNode): TAstViewNode;
var
    C: IFunctionCallNode;
    calleeName: string;
    isOp: Boolean;
begin
    C := Node.AsFunctionCall;
    isOp := False;

    if C.Callee.Kind = akIdentifier then
    begin
        calleeName := C.Callee.AsIdentifier.Name;
        isOp := IsStandardOperator(calleeName);
    end
    else if C.Callee.Kind = akKeyword then
    begin
        calleeName := C.Callee.AsKeyword.Value.Name;
        isOp := IsStandardOperator(calleeName);
    end;

    if isOp then
        Result := TAstViewNode.Create(Self, TOperatorCallHandler.Create(C))
    else
        Result := TAstViewNode.Create(Self, TFunctionCallNodeHandler.Create(C));
end;

function TAstVisualizer.VisitMacroExpansionNode(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TMacroExpansionNodeHandler.Create(Node.AsMacroExpansion));
end;

// Declarations

function TAstVisualizer.VisitVariableDeclaration(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TVariableDeclarationNodeHandler.Create(Node.AsVariableDeclaration));
end;

function TAstVisualizer.VisitAssignment(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TAssignmentNodeHandler.Create(Node.AsAssignment));
end;

function TAstVisualizer.VisitMacroDefinition(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TMacroDefinitionNodeHandler.Create(Node.AsMacroDefinition));
end;

// Metaprogramming

function TAstVisualizer.VisitQuasiquote(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TQuasiquoteNodeHandler.Create(Node.AsQuasiquote));
end;

function TAstVisualizer.VisitUnquote(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TUnquoteNodeHandler.Create(Node.AsUnquote));
end;

function TAstVisualizer.VisitUnquoteSplicing(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TUnquoteSplicingNodeHandler.Create(Node.AsUnquoteSplicing));
end;

// Data Access

function TAstVisualizer.VisitIndexer(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TIndexerNodeHandler.Create(Node.AsIndexer));
end;

function TAstVisualizer.VisitMemberAccess(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TMemberAccessNodeHandler.Create(Node.AsMemberAccess));
end;

function TAstVisualizer.VisitRecordLiteral(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TRecordLiteralNodeHandler.Create(Node.AsRecordLiteral));
end;

// Series

function TAstVisualizer.VisitCreateSeries(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TCreateSeriesNodeHandler.Create(Node.AsCreateSeries));
end;

function TAstVisualizer.VisitAddSeriesItem(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TAddSeriesItemNodeHandler.Create(Node.AsAddSeriesItem));
end;

function TAstVisualizer.VisitSeriesLength(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TSeriesLengthNodeHandler.Create(Node.AsSeriesLength));
end;

// Pipes (Fallback to Nop/Placeholder visualization until specific handlers are implemented)

function TAstVisualizer.VisitPipeInput(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node.AsNop));
end;

function TAstVisualizer.VisitPipeSelectorList(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node.AsNop));
end;

function TAstVisualizer.VisitPipeInputList(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node.AsNop));
end;

function TAstVisualizer.VisitPipe(const Node: IAstNode): TAstViewNode;
begin
    Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node.AsNop));
end;

end.
