<?php
/* Copyright (C) 2026 Alles Watt lauft
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 */

/**
 * \file       tabs/contact_anlagen.php
 * \brief      Tab for technical installations on contact/address card
 */

// Load Dolibarr environment
$res = 0;
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
if (!$res && file_exists("../../../../main.inc.php")) $res = @include "../../../../main.inc.php";
if (!$res) die("Include of main fails");

require_once DOL_DOCUMENT_ROOT.'/core/lib/contact.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
dol_include_once('/kundenkarte/class/anlage.class.php');
dol_include_once('/kundenkarte/class/anlagetype.class.php');
dol_include_once('/kundenkarte/class/anlagefile.class.php');
dol_include_once('/kundenkarte/class/equipmentpanel.class.php');
dol_include_once('/kundenkarte/class/equipmentcarrier.class.php');
dol_include_once('/kundenkarte/class/equipment.class.php');
dol_include_once('/kundenkarte/lib/kundenkarte.lib.php');

// Load translation files
$langs->loadLangs(array('companies', 'kundenkarte@kundenkarte'));

// Get parameters
// Support both 'id' and 'contactid' for compatibility with Dolibarr's contact navigation arrows
$id = GETPOSTINT('id');
if ($id <= 0) {
	$id = GETPOSTINT('contactid');
}
$action = GETPOST('action', 'aZ09');
$confirm = GETPOST('confirm', 'alpha');
$systemId = GETPOSTINT('system');
$anlageId = GETPOSTINT('anlage_id');
$parentId = GETPOSTINT('parent_id');

// Security check
if (!$user->hasRight('kundenkarte', 'read')) {
	accessforbidden();
}

// Initialize objects
$object = new Contact($db);
$form = new Form($db);
$anlage = new Anlage($db);
$anlageType = new AnlageType($db);

// Load contact - id is required
if ($id <= 0) {
	// If no id, try to get it from anlage_id
	if ($anlageId > 0) {
		$tmpAnlage = new Anlage($db);
		if ($tmpAnlage->fetch($anlageId) > 0) {
			$id = $tmpAnlage->fk_contact;
			if ($id > 0) {
				// Redirect to include id in URL for proper navigation
				$redirectUrl = $_SERVER['PHP_SELF'].'?id='.$id;
				if ($systemId > 0) $redirectUrl .= '&system='.$systemId;
				if ($action) $redirectUrl .= '&action='.urlencode($action);
				if ($anlageId > 0) $redirectUrl .= '&anlage_id='.$anlageId;
				header('Location: '.$redirectUrl);
				exit;
			}
		}
	}
	// Still no id - show error
	accessforbidden($langs->trans('ErrorRecordNotFound'));
}

$result = $object->fetch($id);
if ($result <= 0) {
	dol_print_error($db, $object->error);
	exit;
}

$permissiontoread = $user->hasRight('kundenkarte', 'read');
$permissiontoadd = $user->hasRight('kundenkarte', 'write');
$permissiontodelete = $user->hasRight('kundenkarte', 'delete');

// Load ALL available systems (from dictionary)
$allSystems = array();
$sql = "SELECT rowid, code, label, picto, color FROM ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system WHERE active = 1 ORDER BY position ASC";
$resql = $db->query($sql);
if ($resql) {
	while ($obj = $db->fetch_object($resql)) {
		$allSystems[$obj->rowid] = $obj;
	}
}

// Load systems ENABLED for this contact
$customerSystems = array();
$sql = "SELECT ss.rowid, ss.fk_system, s.code, s.label, s.picto, s.color
        FROM ".MAIN_DB_PREFIX."kundenkarte_societe_system ss
        JOIN ".MAIN_DB_PREFIX."c_kundenkarte_anlage_system s ON s.rowid = ss.fk_system
        WHERE ss.fk_soc = ".((int) $object->socid)." AND ss.fk_contact = ".((int) $id)." AND ss.active = 1 AND s.active = 1
        AND s.code != 'GLOBAL'
        ORDER BY s.position ASC";
$resql = $db->query($sql);
if ($resql) {
	while ($obj = $db->fetch_object($resql)) {
		$customerSystems[$obj->fk_system] = $obj;
	}
}

// Default to first enabled system if not specified
if (empty($systemId) && !empty($customerSystems)) {
	$systemId = array_key_first($customerSystems);
}

/*
 * Actions
 */

// Add system to contact
if ($action == 'add_system' && $permissiontoadd) {
	$newSystemId = GETPOSTINT('new_system_id');
	if ($newSystemId > 0 && !isset($customerSystems[$newSystemId])) {
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."kundenkarte_societe_system";
		$sql .= " (entity, fk_soc, fk_contact, fk_system, date_creation, fk_user_creat, active)";
		$sql .= " VALUES (".$conf->entity.", ".((int) $object->socid).", ".((int) $id).", ".((int) $newSystemId).", NOW(), ".((int) $user->id).", 1)";
		$result = $db->query($sql);
		if ($result) {
			setEventMessages($langs->trans('SystemAdded'), null, 'mesgs');
			header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$newSystemId);
			exit;
		} else {
			setEventMessages($db->lasterror(), null, 'errors');
		}
	}
	$action = '';
}

// Remove system from contact
if ($action == 'confirm_remove_system' && $confirm == 'yes' && $permissiontodelete) {
	$removeSystemId = GETPOSTINT('remove_system_id');
	if ($removeSystemId > 0) {
		// Check if system has any elements for this contact
		$sql = "SELECT COUNT(*) as cnt FROM ".MAIN_DB_PREFIX."kundenkarte_anlage WHERE fk_soc = ".((int) $object->socid)." AND fk_contact = ".((int) $id)." AND fk_system = ".((int) $removeSystemId);
		$resql = $db->query($sql);
		$obj = $db->fetch_object($resql);

		if ($obj->cnt > 0) {
			setEventMessages($langs->trans('ErrorSystemHasElements'), null, 'errors');
		} else {
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."kundenkarte_societe_system WHERE fk_soc = ".((int) $object->socid)." AND fk_contact = ".((int) $id)." AND fk_system = ".((int) $removeSystemId);
			$db->query($sql);
			setEventMessages($langs->trans('SystemRemoved'), null, 'mesgs');

			// Switch to another system or none
			unset($customerSystems[$removeSystemId]);
			if (!empty($customerSystems)) {
				$systemId = array_key_first($customerSystems);
			} else {
				$systemId = 0;
			}
		}
	}
	header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.($systemId ? '&system='.$systemId : ''));
	exit;
}

if ($action == 'add' && $permissiontoadd) {
	$anlage->label = GETPOST('label', 'alphanohtml');
	$anlage->fk_soc = $object->socid;
	$anlage->fk_contact = $id;
	$anlage->fk_anlage_type = GETPOSTINT('fk_anlage_type');
	$anlage->fk_parent = GETPOSTINT('fk_parent');
	$anlage->fk_system = $systemId;
	$anlage->note_private = isset($_POST['note_private']) ? $_POST['note_private'] : '';
	$anlage->status = 1;

	// Get type - but keep current system for GLOBAL types (buildings)
	$type = new AnlageType($db);
	if ($type->fetch($anlage->fk_anlage_type) > 0) {
		// Only change system if type is NOT a global type
		// Global types (buildings) should stay in the current system
		if ($type->system_code !== 'GLOBAL') {
			$anlage->fk_system = $type->fk_system;
		}
	}

	// All fields come from dynamic fields now
	$fieldValues = array();
	$fields = $type->fetchFields();
	foreach ($fields as $field) {
		if ($field->field_type === 'header') continue; // Skip headers
		$value = GETPOST('field_'.$field->field_code, 'alphanohtml');
		if ($value !== '') {
			$fieldValues[$field->field_code] = $value;
		}
	}
	$anlage->setFieldValues($fieldValues);

	$result = $anlage->create($user);
	if ($result > 0) {
		setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
		header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId);
		exit;
	} else {
		setEventMessages($anlage->error, $anlage->errors, 'errors');
		$action = 'create';
	}
}

if ($action == 'update' && $permissiontoadd) {
	$anlage->fetch($anlageId);
	$systemIdBefore = $anlage->fk_system; // Remember original system
	$anlage->label = GETPOST('label', 'alphanohtml');
	$anlage->fk_anlage_type = GETPOSTINT('fk_anlage_type');
	$anlage->fk_parent = GETPOSTINT('fk_parent');
	$anlage->note_private = isset($_POST['note_private']) ? $_POST['note_private'] : '';

	// Get type - but keep current system for GLOBAL types (buildings)
	$type = new AnlageType($db);
	if ($type->fetch($anlage->fk_anlage_type) > 0) {
		// Only change system if type is NOT a global type
		// Global types (buildings) should stay in their current system
		if ($type->system_code !== 'GLOBAL') {
			$anlage->fk_system = $type->fk_system;
		}
	}

	// All fields come from dynamic fields now
	$fieldValues = array();
	$fields = $type->fetchFields();
	foreach ($fields as $field) {
		if ($field->field_type === 'header') continue; // Skip headers
		$value = GETPOST('field_'.$field->field_code, 'alphanohtml');
		if ($value !== '') {
			$fieldValues[$field->field_code] = $value;
		}
	}
	$anlage->setFieldValues($fieldValues);

	$result = $anlage->update($user);
	if ($result > 0) {
		setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
		header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId);
		exit;
	} else {
		setEventMessages($anlage->error, $anlage->errors, 'errors');
		$action = 'edit';
	}
}

if ($action == 'confirm_delete' && $confirm == 'yes' && $permissiontodelete) {
	$anlage->fetch($anlageId);
	$systemIdBefore = $anlage->fk_system;
	$result = $anlage->delete($user);
	if ($result > 0) {
		setEventMessages($langs->trans('RecordDeleted'), null, 'mesgs');
	} else {
		setEventMessages($anlage->error, $anlage->errors, 'errors');
	}
	header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemIdBefore);
	exit;
}

// File upload (multi-file support)
if ($action == 'uploadfile' && $permissiontoadd) {
	$anlage->fetch($anlageId);
	$upload_dir = $anlage->getFileDirectory();

	// Create directory if not exists
	if (!is_dir($upload_dir)) {
		dol_mkdir($upload_dir);
	}

	$uploadCount = 0;
	if (!empty($_FILES['userfiles']['name'][0])) {
		// Multi-file upload
		$fileCount = count($_FILES['userfiles']['name']);
		for ($i = 0; $i < $fileCount; $i++) {
			if ($_FILES['userfiles']['error'][$i] === UPLOAD_ERR_OK && !empty($_FILES['userfiles']['name'][$i])) {
				$tmpName = $_FILES['userfiles']['tmp_name'][$i];
				$fileName = dol_sanitizeFileName($_FILES['userfiles']['name'][$i]);
				$destPath = $upload_dir.'/'.$fileName;

				// Handle duplicate filenames
				$counter = 1;
				$baseName = pathinfo($fileName, PATHINFO_FILENAME);
				$extension = pathinfo($fileName, PATHINFO_EXTENSION);
				while (file_exists($destPath)) {
					$fileName = $baseName.'_'.$counter.'.'.$extension;
					$destPath = $upload_dir.'/'.$fileName;
					$counter++;
				}

				if (move_uploaded_file($tmpName, $destPath)) {
					// Add to database
					$anlagefile = new AnlageFile($db);
					$anlagefile->fk_anlage = $anlageId;
					$anlagefile->filename = $fileName;
					// IMPORTANT: Store ONLY relative path (anlagen/socid/anlageid/filename) - never full path!
					$anlagefile->filepath = 'anlagen/'.$anlage->fk_soc.'/'.$anlage->id.'/'.$fileName;
					$anlagefile->filesize = $_FILES['userfiles']['size'][$i];
					$anlagefile->mimetype = dol_mimetype($fileName);
					$anlagefile->create($user);

					// Generate thumbnail
					$anlagefile->generateThumbnail();

					$uploadCount++;
				}
			}
		}
		if ($uploadCount > 0) {
			$msg = $uploadCount > 1 ? $uploadCount.' Dateien hochgeladen' : 'Datei hochgeladen';
			setEventMessages($msg, null, 'mesgs');
		}
	}
	header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=view&anlage_id='.$anlageId);
	exit;
}

// File delete (after confirmation)
if ($action == 'confirm_deletefile' && $confirm == 'yes' && $permissiontodelete) {
	$fileId = GETPOSTINT('fileid');
	if ($fileId > 0) {
		$anlagefile = new AnlageFile($db);
		if ($anlagefile->fetch($fileId) > 0) {
			// Delete method handles physical file and database
			if ($anlagefile->delete($user) > 0) {
				setEventMessages($langs->trans('FileDeleted'), null, 'mesgs');
			} else {
				setEventMessages($langs->trans('Error'), null, 'errors');
			}
		}
	}
	header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=view&anlage_id='.$anlageId);
	exit;
}

// Toggle file pinned status
if ($action == 'togglepin' && $permissiontoadd) {
	$fileId = GETPOSTINT('fileid');
	if ($fileId > 0) {
		$anlagefile = new AnlageFile($db);
		if ($anlagefile->fetch($fileId) > 0) {
			if ($anlagefile->togglePin($user) > 0) {
				$msg = $anlagefile->is_pinned ? $langs->trans('FilePinned') : $langs->trans('FileUnpinned');
				setEventMessages($msg, null, 'mesgs');
			}
		}
	}
	header('Location: '.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=view&anlage_id='.$anlageId.'#files');
	exit;
}

/*
 * View
 */

$title = $langs->trans('TechnicalInstallations').' - '.$object->getFullName($langs);

// Ansichtsmodus: URL-Parameter hat Vorrang, sonst Admin-Setting
dol_include_once('/kundenkarte/lib/graph_view.lib.php');
$defaultView = getDolGlobalString('KUNDENKARTE_DEFAULT_VIEW', 'tree');
$viewMode = GETPOST('view', 'aZ09');
if (!in_array($viewMode, array('tree', 'graph'))) {
	$viewMode = $defaultView;
}

$jsFiles = array('/kundenkarte/js/kundenkarte.js?v='.time());
$cssFiles = array('/kundenkarte/css/kundenkarte.css?v='.time());
kundenkarte_graph_add_assets($jsFiles, $cssFiles, $viewMode);

llxHeader('', $title, '', '', 0, 0, $jsFiles, $cssFiles);

// Prepare tabs
$head = contact_prepare_head($object);

print dol_get_fiche_head($head, 'anlagen', $langs->trans("ContactAddress"), -1, 'contact');

// Contact card
$linkback = '<a href="'.DOL_URL_ROOT.'/contact/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'nom');

print '<div class="fichecenter">';

// Confirmation dialogs
if ($action == 'delete') {
	print $form->formconfirm(
		$_SERVER['PHP_SELF'].'?id='.$id.'&anlage_id='.$anlageId.'&system='.$systemId,
		$langs->trans('DeleteElement'),
		$langs->trans('ConfirmDeleteElement'),
		'confirm_delete',
		'',
		'yes',
		1
	);
}

if ($action == 'remove_system') {
	$removeSystemId = GETPOSTINT('remove_system_id');
	$sysLabel = isset($customerSystems[$removeSystemId]) ? $customerSystems[$removeSystemId]->label : '';
	print $form->formconfirm(
		$_SERVER['PHP_SELF'].'?id='.$id.'&remove_system_id='.$removeSystemId,
		$langs->trans('RemoveSystem'),
		$langs->trans('ConfirmRemoveSystem', $sysLabel),
		'confirm_remove_system',
		'',
		'yes',
		1
	);
}

if ($action == 'askdeletefile') {
	$fileId = GETPOSTINT('fileid');
	print $form->formconfirm(
		$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&anlage_id='.$anlageId.'&fileid='.$fileId,
		$langs->trans('Delete'),
		$langs->trans('ConfirmDeleteFile'),
		'confirm_deletefile',
		'',
		'yes',
		1
	);
}

// System tabs (only show enabled systems for this contact)
print '<div class="kundenkarte-system-tabs-wrapper">';
print '<div class="kundenkarte-system-tabs">';
foreach ($customerSystems as $sysId => $sys) {
	$activeClass = ($sysId == $systemId) ? ' active' : '';
	print '<div class="kundenkarte-system-tab'.$activeClass.'" data-system="'.$sysId.'">';
	print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$sysId.'" style="text-decoration:none;color:inherit;display:flex;align-items:center;gap:8px;">';
	if ($sys->picto) {
		print '<span class="kundenkarte-system-tab-icon" style="color:'.$sys->color.';">'.kundenkarte_render_icon($sys->picto).'</span>';
	}
	print '<span>'.dol_escape_htmltag($sys->label).'</span>';
	print '</a>';
	// Remove button (only if no elements)
	if ($permissiontodelete && $sysId == $systemId) {
		print ' <a href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&action=remove_system&remove_system_id='.$sysId.'" class="kundenkarte-system-remove" title="'.$langs->trans('RemoveSystem').'"><i class="fa fa-times"></i></a>';
	}
	print '</div>';
}

// Add system button (always on the right)
if ($permissiontoadd) {
	// Get systems not yet enabled for this contact
	$availableSystems = array_diff_key($allSystems, $customerSystems);
	if (!empty($availableSystems)) {
		print '<button type="button" class="button small" style="margin-left:auto;" onclick="document.getElementById(\'add-system-form\').style.display=\'block\';">';
		print '<i class="fa fa-plus"></i> '.$langs->trans('AddSystem');
		print '</button>';
	}
}
print '</div>';

// Steuerungs-Buttons (nur wenn kein Formular aktiv)
$isTreeView = !in_array($action, array('create', 'edit', 'view', 'copy'));
if ($isTreeView) {
	$toggleView = ($viewMode === 'graph') ? 'tree' : 'graph';
	$toggleUrl = $_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&view='.$toggleView;
	$toggleIcon = ($viewMode === 'graph') ? 'fa-list' : 'fa-sitemap';
	$toggleLabel = ($viewMode === 'graph') ? $langs->trans('TreeView') : $langs->trans('GraphView');

	if ($viewMode !== 'graph') {
		// Baumansicht: Controls auf gleicher Zeile wie System-Tabs (im Wrapper)
		print '<div class="kundenkarte-tree-controls">';
		print '<a class="button small" href="'.$toggleUrl.'" title="'.$toggleLabel.'">';
		print '<i class="fa '.$toggleIcon.'"></i> '.$toggleLabel;
		print '</a>';
		print '<button type="button" class="kundenkarte-view-toggle" id="btn-compact-mode" title="Kompakte Ansicht">';
		print '<i class="fa fa-compress"></i> <span>Kompakt</span>';
		print '</button>';
		print '<button type="button" class="button small" id="btn-expand-all" title="'.$langs->trans('ExpandAll').'">';
		print '<i class="fa fa-expand"></i> '.$langs->trans('ExpandAll');
		print '</button>';
		print '<button type="button" class="button small" id="btn-collapse-all" title="'.$langs->trans('CollapseAll').'">';
		print '<i class="fa fa-compress"></i> '.$langs->trans('CollapseAll');
		print '</button>';
		if ($systemId > 0) {
			$exportUrl = dol_buildpath('/kundenkarte/ajax/export_tree_pdf.php', 1).'?socid='.$object->socid.'&contactid='.$id.'&system='.$systemId;
			print '<a class="button small" href="'.$exportUrl.'" title="'.$langs->trans('ExportPDF').'" target="_blank">';
			print '<i class="fa fa-file-pdf-o"></i> PDF Export';
			print '</a>';
		}
		print '</div>';
	}
}

print '</div>'; // End kundenkarte-system-tabs-wrapper

// Graph-Toolbar: UNTER der System-Tab-Borderlinie
if ($isTreeView && $viewMode === 'graph') {
	kundenkarte_graph_print_toolbar(array(
		'socid' => $object->socid,
		'contactid' => $id,
		'systemid' => $systemId,
		'viewMode' => $viewMode,
		'permissiontoadd' => $permissiontoadd,
		'pageUrl' => $_SERVER['PHP_SELF'],
	));
}

// Add system form (hidden by default)
if ($permissiontoadd && !empty($availableSystems)) {
	print '<div id="add-system-form" class="kundenkarte-add-system-form" style="display:none;margin-bottom:15px;">';
	print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$id.'">';
	print '<input type="hidden" name="token" value="'.newToken().'">';
	print '<input type="hidden" name="action" value="add_system">';
	print '<strong>'.$langs->trans('SelectSystemToAdd').':</strong> ';
	print '<select name="new_system_id" class="flat">';
	print '<option value="">'.$langs->trans('Select').'</option>';
	foreach ($availableSystems as $avSys) {
		print '<option value="'.$avSys->rowid.'">'.dol_escape_htmltag($avSys->label).'</option>';
	}
	print '</select>';
	print ' <button type="submit" class="button small">'.$langs->trans('Add').'</button>';
	print ' <button type="button" class="button small" onclick="document.getElementById(\'add-system-form\').style.display=\'none\';">'.$langs->trans('Cancel').'</button>';
	print '</form>';
	print '</div>';
}

// Check if contact has any systems
if (empty($customerSystems)) {
	print '<div class="opacitymedium" style="padding:20px;text-align:center;">';
	print '<i class="fa fa-info-circle" style="font-size:24px;margin-bottom:10px;"></i><br>';
	print $langs->trans('NoSystemsConfigured').'<br><br>';
	if ($permissiontoadd && !empty($allSystems)) {
		print $langs->trans('ClickAddSystemToStart');
	} else {
		print $langs->trans('ContactAdminToAddSystems');
	}
	print '</div>';
} elseif ($systemId > 0) {
	// Show form or tree for selected system
	if (in_array($action, array('create', 'edit', 'view', 'copy'))) {
		// Load element for edit/view/copy
		if ($action != 'create' && $anlageId > 0) {
			$anlage->fetch($anlageId);
			$type = new AnlageType($db);
			$type->fetch($anlage->fk_anlage_type);
			$type->fetchFields();
		}

		// Load types for select
		$types = $anlageType->fetchAllBySystem($systemId);

		print '<div class="kundenkarte-element-form">';

		if ($action == 'view') {
			// View mode
			print '<h3>'.dol_escape_htmltag($anlage->label).'</h3>';

			print '<table class="border centpercent">';

			print '<tr><td class="titlefield">'.$langs->trans('Type').'</td>';
			print '<td>'.dol_escape_htmltag($anlage->type_label).'</td></tr>';

			// Dynamic fields - all fields come from type definition
			$fieldValues = $anlage->getFieldValues();
			$typeFieldsList = $type->fetchFields();
			foreach ($typeFieldsList as $field) {
				if ($field->field_type === 'header') {
					// Section header
					print '<tr class="liste_titre"><th colspan="2" style="background:#f0f0f0;padding:8px;">'.dol_escape_htmltag($field->field_label).'</th></tr>';
				} else {
					$value = isset($fieldValues[$field->field_code]) ? $fieldValues[$field->field_code] : '';
					if ($value !== '') {
						print '<tr><td>'.dol_escape_htmltag($field->field_label).'</td>';
						// Format date fields
						if ($field->field_type === 'date' && $value) {
							print '<td>'.dol_print_date(strtotime($value), 'day').'</td></tr>';
						} elseif ($field->field_type === 'checkbox') {
							print '<td>'.($value ? $langs->trans('Yes') : $langs->trans('No')).'</td></tr>';
						} else {
							print '<td>'.dol_escape_htmltag($value).'</td></tr>';
						}
					}
				}
			}

			if ($anlage->note_private) {
				print '<tr><td>'.$langs->trans('FieldNotes').'</td>';
				print '<td>'.dol_htmlentitiesbr($anlage->note_private).'</td></tr>';
			}

			// Creation date
			if ($anlage->date_creation) {
				print '<tr><td>'.$langs->trans('DateCreation').'</td>';
				print '<td>'.dol_print_date($anlage->date_creation, 'dayhour').'</td></tr>';
			}

			// Last modification date
			if ($anlage->tms && $anlage->tms != $anlage->date_creation) {
				print '<tr><td>'.$langs->trans('DateLastModification').'</td>';
				print '<td>'.dol_print_date($anlage->tms, 'dayhour').'</td></tr>';
			}

			print '</table>';

			// Files section
			$anlagefile = new AnlageFile($db);
			$files = $anlagefile->fetchAllByAnlage($anlageId);

			print '<br><h4>'.$langs->trans('AttachedFiles').'</h4>';

			if ($permissiontoadd) {
				print '<form method="POST" enctype="multipart/form-data" action="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=uploadfile&anlage_id='.$anlageId.'" id="fileUploadForm">';
				print '<input type="hidden" name="token" value="'.newToken().'">';
				print '<div class="kundenkarte-dropzone" id="fileDropzone">';
				print '<input type="file" name="userfiles[]" id="fileInput" multiple accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.odt,.ods,.txt,.rtf,.zip,.rar,.7z,.tar,.gz" style="display:none;">';
				print '<div class="kundenkarte-dropzone-content">';
				print '<i class="fa fa-cloud-upload" style="font-size:32px;color:#3498db;margin-bottom:10px;"></i>';
				print '<p style="margin:0;color:#888;">Dateien hierher ziehen oder <a href="#" onclick="document.getElementById(\'fileInput\').click();return false;" style="color:#3498db;">durchsuchen</a></p>';
				print '<p style="margin:5px 0 0;font-size:11px;color:#666;">Bilder, PDF, Office-Dokumente, ZIP-Archive</p>';
				print '</div>';
				print '<div class="kundenkarte-dropzone-files" id="selectedFiles" style="display:none;"></div>';
				print '</div>';
				print '<button type="submit" class="button" id="uploadBtn" style="display:none;margin-top:10px;">'.$langs->trans('Upload').' (<span id="fileCount">0</span> Dateien)</button>';
				print '</form><br>';
			}

			if (!empty($files)) {
				print '<div class="kundenkarte-files-grid">';
				foreach ($files as $file) {
					$pinnedClass = $file->is_pinned ? ' kundenkarte-file-pinned' : '';
					print '<div class="kundenkarte-file-item'.$pinnedClass.'">';
					if ($file->is_pinned) {
						print '<div class="kundenkarte-pin-indicator" title="'.$langs->trans('Pinned').'"><i class="fa fa-thumb-tack"></i></div>';
					}
					print '<div class="kundenkarte-file-preview">';
					if ($file->file_type == 'image') {
						$thumbUrl = $file->getThumbUrl();
						if ($thumbUrl) {
							print '<img src="'.$thumbUrl.'" alt="">';
						} else {
							print '<img src="'.$file->getUrl().'" alt="" style="max-width:100%;max-height:100%;">';
						}
					} elseif ($file->file_type == 'pdf') {
						// PDF preview using iframe
						print '<div class="kundenkarte-pdf-preview-wrapper">';
						print '<iframe src="'.$file->getUrl().'#page=1&toolbar=0&navpanes=0&statusbar=0&view=FitH" class="kundenkarte-pdf-preview-frame"></iframe>';
						print '</div>';
					} else {
						// Show icon based on file type
						$fileIcon = 'fa-file-o';
						$iconColor = '#999';
						if ($file->file_type == 'archive') {
							$fileIcon = 'fa-file-archive-o';
							$iconColor = '#f39c12';
						} elseif ($file->file_type == 'document') {
							$ext = strtolower(pathinfo($file->filename, PATHINFO_EXTENSION));
							if (in_array($ext, array('doc', 'docx'))) {
								$fileIcon = 'fa-file-word-o';
								$iconColor = '#2b579a';
							} elseif (in_array($ext, array('xls', 'xlsx'))) {
								$fileIcon = 'fa-file-excel-o';
								$iconColor = '#217346';
							} elseif ($ext == 'txt') {
								$fileIcon = 'fa-file-text-o';
								$iconColor = '#666';
							} else {
								$fileIcon = 'fa-file-text-o';
								$iconColor = '#3498db';
							}
						}
						print '<i class="fa '.$fileIcon.'" style="font-size:48px;color:'.$iconColor.';"></i>';
					}
					print '</div>';
					print '<div class="kundenkarte-file-info">';
					print '<div class="kundenkarte-file-name" title="'.dol_escape_htmltag($file->filename).'">'.dol_escape_htmltag(dol_trunc($file->filename, 35)).'</div>';
					print '<div class="kundenkarte-file-size">'.dol_print_size($file->filesize).'</div>';
					print '<div class="kundenkarte-file-actions">';
					print '<a href="'.$file->getUrl().'" target="_blank" class="kundenkarte-file-btn" title="'.$langs->trans('View').'"><i class="fa fa-eye"></i></a>';
					if ($permissiontoadd) {
						$pinClass = $file->is_pinned ? ' kundenkarte-file-btn-pinned' : '';
						$pinTitle = $file->is_pinned ? $langs->trans('Unpin') : $langs->trans('Pin');
						print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=togglepin&anlage_id='.$anlageId.'&fileid='.$file->id.'" class="kundenkarte-file-btn'.$pinClass.'" title="'.$pinTitle.'"><i class="fa fa-thumb-tack"></i></a>';
					}
					if ($permissiontodelete) {
						print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=askdeletefile&anlage_id='.$anlageId.'&fileid='.$file->id.'" class="kundenkarte-file-btn kundenkarte-file-btn-delete" title="'.$langs->trans('Delete').'"><i class="fa fa-trash"></i></a>';
					}
					print '</div>';
					print '</div>';
					print '</div>';
				}
				print '</div>';
			} else {
				print '<p class="opacitymedium">'.$langs->trans('NoFiles').'</p>';
			}

			// Equipment section (only if type can have equipment)
			if ($type->can_have_equipment) {
				print '<br><h4><i class="fa fa-microchip"></i> '.$langs->trans('Equipment').' - Schaltplan</h4>';

				// Equipment container
				print '<div class="kundenkarte-equipment-container" data-anlage-id="'.$anlageId.'" data-system-id="'.$systemId.'">';

				// Schematic Editor
				print '<div class="schematic-editor-wrapper">';
				print '<div class="schematic-editor-header" style="display:flex;justify-content:space-between;align-items:center;padding:10px 15px;background:#252525;border:1px solid #333;border-radius:4px 4px 0 0;">';
				print '<div style="color:#3498db;">';
				print '<strong>'.$langs->trans('SchematicEditor').'</strong> <span style="color:#888;font-size:0.85em;">(Klick auf Block = Bearbeiten | Drag = Verschieben | + = Hinzufügen)</span>';
				print '</div>';
				print '<div class="schematic-editor-actions" style="display:flex;gap:10px;align-items:center;">';
				// Zoom controls
				print '<div class="schematic-zoom-controls" style="display:flex;gap:2px;align-items:center;background:#222;border-radius:3px;padding:2px;">';
				print '<button type="button" class="schematic-zoom-out" style="width:28px;height:28px;background:#333;border:1px solid #555;border-radius:3px;color:#fff;cursor:pointer;" title="Verkleinern (Ctrl+Scroll)"><i class="fa fa-minus"></i></button>';
				print '<span class="schematic-zoom-level" style="min-width:45px;text-align:center;color:#888;font-size:12px;">100%</span>';
				print '<button type="button" class="schematic-zoom-in" style="width:28px;height:28px;background:#333;border:1px solid #555;border-radius:3px;color:#fff;cursor:pointer;" title="Vergrößern (Ctrl+Scroll)"><i class="fa fa-plus"></i></button>';
				print '<button type="button" class="schematic-zoom-fit" style="width:28px;height:28px;background:#333;border:1px solid #555;border-radius:3px;color:#3498db;cursor:pointer;margin-left:3px;" title="Einpassen"><i class="fa fa-compress"></i></button>';
				print '<button type="button" class="schematic-zoom-reset" style="width:28px;height:28px;background:#333;border:1px solid #555;border-radius:3px;color:#888;cursor:pointer;" title="100%"><i class="fa fa-search"></i></button>';
				print '</div>';
				// Manual wire draw toggle
				print '<button type="button" class="schematic-wire-draw-toggle" style="padding:5px 10px;background:#333;border:1px solid #555;border-radius:3px;color:#27ae60;cursor:pointer;" title="Manueller Zeichenmodus: Leitungen selbst zeichnen mit Raster-Snap">';
				print '<i class="fa fa-pencil"></i> Manuell zeichnen';
				print '</button>';
				print '<button type="button" class="schematic-add-busbar" style="padding:5px 10px;background:#333;border:1px solid #555;border-radius:3px;color:#f39c12;cursor:pointer;" title="Phasenschiene hinzufügen">';
				print '<i class="fa fa-arrows-h"></i> Phasenschiene';
				print '</button>';
				print '<button type="button" class="schematic-clear-connections" style="padding:5px 10px;background:#333;border:1px solid #555;border-radius:3px;color:#e74c3c;cursor:pointer;">';
				print '<i class="fa fa-trash"></i> Alle Verbindungen löschen';
				print '</button>';
				// BOM (Stückliste) button
				print '<button type="button" class="schematic-bom-generate" style="padding:5px 10px;background:#333;border:1px solid #555;border-radius:3px;color:#9b59b6;cursor:pointer;" title="Stückliste (Material) aus Schaltplan generieren">';
				print '<i class="fa fa-list-alt"></i> Stückliste';
				print '</button>';
				// Audit Log button
				print '<button type="button" class="schematic-audit-log" style="padding:5px 10px;background:#333;border:1px solid #555;border-radius:3px;color:#95a5a6;cursor:pointer;" title="Änderungsprotokoll anzeigen">';
				print '<i class="fa fa-history"></i> Protokoll';
				print '</button>';
				// PDF Export button
				$pdfExportUrl = dol_buildpath('/kundenkarte/ajax/export_schematic_pdf.php', 1).'?anlage_id='.$anlageId.'&format=A4&orientation=L';
				print '<a href="'.$pdfExportUrl.'" target="_blank" class="schematic-export-pdf" style="padding:5px 10px;background:#333;border:1px solid #555;border-radius:3px;color:#3498db;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;gap:5px;" title="PDF Export (Leitungslaufplan nach DIN EN 61082)">';
				print '<i class="fa fa-file-pdf-o"></i> PDF Export';
				print '</a>';
				print '</div>';
				print '</div>';
				print '<div class="schematic-editor-canvas expanded" style="display:block;background:#1a1a1a;border:1px solid #333;border-top:none;border-radius:0 0 4px 4px;padding:15px;overflow:auto;">';
				print '<div class="schematic-message" style="display:none;padding:8px 15px;margin-bottom:10px;border-radius:4px;font-size:12px;"></div>';
				print '</div>';
				print '</div>';

				print '</div>'; // .kundenkarte-equipment-container

				// Initialize SchematicEditor JavaScript
				print '<script>
					$(document).ready(function() {
						if (typeof KundenKarte !== "undefined" && KundenKarte.SchematicEditor) {
							KundenKarte.SchematicEditor.init('.$anlageId.');
						}
					});
				</script>';
			}

			// Action buttons
			print '<div class="tabsAction">';
			if ($permissiontoadd) {
				print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=edit&anlage_id='.$anlageId.'">'.$langs->trans('Modify').'</a>';
				print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=copy&anlage_id='.$anlageId.'">'.$langs->trans('Copy').'</a>';
			}
			if ($permissiontodelete) {
				print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=delete&anlage_id='.$anlageId.'">'.$langs->trans('Delete').'</a>';
			}
			print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'">'.$langs->trans('Back').'</a>';
			print '</div>';

		} else {
			// Create/Edit/Copy form
			$isEdit = ($action == 'edit');
			$isCopy = ($action == 'copy');
			$formAction = $isEdit ? 'update' : 'add';

			print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'">';
			print '<input type="hidden" name="token" value="'.newToken().'">';
			print '<input type="hidden" name="action" value="'.$formAction.'">';
			if ($isEdit) {
				print '<input type="hidden" name="anlage_id" value="'.$anlageId.'">';
			}
			if ($isCopy) {
				print '<input type="hidden" name="copy_from" value="'.$anlageId.'">';
			}

			print '<table class="border centpercent" id="element_form_table">';

			// Label
			$labelValue = '';
			if ($isEdit) {
				$labelValue = $anlage->label;
			} elseif ($isCopy) {
				$labelValue = $anlage->label.' (Kopie)';
			} else {
				$labelValue = GETPOST('label');
			}
			print '<tr><td class="titlefield fieldrequired">'.$langs->trans('Label').'</td>';
			print '<td><input type="text" name="label" class="flat minwidth300" value="'.dol_escape_htmltag($labelValue).'" required></td></tr>';

			// Kategorie (Gebäude/Standort vs Element/Gerät)
			$currentCategory = '';
			if (($isEdit || $isCopy) && !empty($anlage->fk_anlage_type)) {
				// Kategorie des aktuellen Typs ermitteln
				foreach ($types as $t) {
					if ($t->id == $anlage->fk_anlage_type) {
						$currentCategory = ($t->system_code === 'GLOBAL') ? 'building' : 'element';
						break;
					}
				}
			}
			$postedCategory = GETPOST('element_category', 'alpha');
			if ($postedCategory) $currentCategory = $postedCategory;

			print '<tr><td class="fieldrequired">'.$langs->trans('Category').'</td>';
			print '<td><select name="element_category" class="flat minwidth200" id="select_category">';
			print '<option value="">'.$langs->trans('SelectCategory').'</option>';
			print '<option value="building"'.($currentCategory === 'building' ? ' selected' : '').'>'.$langs->trans('BuildingStructure').'</option>';
			print '<option value="element"'.($currentCategory === 'element' ? ' selected' : '').'>'.$langs->trans('TechnicalElement').'</option>';
			print '</select></td></tr>';

			// Type (gefiltert nach Kategorie)
			print '<tr id="row_type"><td class="fieldrequired">'.$langs->trans('Type').'</td>';
			print '<td><select name="fk_anlage_type" class="flat minwidth200" id="select_type" required>';
			print '<option value="">'.$langs->trans('SelectType').'</option>';

			// Typen nach Kategorie gruppieren
			$buildingTypes = array();
			$elementTypes = array();
			foreach ($types as $t) {
				if ($t->system_code === 'GLOBAL') {
					$buildingTypes[] = $t;
				} else {
					$elementTypes[] = $t;
				}
			}

			// Gebäude-Typen nach level_type gruppieren (position-basiert)
			if (!empty($buildingTypes)) {
				$lastGroup = '';
				foreach ($buildingTypes as $t) {
					// Gruppierung nach Position: 10-99=Gebäude, 100-199=Etage, 200-299=Flügel, 300-399=Flur, 400-599=Raum, 600+=Außen
					if ($t->position < 100) $group = $langs->trans('BuildingLevelBuilding');
					elseif ($t->position < 200) $group = $langs->trans('BuildingLevelFloor');
					elseif ($t->position < 300) $group = $langs->trans('BuildingLevelWing');
					elseif ($t->position < 400) $group = $langs->trans('BuildingLevelCorridor');
					elseif ($t->position < 600) $group = $langs->trans('BuildingLevelRoom');
					else $group = $langs->trans('BuildingLevelArea');

					if ($group !== $lastGroup) {
						if ($lastGroup !== '') print '</optgroup>';
						print '<optgroup label="'.dol_escape_htmltag($group).'" class="type-category-building">';
						$lastGroup = $group;
					}
					$selected = (($isEdit || $isCopy) && $anlage->fk_anlage_type == $t->id) ? ' selected' : '';
					$picto = !empty($t->picto) ? dol_escape_htmltag($t->picto) : '';
					$color = !empty($t->color) ? dol_escape_htmltag($t->color) : '';
					print '<option value="'.$t->id.'" data-category="building" data-icon="'.$picto.'" data-color="'.$color.'"'.$selected.'>'.dol_escape_htmltag($t->label).'</option>';
				}
				if ($lastGroup !== '') print '</optgroup>';
			}

			// Element-Typen
			if (!empty($elementTypes)) {
				print '<optgroup label="'.$langs->trans('TechnicalElement').'" class="type-category-element">';
				foreach ($elementTypes as $t) {
					$selected = (($isEdit || $isCopy) && $anlage->fk_anlage_type == $t->id) ? ' selected' : '';
					$picto = !empty($t->picto) ? dol_escape_htmltag($t->picto) : '';
					$color = !empty($t->color) ? dol_escape_htmltag($t->color) : '';
					print '<option value="'.$t->id.'" data-category="element" data-icon="'.$picto.'" data-color="'.$color.'"'.$selected.'>'.dol_escape_htmltag($t->label).'</option>';
				}
				print '</optgroup>';
			}

			print '</select>';
			if (empty($types)) {
				print '<br><span class="warning">'.$langs->trans('NoTypesDefinedForSystem').'</span>';
			}
			print '</td></tr>';

			// Parent (uses contact-specific tree)
			$tree = $anlage->fetchTreeByContact($object->socid, $id, $systemId);
			$selectedParent = ($isEdit || $isCopy) ? $anlage->fk_parent : $parentId;
			$excludeId = $isEdit ? $anlageId : 0;
			print '<tr><td>'.$langs->trans('SelectParent').'</td>';
			print '<td><select name="fk_parent" class="flat minwidth200">';
			print '<option value="0">('.$langs->trans('Root').')</option>';
			printTreeOptions($tree, $selectedParent, $excludeId);
			print '</select></td></tr>';

			// Dynamic fields will be inserted here via JavaScript
			print '<tbody id="dynamic_fields"></tbody>';

			// Notes (always at the end)
			print '<tr class="notes-row"><td>'.$langs->trans('FieldNotes').'</td>';
			$noteValue = ($isEdit || $isCopy) ? $anlage->note_private : (isset($_POST['note_private']) ? $_POST['note_private'] : '');
			print '<td><textarea name="note_private" class="flat minwidth300" rows="3">'.htmlspecialchars($noteValue, ENT_QUOTES, 'UTF-8').'</textarea></td></tr>';

			print '</table>';

			print '<div class="center" style="margin-top:20px;">';
			print '<button type="submit" class="button button-save">'.$langs->trans('Save').'</button>';
			print ' <a class="button button-cancel" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'">'.$langs->trans('Cancel').'</a>';
			print '</div>';

			print '</form>';

			// JavaScript: Kategorie-Filter + Select2 mit Icons
			print '<script>
			$(document).ready(function() {
				var $catSelect = $("#select_category");
				var $typeSelect = $("#select_type");

				// Alle Options und Optgroups als HTML-String sichern
				var allOptionsHtml = $typeSelect.html();

				// Select2 Template-Funktion mit Icons
				function formatTypeOption(option) {
					if (!option.id) return option.text; // Placeholder
					var $opt = $(option.element);
					var icon = $opt.data("icon");
					var color = $opt.data("color") || "#666";
					if (icon) {
						return $("<span><i class=\"fa " + icon + "\" style=\"color:" + color + ";width:20px;margin-right:8px;text-align:center;\"></i>" + option.text + "</span>");
					}
					return option.text;
				}

				// Select2 initialisieren
				function initSelect2() {
					// Falls bereits initialisiert, zerstören
					if ($typeSelect.hasClass("select2-hidden-accessible")) {
						$typeSelect.select2("destroy");
					}
					$typeSelect.select2({
						templateResult: formatTypeOption,
						templateSelection: formatTypeOption,
						placeholder: "'.dol_escape_js($langs->trans('SelectType')).'",
						allowClear: true,
						width: "300px",
						dropdownAutoWidth: true
					});
				}

				function filterTypes() {
					var category = $catSelect.val();
					var currentVal = $typeSelect.val();

					// Select2 zerstören vor DOM-Änderungen
					if ($typeSelect.hasClass("select2-hidden-accessible")) {
						$typeSelect.select2("destroy");
					}

					// Alle Options zurücksetzen
					$typeSelect.html(allOptionsHtml);

					if (!category) {
						$typeSelect.prop("disabled", true);
						$("#row_type").hide();
						return;
					}

					// Nicht passende Options entfernen
					$typeSelect.find("option[data-category]").each(function() {
						if ($(this).data("category") !== category) {
							$(this).remove();
						}
					});

					// Leere Optgroups entfernen
					$typeSelect.find("optgroup").each(function() {
						if ($(this).find("option").length === 0) {
							$(this).remove();
						}
					});

					$typeSelect.prop("disabled", false);
					$("#row_type").show();

					// Wert wiederherstellen falls noch vorhanden
					if (currentVal && $typeSelect.find("option[value=\"" + currentVal + "\"]").length) {
						$typeSelect.val(currentVal);
					} else {
						$typeSelect.val("");
					}

					// Select2 neu initialisieren
					initSelect2();
				}

				$catSelect.on("change", function() {
					$typeSelect.val("");
					filterTypes();
					$typeSelect.trigger("change");
				});

				// Initial filtern
				if ($catSelect.val()) {
					filterTypes();
				} else {
					$typeSelect.prop("disabled", true);
					$("#row_type").hide();
				}

				// Select2 für übergeordnetes Element mit Icons
				var $parentSelect = $("select[name=\'fk_parent\']");
				if ($parentSelect.length) {
					$parentSelect.select2({
						templateResult: formatTypeOption,
						templateSelection: formatTypeOption,
						placeholder: "'.dol_escape_js($langs->trans('SelectParent')).'",
						allowClear: true,
						width: "300px",
						dropdownAutoWidth: true
					});
				}
			});
			</script>';
		}

		print '</div>';

	} else {
		// Listenansicht (Baum oder Graph)
		if ($permissiontoadd && $viewMode !== 'graph') {
			print '<div style="margin-bottom:15px;">';
			print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$id.'&system='.$systemId.'&action=create">';
			print '<i class="fa fa-plus"></i> '.$langs->trans('AddElement');
			print '</a>';
			print '</div>';
		}

		if ($viewMode === 'graph' && $isTreeView) {
			// Graph-Ansicht: Container rendern, Daten werden per AJAX geladen
			kundenkarte_graph_print_container(array(
				'socid' => $object->socid,
				'contactid' => $id,
				'systemid' => $systemId,
				'permissiontoadd' => $permissiontoadd,
				'permissiontodelete' => $permissiontodelete,
				'pageUrl' => $_SERVER['PHP_SELF'],
			));
		} else {
			// Baumansicht (klassisch)

			// Load tree for this contact
			$tree = $anlage->fetchTreeByContact($object->socid, $id, $systemId);

			// Pre-load all type fields for tooltip and tree display
			$typeFieldsMap = array();
			$sql = "SELECT f.*, f.fk_anlage_type FROM ".MAIN_DB_PREFIX."kundenkarte_anlage_type_field f WHERE f.active = 1 ORDER BY f.position ASC";
			$resql = $db->query($sql);
			if ($resql) {
				while ($obj = $db->fetch_object($resql)) {
					if (!isset($typeFieldsMap[$obj->fk_anlage_type])) {
						$typeFieldsMap[$obj->fk_anlage_type] = array();
					}
					$typeFieldsMap[$obj->fk_anlage_type][] = $obj;
				}
				$db->free($resql);
			}

			// Pre-load all connections for this contact/system
			dol_include_once('/kundenkarte/class/anlageconnection.class.php');
			$connObj = new AnlageConnection($db);
			$allConnections = $connObj->fetchBySociete($object->socid, $systemId);
			// Index by target_id for quick lookup (connection shows ABOVE the target element)
			$connectionsByTarget = array();
			foreach ($allConnections as $conn) {
				if (!isset($connectionsByTarget[$conn->fk_target])) {
					$connectionsByTarget[$conn->fk_target] = array();
				}
				$connectionsByTarget[$conn->fk_target][] = $conn;
			}

			if (!empty($tree)) {
				print '<div class="kundenkarte-tree" data-system="'.$systemId.'" data-socid="'.$object->socid.'">';
				printTree($tree, $id, $systemId, $permissiontoadd, $permissiontodelete, $langs, 0, $typeFieldsMap, $connectionsByTarget);
				print '</div>';
			} else {
				print '<div class="opacitymedium">'.$langs->trans('NoInstallations').'</div>';
			}
		}
	}
}

print '</div>';

print dol_get_fiche_end();

// Tooltip container
print '<div id="kundenkarte-tooltip" class="kundenkarte-tooltip"></div>';

llxFooter();
$db->close();

/**
 * Print tree recursively (root level - handles cable line assignment)
 */
function printTree($nodes, $contactid, $systemId, $canEdit, $canDelete, $langs, $level = 0, $typeFieldsMap = array(), $connectionsByTarget = array())
{
	foreach ($nodes as $node) {
		$hasChildren = !empty($node->children);
		$fieldValues = $node->getFieldValues();

		// Build tooltip data - only label, type and dynamic fields
		$tooltipData = array(
			'label' => $node->label,
			'type' => $node->type_label,
			'note_html' => $node->note_private ? nl2br(htmlspecialchars($node->note_private, ENT_QUOTES, 'UTF-8')) : '',
			'fields' => array()
		);

		// Collect fields for tooltip (show_in_hover) and tree label (show_in_tree)
		$treeInfoBadges = array();      // Fields to display as badges (right side)
		$treeInfoParentheses = array(); // Fields to display in parentheses (after label)

		if (!empty($typeFieldsMap[$node->fk_anlage_type])) {
			foreach ($typeFieldsMap[$node->fk_anlage_type] as $fieldDef) {
				// Handle header fields
				if ($fieldDef->field_type === 'header') {
					if ($fieldDef->show_in_hover) {
						$tooltipData['fields'][$fieldDef->field_code] = array(
							'label' => $fieldDef->field_label,
							'value' => '',
							'type' => 'header'
						);
					}
					continue;
				}

				$value = isset($fieldValues[$fieldDef->field_code]) ? $fieldValues[$fieldDef->field_code] : '';

				// Add to tooltip if show_in_hover
				if ($fieldDef->show_in_hover && $value !== '') {
					// Format date values
					$displayValue = $value;
					if ($fieldDef->field_type === 'date' && $value) {
						$displayValue = dol_print_date(strtotime($value), 'day');
					}
					$tooltipData['fields'][$fieldDef->field_code] = array(
						'label' => $fieldDef->field_label,
						'value' => $displayValue,
						'type' => $fieldDef->field_type
					);
				}

				// Add to tree label info if show_in_tree
				if ($fieldDef->show_in_tree && $value !== '') {
					// Format date for tree info too
					$displayVal = $value;
					if ($fieldDef->field_type === 'date' && $value) {
						$displayVal = dol_print_date(strtotime($value), 'day');
					}
					// Store as array with field info
					$fieldInfo = array(
						'label' => $fieldDef->field_label,
						'value' => $displayVal,
						'code' => $fieldDef->field_code,
						'type' => $fieldDef->field_type,
						'color' => $fieldDef->badge_color ?? ''
					);
					// Sort into badge or parentheses based on field setting
					$displayMode = $fieldDef->tree_display_mode ?? 'badge';
					if ($displayMode === 'parentheses') {
						$treeInfoParentheses[] = $fieldInfo;
					} else {
						$treeInfoBadges[] = $fieldInfo;
					}
				}
			}
		}

		// Show cable connections TO this node (BEFORE the element - cable appears above verbraucher)
		$hasConnection = !empty($connectionsByTarget[$node->id]);
		if ($hasConnection) {
			foreach ($connectionsByTarget[$node->id] as $conn) {
				// Build cable info (type + spec + length)
				$cableInfo = '';
				if ($conn->medium_type_label || $conn->medium_type_text) {
					$cableInfo = $conn->medium_type_label ?: $conn->medium_type_text;
				}
				if ($conn->medium_spec) {
					$cableInfo .= ($cableInfo ? ' ' : '').$conn->medium_spec;
				}
				if ($conn->medium_length) {
					$cableInfo .= ' ('.$conn->medium_length.')';
				}

				// If label exists, show cable info as badge. Otherwise show cable info as main text
				$mainText = $conn->label ? $conn->label : $cableInfo;
				$badgeText = $conn->label ? $cableInfo : '';

				$connEditUrl = dol_buildpath('/kundenkarte/anlage_connection.php', 1).'?id='.$conn->id.'&socid='.$node->fk_soc.'&contactid='.$id.'&system_id='.$systemId;
				print '<a href="'.$connEditUrl.'" class="kundenkarte-tree-conn">';
				print '<span class="conn-icon"><i class="fa fa-plug"></i></span>';
				if ($mainText) {
					print '<span class="conn-main">'.dol_escape_htmltag($mainText).'</span>';
				}
				if ($badgeText) {
					print ' <span class="conn-label">'.dol_escape_htmltag($badgeText).'</span>';
				}
				print '</a>';
			}
		}

		// CSS class based on whether node has its own cable connection
		$nodeClass = 'kundenkarte-tree-node';
		if (!$hasConnection && $level > 0) {
			$nodeClass .= ' no-cable'; // durchgeschleift - kein eigenes Kabel
		}
		print '<div class="'.$nodeClass.'">';
		print '<div class="kundenkarte-tree-item" data-anlage-id="'.$node->id.'">';

		// Toggle
		if ($hasChildren) {
			print '<span class="kundenkarte-tree-toggle"><i class="fa fa-chevron-down"></i></span>';
		} else {
			print '<span class="kundenkarte-tree-toggle" style="visibility:hidden;"><i class="fa fa-chevron-down"></i></span>';
		}

		// Icon with tooltip data
		$picto = $node->type_picto ? $node->type_picto : 'fa-cube';
		print '<span class="kundenkarte-tree-icon kundenkarte-tooltip-trigger" data-tooltip="'.htmlspecialchars(json_encode($tooltipData), ENT_QUOTES, 'UTF-8').'" data-anlage-id="'.$node->id.'">'.kundenkarte_render_icon($picto).'</span>';

		// Label with parentheses info (directly after label, only values)
		$viewUrl = $_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=view&anlage_id='.$node->id;
		print '<span class="kundenkarte-tree-label">'.dol_escape_htmltag($node->label);

		// Parentheses info directly after label (only values, no field names)
		if (!empty($treeInfoParentheses)) {
			$infoValues = array();
			foreach ($treeInfoParentheses as $info) {
				$infoValues[] = dol_escape_htmltag($info['value']);
			}
			print ' <span class="kundenkarte-tree-label-info">('.implode(', ', $infoValues).')</span>';
		}
		print '</span>';

		// Spacer to push badges to the right
		print '<span class="kundenkarte-tree-spacer"></span>';

		// Badges (far right, before actions)
		$defaultBadgeColor = getDolGlobalString('KUNDENKARTE_TREE_BADGE_COLOR', '#2a4a5e');
		if (!empty($treeInfoBadges)) {
			print '<span class="kundenkarte-tree-badges">';
			foreach ($treeInfoBadges as $info) {
				$badgeIcon = kundenkarte_get_field_icon($info['code'], $info['type']);
				// Use field-specific color if set, otherwise global default
				$fieldBadgeColor = !empty($info['color']) ? $info['color'] : $defaultBadgeColor;
				print '<span class="kundenkarte-tree-badge" title="'.dol_escape_htmltag($info['label']).'" style="background:linear-gradient(135deg, '.$fieldBadgeColor.' 0%, '.kundenkarte_adjust_color($fieldBadgeColor, -20).' 100%);">';
				print '<i class="fa '.$badgeIcon.'"></i> '.dol_escape_htmltag($info['value']);
				print '</span>';
			}
			print '</span>';
		}

		// File indicators
		if ($node->image_count > 0 || $node->doc_count > 0) {
			$totalFiles = $node->image_count + $node->doc_count;
			print '<span class="kundenkarte-tree-files">';
			print '<a href="'.$viewUrl.'#files" class="kundenkarte-tree-file-badge kundenkarte-tree-file-all" data-anlage-id="'.$node->id.'" title="'.$totalFiles.' '.($totalFiles == 1 ? 'Datei' : 'Dateien').'">';
			print '<i class="fa fa-paperclip"></i> '.$totalFiles;
			print '</a>';
			print '</span>';
		}

		// Type badge
		if ($node->type_short || $node->type_label) {
			$typeDisplay = $node->type_short ? $node->type_short : $node->type_label;
			print '<span class="kundenkarte-tree-type badge badge-secondary">'.dol_escape_htmltag($typeDisplay).'</span>';
		}

		// Actions
		print '<span class="kundenkarte-tree-actions">';
		print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=view&anlage_id='.$node->id.'" title="'.$langs->trans('View').'"><i class="fa fa-eye"></i></a>';
		if ($canEdit) {
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=create&parent_id='.$node->id.'" title="'.$langs->trans('AddChild').'"><i class="fa fa-plus"></i></a>';
			print '<a href="#" class="anlage-connection-add" data-anlage-id="'.$node->id.'" data-soc-id="'.$node->fk_soc.'" data-system-id="'.$systemId.'" title="'.$langs->trans('AddCableConnection').'"><i class="fa fa-plug"></i></a>';
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=edit&anlage_id='.$node->id.'" title="'.$langs->trans('Edit').'"><i class="fa fa-edit"></i></a>';
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=copy&anlage_id='.$node->id.'" title="'.$langs->trans('Copy').'"><i class="fa fa-copy"></i></a>';
		}
		if ($canDelete) {
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=delete&anlage_id='.$node->id.'" title="'.$langs->trans('Delete').'" class="deletelink"><i class="fa fa-trash"></i></a>';
		}
		print '</span>';

		print '</div>';

		// Children - vertical tree layout with multiple parallel cable lines
		if ($hasChildren) {
			// First pass: assign cable index to each child with cable
			$cableCount = 0;
			$childCableIndex = array(); // child_id => cable_index
			foreach ($node->children as $child) {
				if (!empty($connectionsByTarget[$child->id])) {
					$cableCount++;
					$childCableIndex[$child->id] = $cableCount;
				}
			}

			print '<div class="kundenkarte-tree-children" data-cable-count="'.$cableCount.'">';

			// Render children - each row has cable line columns on the left
			$prevHadCable = false;
			$isFirst = true;
			foreach ($node->children as $child) {
				$myCableIdx = isset($childCableIndex[$child->id]) ? $childCableIndex[$child->id] : 0;
				$hasOwnCable = !empty($connectionsByTarget[$child->id]);

				// Add spacer row before elements with their own cable (except first)
				if ($hasOwnCable && !$isFirst) {
					// Spacer row with active cable lines passing through
					$spacerActiveLines = array();
					$foundCurrent = false;
					foreach ($node->children as $c) {
						if ($c->id == $child->id) {
							$foundCurrent = true;
						}
						if ($foundCurrent && isset($childCableIndex[$c->id])) {
							$spacerActiveLines[] = $childCableIndex[$c->id];
						}
					}

					print '<div class="kundenkarte-tree-row spacer-row">';
					for ($i = $cableCount; $i >= 1; $i--) {
						$isActive = in_array($i, $spacerActiveLines);
						$lineClass = 'cable-line';
						if ($isActive) {
							$lineClass .= ' active';
						}
						print '<span class="'.$lineClass.'" data-line="'.$i.'"></span>';
					}
					print '<div class="kundenkarte-tree-node-content"></div>';
					print '</div>';
				}

				// Find which cable lines are still active (run past this row to children below)
				$childActiveLinesAfter = array();
				$foundCurrent = false;
				foreach ($node->children as $c) {
					if ($c->id == $child->id) {
						$foundCurrent = true;
						continue;
					}
					if ($foundCurrent && isset($childCableIndex[$c->id])) {
						$childActiveLinesAfter[] = $childCableIndex[$c->id];
					}
				}

				printTreeWithCableLines(array($child), $contactid, $systemId, $canEdit, $canDelete, $langs, $level + 1, $typeFieldsMap, $connectionsByTarget, $myCableIdx, $cableCount, $childActiveLinesAfter);

				$prevHadCable = $hasOwnCable;
				$isFirst = false;
			}
			print '</div>';
		}

		print '</div>';
	}
}

/**
 * Print tree with multiple parallel cable lines
 * Each child with its own cable gets a vertical line that runs from top past all siblings
 */
function printTreeWithCableLines($nodes, $contactid, $systemId, $canEdit, $canDelete, $langs, $level = 0, $typeFieldsMap = array(), $connectionsByTarget = array(), $myCableIndex = 0, $totalCables = 0, $activeLinesAfter = array())
{
	foreach ($nodes as $node) {
		$hasChildren = !empty($node->children);
		$hasConnection = !empty($connectionsByTarget[$node->id]);
		$fieldValues = $node->getFieldValues();

		// Build tooltip data
		$tooltipData = array(
			'label' => $node->label,
			'type' => $node->type_label,
			'note_html' => $node->note_private ? nl2br(htmlspecialchars($node->note_private, ENT_QUOTES, 'UTF-8')) : '',
			'fields' => array()
		);

		$treeInfoBadges = array();
		$treeInfoParentheses = array();
		if (!empty($typeFieldsMap[$node->fk_anlage_type])) {
			foreach ($typeFieldsMap[$node->fk_anlage_type] as $fieldDef) {
				if ($fieldDef->field_type === 'header') continue;
				$value = isset($fieldValues[$fieldDef->field_code]) ? $fieldValues[$fieldDef->field_code] : '';
				if ($fieldDef->show_in_hover && $value !== '') {
					$displayValue = $value;
					if ($fieldDef->field_type === 'date' && $value) {
						$displayValue = dol_print_date(strtotime($value), 'day');
					}
					$tooltipData['fields'][$fieldDef->field_code] = array(
						'label' => $fieldDef->field_label,
						'value' => $displayValue,
						'type' => $fieldDef->field_type
					);
				}
				if ($fieldDef->show_in_tree && $value !== '') {
					$displayVal = ($fieldDef->field_type === 'date' && $value) ? dol_print_date(strtotime($value), 'day') : $value;
					$fieldInfo = array(
						'label' => $fieldDef->field_label,
						'value' => $displayVal,
						'code' => $fieldDef->field_code,
						'type' => $fieldDef->field_type,
						'color' => $fieldDef->badge_color ?? ''
					);
					$displayMode = $fieldDef->tree_display_mode ?? 'badge';
					if ($displayMode === 'parentheses') {
						$treeInfoParentheses[] = $fieldInfo;
					} else {
						$treeInfoBadges[] = $fieldInfo;
					}
				}
			}
		}

		// All lines that need to be drawn for this row (active lines passing through + my line if I have cable)
		$allLines = $activeLinesAfter;
		if ($hasConnection && $myCableIndex > 0) {
			$allLines[] = $myCableIndex;
		}
		sort($allLines);

		// Cable connection row (BEFORE the element)
		if ($hasConnection) {
			foreach ($connectionsByTarget[$node->id] as $conn) {
				$cableInfo = '';
				if ($conn->medium_type_label || $conn->medium_type_text) {
					$cableInfo = $conn->medium_type_label ?: $conn->medium_type_text;
				}
				if ($conn->medium_spec) {
					$cableInfo .= ($cableInfo ? ' ' : '').$conn->medium_spec;
				}
				if ($conn->medium_length) {
					$cableInfo .= ' ('.$conn->medium_length.')';
				}

				$mainText = $conn->label ? $conn->label : $cableInfo;
				$badgeText = $conn->label ? $cableInfo : '';

				$connEditUrl = dol_buildpath('/kundenkarte/anlage_connection.php', 1).'?id='.$conn->id.'&socid='.$node->fk_soc.'&contactid='.$id.'&system_id='.$systemId;
				print '<div class="kundenkarte-tree-row">';

				// Draw vertical line columns (for cables passing through)
				// Reverse order: index 1 (first element) = rightmost, highest index = leftmost
				for ($i = $totalCables; $i >= 1; $i--) {
					$isActive = in_array($i, $activeLinesAfter);
					$isMyLine = ($i == $myCableIndex);
					$lineClass = 'cable-line';
					$inlineStyle = '';
					if ($isActive) {
						$lineClass .= ' active'; // Line continues down
					}
					if ($isMyLine) {
						$lineClass .= ' my-line conn-line'; // This is my cable line - ends here with horizontal
						// Calculate width: columns to the right * 15px + 8px to reach element border
						$columnsToRight = $i - 1;
						$horizontalWidth = ($columnsToRight * 15) + 8;
						$inlineStyle = ' style="--h-width: '.$horizontalWidth.'px;"';
					}
					print '<span class="'.$lineClass.'"'.$inlineStyle.' data-line="'.$i.'"></span>';
				}

				print '<a href="'.$connEditUrl.'" class="kundenkarte-tree-conn-content">';
				print '<span class="conn-icon"><i class="fa fa-plug"></i></span>';
				if ($mainText) {
					print '<span class="conn-main">'.dol_escape_htmltag($mainText).'</span>';
				}
				if ($badgeText) {
					print ' <span class="conn-label">'.dol_escape_htmltag($badgeText).'</span>';
				}
				print '</a>';
				print '</div>';
			}
		}

		// Node row
		$nodeClass = 'kundenkarte-tree-row node-row';
		if (!$hasConnection && $level > 0) {
			$nodeClass .= ' no-cable';
		}

		print '<div class="'.$nodeClass.'">';

		// Draw vertical line columns (for cables passing through)
		// Reverse order: index 1 (first element) = rightmost, highest index = leftmost
		for ($i = $totalCables; $i >= 1; $i--) {
			$isActive = in_array($i, $activeLinesAfter);
			$isMyLine = ($i == $myCableIndex && $hasConnection);
			$lineClass = 'cable-line';
			$inlineStyle = '';
			if ($isActive) {
				$lineClass .= ' active';
			}
			if ($isMyLine) {
				$lineClass .= ' my-line node-line'; // Horizontal connector to this node
				// Calculate width: columns to the right * 15px + 8px to reach element border
				$columnsToRight = $i - 1;
				$horizontalWidth = ($columnsToRight * 15) + 8;
				$inlineStyle = ' style="--h-width: '.$horizontalWidth.'px;"';
			}
			print '<span class="'.$lineClass.'"'.$inlineStyle.' data-line="'.$i.'"></span>';
		}

		print '<div class="kundenkarte-tree-node-content">';
		print '<div class="kundenkarte-tree-item" data-anlage-id="'.$node->id.'">';

		if ($hasChildren) {
			print '<span class="kundenkarte-tree-toggle"><i class="fa fa-chevron-down"></i></span>';
		} else {
			print '<span class="kundenkarte-tree-toggle" style="visibility:hidden;"><i class="fa fa-chevron-down"></i></span>';
		}

		$picto = $node->type_picto ? $node->type_picto : 'fa-cube';
		print '<span class="kundenkarte-tree-icon kundenkarte-tooltip-trigger" data-tooltip="'.htmlspecialchars(json_encode($tooltipData), ENT_QUOTES, 'UTF-8').'" data-anlage-id="'.$node->id.'">'.kundenkarte_render_icon($picto).'</span>';

		$viewUrl = $_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=view&anlage_id='.$node->id;
		// Label with parentheses info (only values, no field names)
		print '<span class="kundenkarte-tree-label">'.dol_escape_htmltag($node->label);
		if (!empty($treeInfoParentheses)) {
			$infoValues = array();
			foreach ($treeInfoParentheses as $info) {
				$infoValues[] = dol_escape_htmltag($info['value']);
			}
			print ' <span class="kundenkarte-tree-label-info">('.implode(', ', $infoValues).')</span>';
		}
		print '</span>';

		// Spacer to push badges to the right
		print '<span class="kundenkarte-tree-spacer"></span>';

		// Badges (far right)
		if (!empty($treeInfoBadges)) {
			$defaultBadgeColor = getDolGlobalString('KUNDENKARTE_TREE_BADGE_COLOR', '#2a4a5e');
			print '<span class="kundenkarte-tree-badges">';
			foreach ($treeInfoBadges as $info) {
				$badgeIcon = kundenkarte_get_field_icon($info['code'], $info['type']);
				$fieldBadgeColor = !empty($info['color']) ? $info['color'] : $defaultBadgeColor;
				print '<span class="kundenkarte-tree-badge" title="'.dol_escape_htmltag($info['label']).'" style="background:linear-gradient(135deg, '.$fieldBadgeColor.' 0%, '.kundenkarte_adjust_color($fieldBadgeColor, -20).' 100%);">';
				print '<i class="fa '.$badgeIcon.'"></i> '.dol_escape_htmltag($info['value']);
				print '</span>';
			}
			print '</span>';
		}

		// File indicators
		if ($node->image_count > 0 || $node->doc_count > 0) {
			$totalFiles = $node->image_count + $node->doc_count;
			print '<span class="kundenkarte-tree-files">';
			print '<a href="'.$viewUrl.'#files" class="kundenkarte-tree-file-badge kundenkarte-tree-file-all" data-anlage-id="'.$node->id.'" title="'.$totalFiles.' '.($totalFiles == 1 ? 'Datei' : 'Dateien').'">';
			print '<i class="fa fa-paperclip"></i> '.$totalFiles;
			print '</a>';
			print '</span>';
		}

		if ($node->type_short || $node->type_label) {
			$typeDisplay = $node->type_short ? $node->type_short : $node->type_label;
			print '<span class="kundenkarte-tree-type badge badge-secondary">'.dol_escape_htmltag($typeDisplay).'</span>';
		}

		print '<span class="kundenkarte-tree-actions">';
		print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=view&anlage_id='.$node->id.'" title="'.$langs->trans('View').'"><i class="fa fa-eye"></i></a>';
		if ($canEdit) {
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=create&parent_id='.$node->id.'" title="'.$langs->trans('AddChild').'"><i class="fa fa-plus"></i></a>';
			print '<a href="#" class="anlage-connection-add" data-anlage-id="'.$node->id.'" data-soc-id="'.$node->fk_soc.'" data-system-id="'.$systemId.'" title="'.$langs->trans('AddCableConnection').'"><i class="fa fa-plug"></i></a>';
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=edit&anlage_id='.$node->id.'" title="'.$langs->trans('Edit').'"><i class="fa fa-edit"></i></a>';
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=copy&anlage_id='.$node->id.'" title="'.$langs->trans('Copy').'"><i class="fa fa-copy"></i></a>';
		}
		if ($canDelete) {
			print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$contactid.'&system='.$systemId.'&action=delete&anlage_id='.$node->id.'" title="'.$langs->trans('Delete').'" class="deletelink"><i class="fa fa-trash"></i></a>';
		}
		print '</span>';
		print '</div>';
		print '</div>'; // node-content

		print '</div>'; // tree-row

		// Children
		if ($hasChildren) {
			// First pass: assign cable index to each child with cable
			$childCableCount = 0;
			$childCableIndex = array(); // child_id => cable_index
			foreach ($node->children as $child) {
				if (!empty($connectionsByTarget[$child->id])) {
					$childCableCount++;
					$childCableIndex[$child->id] = $childCableCount;
				}
			}

			print '<div class="kundenkarte-tree-children" data-cable-count="'.$childCableCount.'">';

			$prevHadCable = false;
			$isFirst = true;
			foreach ($node->children as $child) {
				$myCableIdx = isset($childCableIndex[$child->id]) ? $childCableIndex[$child->id] : 0;
				$hasOwnCable = !empty($connectionsByTarget[$child->id]);

				// Add spacer row before elements with their own cable (except first)
				if ($hasOwnCable && !$isFirst) {
					// Spacer row with active cable lines passing through
					$spacerActiveLines = array();
					$foundCurrent = false;
					foreach ($node->children as $c) {
						if ($c->id == $child->id) {
							$foundCurrent = true;
						}
						if ($foundCurrent && isset($childCableIndex[$c->id])) {
							$spacerActiveLines[] = $childCableIndex[$c->id];
						}
					}

					print '<div class="kundenkarte-tree-row spacer-row">';
					for ($i = $childCableCount; $i >= 1; $i--) {
						$isActive = in_array($i, $spacerActiveLines);
						$lineClass = 'cable-line';
						if ($isActive) {
							$lineClass .= ' active';
						}
						print '<span class="'.$lineClass.'" data-line="'.$i.'"></span>';
					}
					print '<div class="kundenkarte-tree-node-content"></div>';
					print '</div>';
				}

				// Find which cable lines are still active (run past this row to children below)
				$childActiveLinesAfter = array();
				$foundCurrent = false;
				foreach ($node->children as $c) {
					if ($c->id == $child->id) {
						$foundCurrent = true;
						continue;
					}
					if ($foundCurrent && isset($childCableIndex[$c->id])) {
						$childActiveLinesAfter[] = $childCableIndex[$c->id];
					}
				}

				printTreeWithCableLines(array($child), $contactid, $systemId, $canEdit, $canDelete, $langs, $level + 1, $typeFieldsMap, $connectionsByTarget, $myCableIdx, $childCableCount, $childActiveLinesAfter);

				$prevHadCable = $hasOwnCable;
				$isFirst = false;
			}
			print '</div>';
		}
	}
}

/**
 * Print tree options for select
 */
function printTreeOptions($nodes, $selected = 0, $excludeId = 0, $prefix = '', $level = 0)
{
	foreach ($nodes as $node) {
		if ($node->id == $excludeId) continue;

		$sel = ($node->id == $selected) ? ' selected' : '';
		$icon = !empty($node->type_picto) ? $node->type_picto : 'fa-cube';
		$color = !empty($node->type_color) ? $node->type_color : '#888';
		print '<option value="'.$node->id.'"'.$sel.' data-icon="'.$icon.'" data-color="'.$color.'">'.$prefix.dol_escape_htmltag($node->label).'</option>';

		if (!empty($node->children)) {
			printTreeOptions($node->children, $selected, $excludeId, $prefix.'── ', $level + 1);
		}
	}
}
