"""
BreakPilot Studio - Workflow/BPMN Module

BPMN 2.0 Prozess-Editor mit bpmn-js Integration.
Ermoeglicht das Modellieren, Speichern und Deployen von Geschaeftsprozessen.
"""


class WorkflowModule:
    """BPMN Workflow Editor Modul fuer BreakPilot Studio."""

    @staticmethod
    def get_css() -> str:
        """CSS fuer das Workflow/BPMN Panel."""
        return """
/* ==========================================
   WORKFLOW/BPMN MODULE
   ========================================== */

#panel-workflow {
  display: none;
  flex-direction: column;
  padding: 24px;
  min-height: calc(100vh - 104px);
  height: calc(100vh - 104px);
}

#panel-workflow.active {
  display: flex;
}

/* Header */
.workflow-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 20px;
}

.workflow-title {
  font-size: 24px;
  font-weight: 700;
  color: var(--bp-text);
  margin-bottom: 4px;
}

.workflow-subtitle {
  font-size: 14px;
  color: var(--bp-text-muted);
}

/* Toolbar */
.workflow-toolbar {
  display: flex;
  gap: 12px;
  margin-bottom: 16px;
  padding: 12px 16px;
  background: var(--bp-surface-elevated);
  border-radius: 8px;
  border: 1px solid var(--bp-border);
  flex-wrap: wrap;
}

.workflow-toolbar-group {
  display: flex;
  gap: 8px;
  align-items: center;
}

.workflow-toolbar-separator {
  width: 1px;
  height: 24px;
  background: var(--bp-border);
  margin: 0 8px;
}

.workflow-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
  border: 1px solid var(--bp-border);
  background: var(--bp-surface);
  color: var(--bp-text);
}

.workflow-btn:hover {
  background: var(--bp-surface-elevated);
  border-color: var(--bp-primary);
}

.workflow-btn.primary {
  background: var(--bp-primary);
  border-color: var(--bp-primary);
  color: white;
}

.workflow-btn.primary:hover {
  background: var(--bp-primary-hover);
}

.workflow-btn.success {
  background: var(--bp-success);
  border-color: var(--bp-success);
  color: white;
}

.workflow-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Canvas Container */
.workflow-canvas-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--bp-border);
  border-radius: 12px;
  overflow: hidden;
  background: white;
  min-height: 400px;
}

.workflow-canvas {
  flex: 1;
  width: 100%;
  height: 100%;
}

/* bpmn-js Overrides for Dark Theme Support */
.bjs-powered-by {
  display: none !important;
}

.djs-palette {
  background: var(--bp-surface) !important;
  border-color: var(--bp-border) !important;
}

.djs-palette-entries .entry {
  color: var(--bp-text) !important;
}

/* Status Bar */
.workflow-status-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  background: var(--bp-surface);
  border-top: 1px solid var(--bp-border);
  font-size: 12px;
  color: var(--bp-text-muted);
}

.workflow-status-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.workflow-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--bp-text-muted);
}

.workflow-status-dot.connected {
  background: var(--bp-success);
}

.workflow-status-dot.disconnected {
  background: var(--bp-danger);
}

/* Process List Panel */
.workflow-processes-panel {
  position: fixed;
  top: 56px;
  right: 0;
  bottom: 0;
  width: 320px;
  background: var(--bp-surface);
  border-left: 1px solid var(--bp-border);
  transform: translateX(100%);
  transition: transform 0.3s ease;
  z-index: 60;
  display: flex;
  flex-direction: column;
}

.workflow-processes-panel.open {
  transform: translateX(0);
}

.workflow-processes-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  border-bottom: 1px solid var(--bp-border);
}

.workflow-processes-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--bp-text);
}

.workflow-processes-close {
  background: none;
  border: none;
  font-size: 20px;
  color: var(--bp-text-muted);
  cursor: pointer;
}

.workflow-processes-list {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}

.workflow-process-item {
  padding: 12px;
  background: var(--bp-surface-elevated);
  border: 1px solid var(--bp-border);
  border-radius: 8px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: all 0.2s;
}

.workflow-process-item:hover {
  border-color: var(--bp-primary);
}

.workflow-process-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--bp-text);
  margin-bottom: 4px;
}

.workflow-process-meta {
  font-size: 12px;
  color: var(--bp-text-muted);
}

/* Task Inbox Panel */
.workflow-tasks-panel {
  margin-top: 16px;
  background: var(--bp-surface-elevated);
  border: 1px solid var(--bp-border);
  border-radius: 12px;
  max-height: 300px;
  overflow: hidden;
  display: none;
}

.workflow-tasks-panel.visible {
  display: block;
}

.workflow-tasks-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid var(--bp-border);
}

.workflow-tasks-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--bp-text);
}

.workflow-tasks-count {
  padding: 2px 8px;
  background: var(--bp-primary);
  color: white;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}

.workflow-tasks-list {
  max-height: 240px;
  overflow-y: auto;
}

.workflow-task-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid var(--bp-border-subtle);
}

.workflow-task-item:last-child {
  border-bottom: none;
}

.workflow-task-info {
  flex: 1;
}

.workflow-task-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--bp-text);
  margin-bottom: 2px;
}

.workflow-task-process {
  font-size: 11px;
  color: var(--bp-text-muted);
}

.workflow-task-action {
  padding: 6px 12px;
  background: var(--bp-primary);
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
}

/* Loading Overlay */
.workflow-loading {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

.workflow-loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--bp-border);
  border-top-color: var(--bp-primary);
  border-radius: 50%;
  animation: workflow-spin 1s linear infinite;
}

@keyframes workflow-spin {
  to { transform: rotate(360deg); }
}

/* Toast Notifications */
.workflow-toast {
  position: fixed;
  bottom: 24px;
  right: 24px;
  padding: 12px 20px;
  background: var(--bp-surface);
  border: 1px solid var(--bp-border);
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  z-index: 200;
  animation: workflow-toast-in 0.3s ease;
}

.workflow-toast.success {
  border-color: var(--bp-success);
}

.workflow-toast.error {
  border-color: var(--bp-danger);
}

@keyframes workflow-toast-in {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
"""

    @staticmethod
    def get_html() -> str:
        """HTML fuer das Workflow/BPMN Panel."""
        return """
<!-- WORKFLOW/BPMN PANEL -->
<div id="panel-workflow" class="module-panel">
  <!-- Header -->
  <div class="workflow-header">
    <div>
      <h1 class="workflow-title">BPMN Workflow Editor</h1>
      <p class="workflow-subtitle">Geschaeftsprozesse modellieren und automatisieren (Camunda 7)</p>
    </div>
  </div>

  <!-- Toolbar -->
  <div class="workflow-toolbar">
    <div class="workflow-toolbar-group">
      <button class="workflow-btn primary" onclick="workflowNewDiagram()" title="Neues Diagramm">
        <span>&#10133;</span> Neu
      </button>
      <button class="workflow-btn" onclick="workflowOpenFile()" title="BPMN-Datei oeffnen">
        <span>&#128194;</span> Oeffnen
      </button>
      <input type="file" id="workflow-file-input" accept=".bpmn,.xml" style="display:none" onchange="workflowLoadFile(event)">
    </div>

    <div class="workflow-toolbar-separator"></div>

    <div class="workflow-toolbar-group">
      <button class="workflow-btn" onclick="workflowSaveXML()" title="Als XML speichern">
        <span>&#128190;</span> XML
      </button>
      <button class="workflow-btn" onclick="workflowSaveSVG()" title="Als SVG exportieren">
        <span>&#127912;</span> SVG
      </button>
    </div>

    <div class="workflow-toolbar-separator"></div>

    <div class="workflow-toolbar-group">
      <button class="workflow-btn success" onclick="workflowDeploy()" title="In Camunda deployen">
        <span>&#128640;</span> Deployen
      </button>
      <button class="workflow-btn" onclick="workflowShowProcesses()" title="Deployments anzeigen">
        <span>&#128203;</span> Prozesse
      </button>
      <button class="workflow-btn" onclick="workflowToggleTasks()" title="Offene Tasks anzeigen">
        <span>&#128221;</span> Tasks
      </button>
    </div>

    <div class="workflow-toolbar-separator"></div>

    <div class="workflow-toolbar-group">
      <button class="workflow-btn" onclick="workflowZoomIn()" title="Vergroessern">&#128269;+</button>
      <button class="workflow-btn" onclick="workflowZoomOut()" title="Verkleinern">&#128269;-</button>
      <button class="workflow-btn" onclick="workflowZoomFit()" title="Einpassen">&#9724;</button>
    </div>
  </div>

  <!-- BPMN Canvas -->
  <div class="workflow-canvas-container">
    <div class="workflow-canvas" id="workflow-canvas"></div>
    <div class="workflow-status-bar">
      <div class="workflow-status-item">
        <span class="workflow-status-dot" id="workflow-camunda-status"></span>
        <span id="workflow-camunda-status-text">Camunda: Pruefe...</span>
      </div>
      <div class="workflow-status-item">
        <span id="workflow-element-count">Elemente: 0</span>
      </div>
    </div>
  </div>

  <!-- Task Inbox (toggleable) -->
  <div class="workflow-tasks-panel" id="workflow-tasks-panel">
    <div class="workflow-tasks-header">
      <span class="workflow-tasks-title">Offene Tasks</span>
      <span class="workflow-tasks-count" id="workflow-tasks-count">0</span>
    </div>
    <div class="workflow-tasks-list" id="workflow-tasks-list">
      <div class="workflow-task-item" style="color: var(--bp-text-muted); text-align: center;">
        Keine offenen Tasks
      </div>
    </div>
  </div>
</div>

<!-- Processes Side Panel -->
<div class="workflow-processes-panel" id="workflow-processes-panel">
  <div class="workflow-processes-header">
    <span class="workflow-processes-title">Deployed Processes</span>
    <button class="workflow-processes-close" onclick="workflowHideProcesses()">&times;</button>
  </div>
  <div class="workflow-processes-list" id="workflow-processes-list">
    <div style="text-align: center; color: var(--bp-text-muted); padding: 20px;">
      Lade Prozesse...
    </div>
  </div>
</div>

<!-- bpmn-js CDN Scripts -->
<link rel="stylesheet" href="https://unpkg.com/bpmn-js@17.11.1/dist/assets/diagram-js.css">
<link rel="stylesheet" href="https://unpkg.com/bpmn-js@17.11.1/dist/assets/bpmn-js.css">
<link rel="stylesheet" href="https://unpkg.com/bpmn-js@17.11.1/dist/assets/bpmn-font/css/bpmn-embedded.css">
<script src="https://unpkg.com/bpmn-js@17.11.1/dist/bpmn-modeler.production.min.js"></script>
"""

    @staticmethod
    def get_js() -> str:
        """JavaScript fuer das Workflow/BPMN Panel."""
        return """
// ==========================================
// WORKFLOW/BPMN MODULE
// ==========================================

console.log('Workflow Module loaded');

let workflowModeler = null;
let workflowCamundaConnected = false;

// Default empty BPMN diagram
const WORKFLOW_EMPTY_BPMN = `<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
                  xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                  xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
                  xmlns:camunda="http://camunda.org/schema/1.0/bpmn"
                  id="Definitions_1"
                  targetNamespace="http://bpmn.io/schema/bpmn">
  <bpmn:process id="Process_1" name="Neuer Prozess" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1" name="Start" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
      <bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1">
        <dc:Bounds x="180" y="160" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="186" y="203" width="24" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>`;

// Initialize BPMN Modeler
async function initWorkflowModule() {
  console.log('Initializing Workflow Module...');

  const container = document.getElementById('workflow-canvas');
  if (!container) {
    console.error('Workflow canvas container not found');
    return;
  }

  // Check if BpmnJS is loaded
  if (typeof BpmnJS === 'undefined') {
    console.error('bpmn-js not loaded');
    workflowShowToast('bpmn-js konnte nicht geladen werden', 'error');
    return;
  }

  try {
    // Create modeler instance
    workflowModeler = new BpmnJS({
      container: container,
      keyboard: {
        bindTo: document
      }
    });

    // Load empty diagram
    await workflowModeler.importXML(WORKFLOW_EMPTY_BPMN);

    // Center the diagram
    const canvas = workflowModeler.get('canvas');
    canvas.zoom('fit-viewport');

    // Update element count on changes
    workflowModeler.on('elements.changed', workflowUpdateElementCount);
    workflowUpdateElementCount();

    console.log('Workflow Modeler initialized');

    // Check Camunda connection
    workflowCheckCamundaStatus();

  } catch (err) {
    console.error('Error initializing workflow modeler:', err);
    workflowShowToast('Fehler beim Initialisieren des Editors', 'error');
  }
}

// Check Camunda connection status
async function workflowCheckCamundaStatus() {
  const statusDot = document.getElementById('workflow-camunda-status');
  const statusText = document.getElementById('workflow-camunda-status-text');

  try {
    const response = await fetch('/api/bpmn/health');
    const data = await response.json();

    if (data.connected) {
      statusDot.classList.add('connected');
      statusDot.classList.remove('disconnected');
      statusText.textContent = 'Camunda: Verbunden';
      workflowCamundaConnected = true;
    } else {
      throw new Error('Not connected');
    }
  } catch (err) {
    statusDot.classList.add('disconnected');
    statusDot.classList.remove('connected');
    statusText.textContent = 'Camunda: Nicht verbunden';
    workflowCamundaConnected = false;
  }
}

// Create new diagram
async function workflowNewDiagram() {
  if (!workflowModeler) return;

  try {
    await workflowModeler.importXML(WORKFLOW_EMPTY_BPMN);
    workflowModeler.get('canvas').zoom('fit-viewport');
    workflowUpdateElementCount();
    workflowShowToast('Neues Diagramm erstellt', 'success');
  } catch (err) {
    console.error('Error creating new diagram:', err);
    workflowShowToast('Fehler beim Erstellen', 'error');
  }
}

// Open file dialog
function workflowOpenFile() {
  document.getElementById('workflow-file-input').click();
}

// Load file from input
async function workflowLoadFile(event) {
  const file = event.target.files[0];
  if (!file) return;

  try {
    const xml = await file.text();
    await workflowModeler.importXML(xml);
    workflowModeler.get('canvas').zoom('fit-viewport');
    workflowUpdateElementCount();
    workflowShowToast('Datei geladen: ' + file.name, 'success');
  } catch (err) {
    console.error('Error loading file:', err);
    workflowShowToast('Fehler beim Laden der Datei', 'error');
  }

  // Reset input
  event.target.value = '';
}

// Save as XML
async function workflowSaveXML() {
  if (!workflowModeler) return;

  try {
    const { xml } = await workflowModeler.saveXML({ format: true });
    workflowDownload(xml, 'process.bpmn', 'application/xml');
    workflowShowToast('XML exportiert', 'success');
  } catch (err) {
    console.error('Error saving XML:', err);
    workflowShowToast('Fehler beim Speichern', 'error');
  }
}

// Save as SVG
async function workflowSaveSVG() {
  if (!workflowModeler) return;

  try {
    const { svg } = await workflowModeler.saveSVG();
    workflowDownload(svg, 'process.svg', 'image/svg+xml');
    workflowShowToast('SVG exportiert', 'success');
  } catch (err) {
    console.error('Error saving SVG:', err);
    workflowShowToast('Fehler beim Speichern', 'error');
  }
}

// Deploy to Camunda
async function workflowDeploy() {
  if (!workflowModeler) return;

  if (!workflowCamundaConnected) {
    workflowShowToast('Camunda nicht verbunden', 'error');
    return;
  }

  try {
    const { xml } = await workflowModeler.saveXML({ format: true });

    // Create form data
    const formData = new FormData();
    formData.append('deployment-name', 'BreakPilot-Process-' + Date.now());
    formData.append('data', new Blob([xml], { type: 'application/octet-stream' }), 'process.bpmn');

    const response = await fetch('/api/bpmn/deployment/create', {
      method: 'POST',
      body: formData
    });

    if (response.ok) {
      const result = await response.json();
      workflowShowToast('Deployment erfolgreich: ' + result.name, 'success');
      console.log('Deployment result:', result);
    } else {
      const error = await response.text();
      throw new Error(error);
    }
  } catch (err) {
    console.error('Error deploying:', err);
    workflowShowToast('Deployment fehlgeschlagen', 'error');
  }
}

// Show deployed processes panel
async function workflowShowProcesses() {
  const panel = document.getElementById('workflow-processes-panel');
  const list = document.getElementById('workflow-processes-list');

  panel.classList.add('open');

  try {
    const response = await fetch('/api/bpmn/process-definition');
    const processes = await response.json();

    if (processes.length === 0) {
      list.innerHTML = '<div style="text-align: center; color: var(--bp-text-muted); padding: 20px;">Keine Prozesse deployed</div>';
      return;
    }

    list.innerHTML = processes.map(p => `
      <div class="workflow-process-item" onclick="workflowLoadProcess('${p.id}')">
        <div class="workflow-process-name">${p.name || p.key}</div>
        <div class="workflow-process-meta">Version ${p.version} | ${p.key}</div>
      </div>
    `).join('');

  } catch (err) {
    console.error('Error loading processes:', err);
    list.innerHTML = '<div style="text-align: center; color: var(--bp-danger); padding: 20px;">Fehler beim Laden</div>';
  }
}

// Hide processes panel
function workflowHideProcesses() {
  document.getElementById('workflow-processes-panel').classList.remove('open');
}

// Load process definition XML
async function workflowLoadProcess(definitionId) {
  try {
    const response = await fetch('/api/bpmn/process-definition/' + definitionId + '/xml');
    const data = await response.json();

    if (data.bpmn20Xml) {
      await workflowModeler.importXML(data.bpmn20Xml);
      workflowModeler.get('canvas').zoom('fit-viewport');
      workflowUpdateElementCount();
      workflowHideProcesses();
      workflowShowToast('Prozess geladen', 'success');
    }
  } catch (err) {
    console.error('Error loading process:', err);
    workflowShowToast('Fehler beim Laden des Prozesses', 'error');
  }
}

// Toggle tasks panel
function workflowToggleTasks() {
  const panel = document.getElementById('workflow-tasks-panel');
  panel.classList.toggle('visible');

  if (panel.classList.contains('visible')) {
    workflowLoadTasks();
  }
}

// Load pending tasks
async function workflowLoadTasks() {
  const list = document.getElementById('workflow-tasks-list');
  const count = document.getElementById('workflow-tasks-count');

  try {
    const response = await fetch('/api/bpmn/tasks/pending');
    const tasks = await response.json();

    count.textContent = tasks.length;

    if (tasks.length === 0) {
      list.innerHTML = '<div class="workflow-task-item" style="color: var(--bp-text-muted); text-align: center; justify-content: center;">Keine offenen Tasks</div>';
      return;
    }

    list.innerHTML = tasks.map(t => `
      <div class="workflow-task-item">
        <div class="workflow-task-info">
          <div class="workflow-task-name">${t.name}</div>
          <div class="workflow-task-process">${t.processDefinitionId || 'Prozess'}</div>
        </div>
        <button class="workflow-task-action" onclick="workflowCompleteTask('${t.id}')">Erledigen</button>
      </div>
    `).join('');

  } catch (err) {
    console.error('Error loading tasks:', err);
    list.innerHTML = '<div class="workflow-task-item" style="color: var(--bp-danger);">Fehler beim Laden</div>';
  }
}

// Complete a task
async function workflowCompleteTask(taskId) {
  try {
    const response = await fetch('/api/bpmn/task/' + taskId + '/complete', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({})
    });

    if (response.ok) {
      workflowShowToast('Task abgeschlossen', 'success');
      workflowLoadTasks();
    } else {
      throw new Error('Failed to complete task');
    }
  } catch (err) {
    console.error('Error completing task:', err);
    workflowShowToast('Fehler beim Abschliessen', 'error');
  }
}

// Zoom controls
function workflowZoomIn() {
  if (!workflowModeler) return;
  const canvas = workflowModeler.get('canvas');
  canvas.zoom(canvas.zoom() * 1.2);
}

function workflowZoomOut() {
  if (!workflowModeler) return;
  const canvas = workflowModeler.get('canvas');
  canvas.zoom(canvas.zoom() / 1.2);
}

function workflowZoomFit() {
  if (!workflowModeler) return;
  workflowModeler.get('canvas').zoom('fit-viewport');
}

// Update element count
function workflowUpdateElementCount() {
  if (!workflowModeler) return;

  const elementRegistry = workflowModeler.get('elementRegistry');
  const count = elementRegistry.getAll().length;
  document.getElementById('workflow-element-count').textContent = 'Elemente: ' + count;
}

// Download helper
function workflowDownload(content, filename, contentType) {
  const blob = new Blob([content], { type: contentType });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}

// Toast notification
function workflowShowToast(message, type = 'info') {
  const toast = document.createElement('div');
  toast.className = 'workflow-toast ' + type;
  toast.textContent = message;
  document.body.appendChild(toast);

  setTimeout(() => {
    toast.remove();
  }, 3000);
}

// Module loader function
function loadWorkflowModule() {
  console.log('Loading Workflow Module...');
  // Small delay to ensure DOM is ready
  setTimeout(initWorkflowModule, 100);
}

// Show panel function for module loader
function showWorkflowPanel() {
  loadWorkflowModule();
}

// Expose globally
window.loadWorkflowModule = loadWorkflowModule;
window.workflowNewDiagram = workflowNewDiagram;
window.workflowOpenFile = workflowOpenFile;
window.workflowLoadFile = workflowLoadFile;
window.workflowSaveXML = workflowSaveXML;
window.workflowSaveSVG = workflowSaveSVG;
window.workflowDeploy = workflowDeploy;
window.workflowShowProcesses = workflowShowProcesses;
window.workflowHideProcesses = workflowHideProcesses;
window.workflowLoadProcess = workflowLoadProcess;
window.workflowToggleTasks = workflowToggleTasks;
window.workflowCompleteTask = workflowCompleteTask;
window.workflowZoomIn = workflowZoomIn;
window.workflowZoomOut = workflowZoomOut;
window.workflowZoomFit = workflowZoomFit;
"""
