// components/workflow/canvas/wf-canvas.component.ts
import { Component, ViewChild, inject, HostListener, } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LabelEditorComponent } from './label-editor.component';
import { LabelManagementService } from '../services/label-management.service';
import { SwimlaneLabelComponent } from './swimlane-label.component';
import { SwimLanePopupComponent } from './swimlane-popup.component';
import { SwimlaneStatsService } from '../services/swimlane-stats.service';
import { KeyboardHandlerService } from '../services/keyboard-handler.service';
import { NodeSelectorComponent } from './node-selector.component';
import { NodePreconditionService, } from '../services/node-precondition.service';
import * as i0 from "@angular/core";
import * as i1 from "../services/wf-facade.service";
import * as i2 from "@angular/common";
export class WFCanvasComponent {
    facade;
    containerRef;
    canvasRef;
    labelService = inject(LabelManagementService);
    swimlaneStats = inject(SwimlaneStatsService);
    keyboardHandler = inject(KeyboardHandlerService);
    preconditionService = inject(NodePreconditionService);
    hoveredSegment = null;
    constructor(facade) {
        this.facade = facade;
    }
    onKeyDown(event) {
        // Only handle keyboard events if the canvas is focused
        if (this.containerRef.nativeElement.contains(document.activeElement)) {
            this.keyboardHandler.handleKeyDown(event);
        }
    }
    // Add click handler to ensure the canvas can receive keyboard events
    onClick() {
        this.containerRef.nativeElement.focus();
    }
    updateLabel(objectId, newLabel) {
        this.labelService.updateLabel(objectId, newLabel);
    }
    // Event handlers
    onMouseDown(event) {
        this.facade.handleMouseDown(event, this.canvasRef);
    }
    onMouseMove(event) {
        this.facade.handleMouseMove(event, this.canvasRef);
    }
    onMouseUp(event) {
        this.facade.handleMouseUp(event, this.canvasRef);
    }
    onMouseLeave() {
        this.facade.handleMouseLeave();
    }
    onSwimlaneAddClick(event, swimlane) {
        const rect = this.canvasRef.nativeElement.getBoundingClientRect();
        const position = {
            x: event.clientX - rect.left + 20,
            y: event.clientY - rect.top,
        };
        this.swimlaneStats.openPopup(position, swimlane.id);
    }
    onPopupAction(actionId) {
        const swimlaneId = this.swimlaneStats.popupStatus().swimlaneId;
        if (!swimlaneId)
            return;
        switch (actionId) {
            case 'add-above':
                // Handle adding swimlane above
                break;
            case 'add-below':
                // Handle adding swimlane below
                break;
            case 'delete':
                // Handle deletion
                break;
        }
    }
    getSegmentPath(start, end) {
        return `M ${start.x} ${start.y} L ${end.x} ${end.y}`;
    }
    isSegmentHovered(connectionId, index) {
        return (this.hoveredSegment?.connectionId === connectionId &&
            this.hoveredSegment?.index === index);
    }
    onSegmentMouseDown(event, connectionId, segmentIndex) {
        event.stopPropagation();
        this.facade.handleSegmentMouseDown(event, this.canvasRef, connectionId, segmentIndex);
    }
    onNodeSelected(data) {
        this.facade.finalizeNodeCreation(data);
    }
    onNodeSelectionCancelled() {
        this.facade.preconditionService.clearPendingNode();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WFCanvasComponent, deps: [{ token: i1.WorkflowFacadeService }], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: WFCanvasComponent, isStandalone: true, selector: "wf-canvas", host: { listeners: { "window:keydown": "onKeyDown($event)", "click": "onClick()" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true }, { propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }], ngImport: i0, template: `
    <div
      class="canvas-container"
      #container
      [class.connecting]="facade.canvasState().isConnecting"
      (mousedown)="onMouseDown($event)"
      (mousemove)="onMouseMove($event)"
      (mouseup)="onMouseUp($event)"
      (mouseleave)="onMouseLeave()"
    >
      <svg
        #canvas
        [attr.width]="facade.canvasState().width"
        [attr.height]="facade.canvasState().height"
      >
        <!-- Grid Pattern -->
        <defs>
          <pattern
            id="grid"
            [attr.width]="facade.canvasState().gridSize"
            [attr.height]="facade.canvasState().gridSize"
            patternUnits="userSpaceOnUse"
          >
            <path
              [attr.d]="facade.getGridPattern().path.d"
              [ngStyle]="facade.getGridPattern().path.style"
            />
          </pattern>
        </defs>

        <!-- Background grid -->
        <rect width="100%" height="100%" fill="url(#grid)" />

        <!-- Swimlanes -->
        @for (swimlane of facade.swimlanes(); track swimlane.id) {
        <g [attr.transform]="facade.getNodeTransforms(swimlane).node">
          <rect
            [attr.width]="swimlane.size.width"
            [attr.height]="swimlane.size.height"
            [ngStyle]="facade.rendering.getSwimlaneStyle()"
          />
          <!-- <text
            x="100"
            y="20"
            [ngStyle]="facade.rendering.getLabelStyle('swimlane')"
          >
            {{ swimlane.label }}
          </text> -->
          <!-- <foreignObject
            [attr.x]="labelService.getLabelPosition(swimlane).x"
            [attr.y]="labelService.getLabelPosition(swimlane).y"
            width="150"
            height="40"
            style="overflow: visible;"
          >
            <wf-label-editor
              [label]="swimlane.label || 'New Swimlane'"
              [x]="0"
              [y]="0"
              [isSwimlane]="true"
              (labelChange)="updateLabel(swimlane.id, $event)"
            />
          </foreignObject> -->

          <!-- <g
            wf-swimlane-label
            [label]="swimlane.label"
            [count]="swimlaneStats.getNodeCount(swimlane.id)"
            [x]="20"
            [y]="swimlane.size.height - 20"
            (addClick)="onSwimlaneAddClick($event, swimlane)"
            (labelChange)="updateLabel(swimlane.id, $event)"
          /> -->

          <g transform="translate(30, 20)">
            <g
              wf-swimlane-label
              [label]="swimlane.label"
              [count]="swimlaneStats.getNodeCount(swimlane.id)"
              (addClick)="onSwimlaneAddClick($event, swimlane)"
              (labelChange)="updateLabel(swimlane.id, $event)"
            />
          </g>

          <!-- <foreignObject
            [attr.x]="50"
            [attr.y]="20"
            width="150"
            height="40"
            style="overflow: visible;"
          >
            <wf-label-editor
              [label]="swimlane.label || 'New Swimlane'"
              [x]="0"
              [y]="0"
              [isSwimlane]="true"
              (labelChange)="updateLabel(swimlane.id, $event)"
            />
          </foreignObject> -->
        </g>
        }

        <!-- Connections with labels -->
        @for (connection of facade.connections(); track connection.id) {
        <g
          class="connection"
          [class.selected]="facade.selection.isSelected(connection.id)"
        >
          <!-- <path
            [attr.d]="facade.getConnectionPath(connection.points)"
            [ngStyle]="
              facade.getConnectionStyle(
                facade.selection.isSelected(connection.id)
              )
            "
          /> -->
          <!-- Complete connection path with arrowhead -->
          <path
            [attr.d]="facade.getConnectionPath(connection.points)"
            [ngStyle]="
              facade.getConnectionStyle(
                facade.selection.isSelected(connection.id)
              )
            "
          />
          <!-- Render segments -->
          @for (point of connection.points; let i = $index; track i) { @if (i <
          connection.points.length - 1) {
          <!-- Interactive segment -->
          <!-- <path
            [attr.d]="getSegmentPath(point, connection.points[i + 1])"
            [ngStyle]="
              facade.getConnectionStyle(
                facade.selection.isSelected(connection.id)
              )
            "
            [style.cursor]="facade.getSegmentCursor(connection.id, i)"
            (mousedown)="onSegmentMouseDown($event, connection.id, i)"
            class="connection-segment"
          /> -->
          <g
            class="segment-group"
            (mouseenter)="
              hoveredSegment = { connectionId: connection.id, index: i }
            "
            (mouseleave)="hoveredSegment = null"
          >
            <!-- Hit detection area -->
            <path
              [attr.d]="getSegmentPath(point, connection.points[i + 1])"
              class="segment-hitarea"
              [style.cursor]="facade.getSegmentCursor(connection.id, i)"
              (mousedown)="onSegmentMouseDown($event, connection.id, i)"
            />

            <!-- Visible segment -->
            <path
              [attr.d]="getSegmentPath(point, connection.points[i + 1])"
              [ngStyle]="
                facade.rendering.getConnectionSegmentStyle(
                  facade.selection.isSelected(connection.id),
                  isSegmentHovered(connection.id, i)
                )
              "
            />
          </g>
          } }
          <!-- Connection Label -->
          @if (connection.fromId && connection.toId) {
          <foreignObject
            [attr.x]="labelService.getLabelPosition(connection).x"
            [attr.y]="labelService.getLabelPosition(connection).y"
            width="150"
            height="40"
            style="overflow: visible; pointer-events: all;"
            [attr.transform]="'translate(-10, -10)'"
          >
            <wf-label-editor
              [label]="connection.label || 'New Action'"
              [x]="0"
              [y]="0"
              [isConnection]="true"
              (labelChange)="updateLabel(connection.id, $event)"
            />
          </foreignObject>
          }
        </g>
        }

        <!-- Nodes -->
        @for (node of facade.nodes(); track node.id) {
        <g
          [attr.transform]="facade.getNodeTransforms(node).node"
          [class.selected]="facade.selection.isSelected(node.id)"
          [class.dragging]="
            facade.canvasState().isDragging &&
            facade.selection.isSelected(node.id)
          "
        >
          @switch (node.type) { @case ('start') {
          <path
            [attr.d]="facade.getStartNodePaths().circle"
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          @if (!facade.hasOutgoingConnections(node.id)) {
          <path
            [attr.d]="facade.getStartNodePaths().arrow"
            [attr.transform]="facade.getNodeTransforms(node).arrow"
            fill="#D36CFF"
          />
          } }@case ('form') {
          <path
            [attr.d]="facade.rendering.generateNodePath(node)"
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } @case ('decision') {
          <path
            [attr.d]="
              facade.rendering.getDecisionPath(
                node.size.width,
                node.size.height
              )
            "
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } @case ('subflow') {
          <path
            [attr.d]="
              facade.rendering.getSubflowPath(node.size.width, node.size.height)
            "
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } @default {
          <rect
            [attr.width]="node.size.width"
            [attr.height]="node.size.height"
            [attr.rx]="4"
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } }

          <!-- Node label -->
          <!-- <text
            [attr.x]="node.size.width / 2"
            [attr.y]="node.size.height / 2"
            [ngStyle]="facade.rendering.getLabelStyle(node.type)"
          >
            {{ node.label }}
          </text> -->
          <foreignObject
            [attr.x]="0"
            [attr.y]="0"
            [attr.width]="node.size.width"
            [attr.height]="node.size.height"
            style="overflow: visible;"
          >
            <wf-label-editor
              [label]="node.label"
              [x]="labelService.getSVGTextPosition(node).x"
              [y]="labelService.getSVGTextPosition(node).y"
              (labelChange)="updateLabel(node.id, $event)"
            />
          </foreignObject>
        </g>
        }

        <!-- Connection preview with arrowhead -->
        @if (facade.canvasState().connectionPreview) {
        <path
          [attr.d]="facade.getConnectionPreviewPath()"
          [ngStyle]="facade.rendering.getConnectionPreviewStyle()"
        />
        }
      </svg>

      @if (swimlaneStats.popupStatus().isOpen) {
      <wf-swimlane-popup
        [position]="swimlaneStats.popupStatus().position"
        (close)="swimlaneStats.closePopup()"
        (actionSelected)="onPopupAction($event)"
      />
      }
    </div>

    <wf-node-selector
      (select)="onNodeSelected($event)"
      (cancel)="onNodeSelectionCancelled()"
    />
  `, isInline: true, styles: [".canvas-container{flex:1;overflow:auto;position:relative;background:#fff}.canvas-container.connecting{cursor:crosshair}.connection path{stroke:#d36cff;stroke-width:2;fill:none;pointer-events:none}.connection.selected path{stroke-width:3}.selected :not(text){stroke-width:3}.dragging{cursor:grabbing}.connection{pointer-events:none}.segment-group{pointer-events:all}.segment-hitarea{stroke:transparent;stroke-width:10;fill:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: LabelEditorComponent, selector: "wf-label-editor", inputs: ["label", "x", "y", "isConnection", "isSwimlane"], outputs: ["labelChange"] }, { kind: "component", type: SwimlaneLabelComponent, selector: "[wf-swimlane-label]", inputs: ["label", "count"], outputs: ["addClick", "labelChange"] }, { kind: "component", type: SwimLanePopupComponent, selector: "wf-swimlane-popup", inputs: ["position"], outputs: ["close", "actionSelected"] }, { kind: "component", type: NodeSelectorComponent, selector: "wf-node-selector", outputs: ["select"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WFCanvasComponent, decorators: [{
            type: Component,
            args: [{ selector: 'wf-canvas', standalone: true, imports: [
                        CommonModule,
                        LabelEditorComponent,
                        SwimlaneLabelComponent,
                        SwimLanePopupComponent,
                        NodeSelectorComponent,
                    ], template: `
    <div
      class="canvas-container"
      #container
      [class.connecting]="facade.canvasState().isConnecting"
      (mousedown)="onMouseDown($event)"
      (mousemove)="onMouseMove($event)"
      (mouseup)="onMouseUp($event)"
      (mouseleave)="onMouseLeave()"
    >
      <svg
        #canvas
        [attr.width]="facade.canvasState().width"
        [attr.height]="facade.canvasState().height"
      >
        <!-- Grid Pattern -->
        <defs>
          <pattern
            id="grid"
            [attr.width]="facade.canvasState().gridSize"
            [attr.height]="facade.canvasState().gridSize"
            patternUnits="userSpaceOnUse"
          >
            <path
              [attr.d]="facade.getGridPattern().path.d"
              [ngStyle]="facade.getGridPattern().path.style"
            />
          </pattern>
        </defs>

        <!-- Background grid -->
        <rect width="100%" height="100%" fill="url(#grid)" />

        <!-- Swimlanes -->
        @for (swimlane of facade.swimlanes(); track swimlane.id) {
        <g [attr.transform]="facade.getNodeTransforms(swimlane).node">
          <rect
            [attr.width]="swimlane.size.width"
            [attr.height]="swimlane.size.height"
            [ngStyle]="facade.rendering.getSwimlaneStyle()"
          />
          <!-- <text
            x="100"
            y="20"
            [ngStyle]="facade.rendering.getLabelStyle('swimlane')"
          >
            {{ swimlane.label }}
          </text> -->
          <!-- <foreignObject
            [attr.x]="labelService.getLabelPosition(swimlane).x"
            [attr.y]="labelService.getLabelPosition(swimlane).y"
            width="150"
            height="40"
            style="overflow: visible;"
          >
            <wf-label-editor
              [label]="swimlane.label || 'New Swimlane'"
              [x]="0"
              [y]="0"
              [isSwimlane]="true"
              (labelChange)="updateLabel(swimlane.id, $event)"
            />
          </foreignObject> -->

          <!-- <g
            wf-swimlane-label
            [label]="swimlane.label"
            [count]="swimlaneStats.getNodeCount(swimlane.id)"
            [x]="20"
            [y]="swimlane.size.height - 20"
            (addClick)="onSwimlaneAddClick($event, swimlane)"
            (labelChange)="updateLabel(swimlane.id, $event)"
          /> -->

          <g transform="translate(30, 20)">
            <g
              wf-swimlane-label
              [label]="swimlane.label"
              [count]="swimlaneStats.getNodeCount(swimlane.id)"
              (addClick)="onSwimlaneAddClick($event, swimlane)"
              (labelChange)="updateLabel(swimlane.id, $event)"
            />
          </g>

          <!-- <foreignObject
            [attr.x]="50"
            [attr.y]="20"
            width="150"
            height="40"
            style="overflow: visible;"
          >
            <wf-label-editor
              [label]="swimlane.label || 'New Swimlane'"
              [x]="0"
              [y]="0"
              [isSwimlane]="true"
              (labelChange)="updateLabel(swimlane.id, $event)"
            />
          </foreignObject> -->
        </g>
        }

        <!-- Connections with labels -->
        @for (connection of facade.connections(); track connection.id) {
        <g
          class="connection"
          [class.selected]="facade.selection.isSelected(connection.id)"
        >
          <!-- <path
            [attr.d]="facade.getConnectionPath(connection.points)"
            [ngStyle]="
              facade.getConnectionStyle(
                facade.selection.isSelected(connection.id)
              )
            "
          /> -->
          <!-- Complete connection path with arrowhead -->
          <path
            [attr.d]="facade.getConnectionPath(connection.points)"
            [ngStyle]="
              facade.getConnectionStyle(
                facade.selection.isSelected(connection.id)
              )
            "
          />
          <!-- Render segments -->
          @for (point of connection.points; let i = $index; track i) { @if (i <
          connection.points.length - 1) {
          <!-- Interactive segment -->
          <!-- <path
            [attr.d]="getSegmentPath(point, connection.points[i + 1])"
            [ngStyle]="
              facade.getConnectionStyle(
                facade.selection.isSelected(connection.id)
              )
            "
            [style.cursor]="facade.getSegmentCursor(connection.id, i)"
            (mousedown)="onSegmentMouseDown($event, connection.id, i)"
            class="connection-segment"
          /> -->
          <g
            class="segment-group"
            (mouseenter)="
              hoveredSegment = { connectionId: connection.id, index: i }
            "
            (mouseleave)="hoveredSegment = null"
          >
            <!-- Hit detection area -->
            <path
              [attr.d]="getSegmentPath(point, connection.points[i + 1])"
              class="segment-hitarea"
              [style.cursor]="facade.getSegmentCursor(connection.id, i)"
              (mousedown)="onSegmentMouseDown($event, connection.id, i)"
            />

            <!-- Visible segment -->
            <path
              [attr.d]="getSegmentPath(point, connection.points[i + 1])"
              [ngStyle]="
                facade.rendering.getConnectionSegmentStyle(
                  facade.selection.isSelected(connection.id),
                  isSegmentHovered(connection.id, i)
                )
              "
            />
          </g>
          } }
          <!-- Connection Label -->
          @if (connection.fromId && connection.toId) {
          <foreignObject
            [attr.x]="labelService.getLabelPosition(connection).x"
            [attr.y]="labelService.getLabelPosition(connection).y"
            width="150"
            height="40"
            style="overflow: visible; pointer-events: all;"
            [attr.transform]="'translate(-10, -10)'"
          >
            <wf-label-editor
              [label]="connection.label || 'New Action'"
              [x]="0"
              [y]="0"
              [isConnection]="true"
              (labelChange)="updateLabel(connection.id, $event)"
            />
          </foreignObject>
          }
        </g>
        }

        <!-- Nodes -->
        @for (node of facade.nodes(); track node.id) {
        <g
          [attr.transform]="facade.getNodeTransforms(node).node"
          [class.selected]="facade.selection.isSelected(node.id)"
          [class.dragging]="
            facade.canvasState().isDragging &&
            facade.selection.isSelected(node.id)
          "
        >
          @switch (node.type) { @case ('start') {
          <path
            [attr.d]="facade.getStartNodePaths().circle"
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          @if (!facade.hasOutgoingConnections(node.id)) {
          <path
            [attr.d]="facade.getStartNodePaths().arrow"
            [attr.transform]="facade.getNodeTransforms(node).arrow"
            fill="#D36CFF"
          />
          } }@case ('form') {
          <path
            [attr.d]="facade.rendering.generateNodePath(node)"
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } @case ('decision') {
          <path
            [attr.d]="
              facade.rendering.getDecisionPath(
                node.size.width,
                node.size.height
              )
            "
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } @case ('subflow') {
          <path
            [attr.d]="
              facade.rendering.getSubflowPath(node.size.width, node.size.height)
            "
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } @default {
          <rect
            [attr.width]="node.size.width"
            [attr.height]="node.size.height"
            [attr.rx]="4"
            [ngStyle]="
              facade.getNodeStyle(facade.selection.isSelected(node.id))
            "
          />
          } }

          <!-- Node label -->
          <!-- <text
            [attr.x]="node.size.width / 2"
            [attr.y]="node.size.height / 2"
            [ngStyle]="facade.rendering.getLabelStyle(node.type)"
          >
            {{ node.label }}
          </text> -->
          <foreignObject
            [attr.x]="0"
            [attr.y]="0"
            [attr.width]="node.size.width"
            [attr.height]="node.size.height"
            style="overflow: visible;"
          >
            <wf-label-editor
              [label]="node.label"
              [x]="labelService.getSVGTextPosition(node).x"
              [y]="labelService.getSVGTextPosition(node).y"
              (labelChange)="updateLabel(node.id, $event)"
            />
          </foreignObject>
        </g>
        }

        <!-- Connection preview with arrowhead -->
        @if (facade.canvasState().connectionPreview) {
        <path
          [attr.d]="facade.getConnectionPreviewPath()"
          [ngStyle]="facade.rendering.getConnectionPreviewStyle()"
        />
        }
      </svg>

      @if (swimlaneStats.popupStatus().isOpen) {
      <wf-swimlane-popup
        [position]="swimlaneStats.popupStatus().position"
        (close)="swimlaneStats.closePopup()"
        (actionSelected)="onPopupAction($event)"
      />
      }
    </div>

    <wf-node-selector
      (select)="onNodeSelected($event)"
      (cancel)="onNodeSelectionCancelled()"
    />
  `, styles: [".canvas-container{flex:1;overflow:auto;position:relative;background:#fff}.canvas-container.connecting{cursor:crosshair}.connection path{stroke:#d36cff;stroke-width:2;fill:none;pointer-events:none}.connection.selected path{stroke-width:3}.selected :not(text){stroke-width:3}.dragging{cursor:grabbing}.connection{pointer-events:none}.segment-group{pointer-events:all}.segment-hitarea{stroke:transparent;stroke-width:10;fill:none}\n"] }]
        }], ctorParameters: () => [{ type: i1.WorkflowFacadeService }], propDecorators: { containerRef: [{
                type: ViewChild,
                args: ['container']
            }], canvasRef: [{
                type: ViewChild,
                args: ['canvas']
            }], onKeyDown: [{
                type: HostListener,
                args: ['window:keydown', ['$event']]
            }], onClick: [{
                type: HostListener,
                args: ['click']
            }] } });
//# sourceMappingURL=data:application/json;base64, 