<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VNC - %s</title>
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link rel="stylesheet" href="/novnc.css">
    <script src="/novnc/util/strings.js"></script>
    <script src="/novnc/util/logging.js"></script>
    <script src="/novnc/util/browser.js"></script>
    <script src="/novnc/util/element.js"></script>
    <script src="/novnc/util/events.js"></script>
    <script src="/novnc/util/eventtarget.js"></script>
    <script src="/novnc/util/int.js"></script>
    <script src="/novnc/util/cursor.js"></script>
    <script src="/novnc/util/md5.js"></script>
    <script src="/novnc/base64.js"></script>
    <script src="/novnc/websock.js"></script>
    <script src="/novnc/des.js"></script>
    <script src="/novnc/input/keysym.js"></script>
    <script src="/novnc/input/keysymdef.js"></script>
    <script src="/novnc/input/domkeytable.js"></script>
    <script src="/novnc/input/xtscancodes.js"></script>
    <script src="/novnc/input/util.js"></script>
    <script src="/novnc/input/keyboard.js"></script>
    <script src="/novnc/input/gesturehandler.js"></script>
    <script src="/novnc/display.js"></script>
    <script src="/novnc/inflator.js"></script>
    <script src="/novnc/deflator.js"></script>
    <script src="/novnc/encodings.js"></script>
    <script src="/novnc/ra2.js"></script>
    <script src="/novnc/decoders/raw.js"></script>
    <script src="/novnc/decoders/copyrect.js"></script>
    <script src="/novnc/decoders/rre.js"></script>
    <script src="/novnc/decoders/hextile.js"></script>
    <script src="/novnc/decoders/tight.js"></script>
    <script src="/novnc/decoders/tightpng.js"></script>
    <script src="/novnc/decoders/zrle.js"></script>
    <script src="/novnc/decoders/jpeg.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/adler32.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/constants.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/crc32.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/deflate.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/inffast.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/inflate.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/inftrees.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/messages.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/trees.js"></script>
    <script src="/novnc/vendor/pako/lib/zlib/zstream.js"></script>
    <script src="/novnc/rfb.js"></script>
    <style>
        .navbar-brand {
            font-weight: bold;
        }
        .vnc-container {
            background-color: #1e1e1e;
            color: #f8f8f2;
            border-radius: 8px;
            height: calc(100vh - 200px);
            min-height: 400px;
            overflow: hidden;
            position: relative;
        }
        .vnc-container.full-size {
            overflow: auto;
            max-height: calc(100vh - 200px);
            height: auto;
        }
        .vnc-container.full-size #noVNC_screen {
            min-width: fit-content;
            min-height: fit-content;
            height: auto;
        }
        /* GNOME-like window decorations */
        .vnc-window {
            border: 1px solid #ccc;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
        }
        .window-titlebar {
            background: linear-gradient(to bottom, #f0f0f0, #e0e0e0);
            border-bottom: 1px solid #ccc;
            padding: 4px 8px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            height: 32px;
        }
        .window-title {
            font-weight: bold;
            color: #333;
            font-size: 14px;
        }
        .window-controls {
            display: flex;
            align-items: center;
            gap: 4px;
        }
        .window-btn {
            width: 24px;
            height: 24px;
            border: none;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.2s;
        }
        .window-btn:hover {
            transform: scale(1.1);
        }
        .close-btn {
            background: #ff605c;
            color: white;
        }
        .close-btn:hover {
            background: #ff403c;
        }
        .maximize-btn {
            background: #28ca42;
            color: white;
        }
        .maximize-btn:hover {
            background: #24b83a;
        }
        .minimize-btn {
            background: #ffbd44;
            color: white;
            display: none; /* Hidden by default, shown in fullscreen */
        }
        .minimize-btn:hover {
            background: #ffad2c;
        }
        .zoom-btn {
            background: #17a2b8;
            color: white;
        }
        .zoom-btn:hover {
            background: #138496;
        }
        .zoom-btn.active {
            background: #007bff;
        }
        .zoom-btn.active:hover {
            background: #0056b3;
        }
        .window-content {
            background: #1e1e1e;
            padding: 8px;
        }
        /* Fullscreen styles */
        .vnc-window.fullscreen {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            border: none;
            border-radius: 0;
            z-index: 9999;
        }
        .vnc-window.fullscreen .vnc-container {
            height: calc(100vh - 40px) !important;
            min-height: calc(100vh - 40px) !important;
        }
        .vnc-window.fullscreen .minimize-btn {
            display: flex;
        }
        #noVNC_screen {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="/">
<i class="fas fa-desktop"></i> WSSSHD control panel</a>
<div class="navbar-nav ms-auto">
<span class="navbar-text me-3">VNC Session - %s</span>
<a class="nav-link" href="/logout">Logout</a>
</div></div></nav>
<div id="notification-area" class="position-fixed top-0 end-0 p-3" style="z-index: 1050;"></div>

<!-- Password Prompt Modal -->
<div class="modal fade" id="passwordModal" tabindex="-1" aria-labelledby="passwordModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="passwordModalLabel">VNC Authentication Required</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p>Please enter the VNC password to connect:</p>
        <div class="mb-3">
          <label for="vncPassword" class="form-label">Password</label>
          <input type="password" class="form-control" id="vncPassword" placeholder="Enter VNC password">
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-primary" id="submitPasswordBtn">Connect</button>
      </div>
    </div>
  </div>
</div>

<div class="container mt-4">
<div class="row">
    <div class="col-12">
        <div class="vnc-window">
            <div class="window-titlebar">
                <div class="window-title">
                    <i class="fas fa-desktop"></i> VNC Session - %s
                </div>
                <div class="window-controls">
                    <button id="connectBtn" class="btn btn-success btn-sm me-1" style="height: 24px; font-size: 12px; padding: 0 8px;">
                        <i class="fas fa-play"></i> Connect
                    </button>
                    <button id="disconnectBtn" class="btn btn-danger btn-sm me-1" disabled style="height: 24px; font-size: 12px; padding: 0 8px;">
                        <i class="fas fa-stop"></i> Disconnect
                    </button>
                    <button class="window-btn zoom-btn" title="Toggle Zoom (Scale/Fit)" id="zoomBtn">
                        <i class="fas fa-search-plus"></i>
                    </button>
                    <button class="window-btn minimize-btn" title="Exit Fullscreen">_</button>
                    <button class="window-btn maximize-btn" title="Fullscreen"><span class="maximize-icon">□</span></button>
                    <button class="window-btn close-btn" title="Disconnect">×</button>
                </div>
            </div>
            <div class="window-content">
                <div id="vnc" class="vnc-container w-100">
                    <div id="noVNC_screen">
                        <div id="noVNC_status">Click Connect to start VNC session</div>
                        <div id="noVNC_loading" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">
                            <div class="spinner-border text-primary mb-2" role="status">
                                <span class="visually-hidden">Loading...</span>
                            </div>
                            <div>Connecting to VNC server...</div>
                            <button id="cancelConnectBtn" class="btn btn-outline-danger btn-sm mt-2" style="display: none;">
                                <i class="fas fa-times"></i> Cancel
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Check if Base64 is loaded
setTimeout(function() {
    if (typeof window.Base64 === 'undefined') {
        console.error('[VNC-ERROR] Base64 is not defined! This will cause JPEG decoding to fail.');
    }
}, 100);

let rfb = null;
let connected = false;
let socketFrameSeq = 0;

document.getElementById('connectBtn').addEventListener('click', connect);
document.getElementById('disconnectBtn').addEventListener('click', disconnect);
document.getElementById('cancelConnectBtn').addEventListener('click', cancelConnect);

// Window control buttons
document.querySelector('.close-btn').addEventListener('click', disconnect);
document.querySelector('.maximize-btn').addEventListener('click', toggleFullscreen);
document.querySelector('.minimize-btn').addEventListener('click', toggleFullscreen);
document.getElementById('zoomBtn').addEventListener('click', toggleZoom);

function showNotification(message, type = 'info') {
    const notificationArea = document.getElementById('notification-area');
    const notification = document.createElement('div');
    notification.className = `alert alert-${type} alert-dismissible fade show`;
    notification.innerHTML = `${message}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>`;
    notificationArea.appendChild(notification);
    setTimeout(() => {
        if (notification.parentNode) {
            notification.remove();
        }
    }, 5000);
}

function toggleFullscreen() {
    const vncWindow = document.querySelector('.vnc-window');
    const maximizeBtn = document.querySelector('.maximize-btn');
    const maximizeIcon = maximizeBtn.querySelector('.maximize-icon');

    if (vncWindow.classList.contains('fullscreen')) {
        // Exit fullscreen
        vncWindow.classList.remove('fullscreen');
        maximizeIcon.textContent = '□';
        maximizeBtn.title = 'Fullscreen';
    } else {
        // Enter fullscreen
        vncWindow.classList.add('fullscreen');
        maximizeIcon.textContent = '▭'; // Restore icon
        maximizeBtn.title = 'Exit Fullscreen';
    }
}

function toggleZoom() {
    if (!rfb || !connected) return;

    const zoomBtn = document.getElementById('zoomBtn');
    const zoomIcon = zoomBtn.querySelector('i');
    const vncContainer = document.getElementById('vnc');

    if (zoomBtn.classList.contains('active')) {
        // Switch to scaled view (fit to window)
        zoomBtn.classList.remove('active');
        zoomBtn.title = 'Toggle Zoom (Scale/Fit)';
        zoomIcon.className = 'fas fa-search-plus';
        vncContainer.classList.remove('full-size');

        // Enable scaling, disable clipping
        rfb.scaleViewport = true;
        rfb.clipViewport = false;

        showNotification('Switched to scaled view (fit to window)', 'info');
    } else {
        // Switch to full-size view with scrollbars
        zoomBtn.classList.add('active');
        zoomBtn.title = 'Toggle Zoom (Actual Size)';
        zoomIcon.className = 'fas fa-search-minus';
        vncContainer.classList.add('full-size');

        // Disable scaling, enable clipping
        rfb.scaleViewport = false;
        rfb.clipViewport = true;

        // Force a resize to ensure canvas is properly sized for scrolling
        setTimeout(() => {
            const canvas = document.querySelector('#noVNC_screen canvas');
            if (canvas) {
                console.log('Canvas size after zoom toggle:', canvas.width, 'x', canvas.height);
                console.log('Container size:', vncContainer.clientWidth, 'x', vncContainer.clientHeight);
            }
        }, 100);

        showNotification('Switched to actual size view with scrollbars', 'info');
    }
}

function connect() {
    if (connected) return;

    // Hide the status text and show loading message
    document.getElementById('noVNC_status').style.display = 'none';
    document.getElementById('noVNC_loading').style.display = 'block';
    document.getElementById('cancelConnectBtn').style.display = 'inline-block';

    const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const wsUrl = wsProtocol + '//' + window.location.host + '/vnc/%s/ws';

    try {
        rfb = new RFB(document.getElementById('noVNC_screen'), wsUrl, {
            credentials: {},
            shared: true,
            repeaterID: '',
            wsProtocols: ['binary']
        });

        rfb.addEventListener('connect', () => {
            connected = true;
            document.getElementById('connectBtn').disabled = true;
            document.getElementById('disconnectBtn').disabled = false;
            // Hide loading message
            document.getElementById('noVNC_loading').style.display = 'none';
            showNotification('VNC session connected', 'success');

            // Reset frame sequence for new connection
            socketFrameSeq = 0;
        });



        rfb.addEventListener('disconnect', () => {
            connected = false;
            document.getElementById('connectBtn').disabled = false;
            document.getElementById('disconnectBtn').disabled = true;
            // Reset UI to initial state
            document.getElementById('noVNC_status').style.display = 'block';
            document.getElementById('noVNC_loading').style.display = 'none';
            document.getElementById('cancelConnectBtn').style.display = 'none';
            showNotification('VNC session disconnected', 'info');
        });

        rfb.addEventListener('credentialsrequired', (e) => {
            console.log('VNC credentials required:', e.detail.types);
            if (e.detail.types.includes('password')) {
                // Show password modal
                const passwordModal = new bootstrap.Modal(document.getElementById('passwordModal'));
                passwordModal.show();

                // Handle password submission
                const submitPassword = () => {
                    const password = document.getElementById('vncPassword').value;
                    if (password) {
                        rfb.sendCredentials({ password: password });
                        passwordModal.hide();
                        document.getElementById('vncPassword').value = ''; // Clear password field
                    }
                };

                document.getElementById('submitPasswordBtn').onclick = submitPassword;

                // Allow Enter key to submit
                document.getElementById('vncPassword').onkeydown = (e) => {
                    if (e.key === 'Enter') {
                        submitPassword();
                    }
                };

                // Handle modal close without password
                document.getElementById('passwordModal').addEventListener('hidden.bs.modal', () => {
                    if (!rfb._rfbCredentials.password) {
                        // If no password was provided, disconnect
                        showNotification('VNC connection cancelled - password required', 'warning');
                        disconnect();
                    }
                });
            }
        });

        rfb.addEventListener('securityfailure', (e) => {
            console.error('VNC security failure:', e.detail);
            // Show password modal again for retry
            const passwordModal = new bootstrap.Modal(document.getElementById('passwordModal'));
            document.getElementById('passwordModalLabel').textContent = 'VNC Authentication Failed';
            document.querySelector('#passwordModal .modal-body p').textContent = 'The password you entered is incorrect. Please try again:';
            document.getElementById('vncPassword').value = ''; // Clear previous password
            passwordModal.show();

            // Handle password resubmission
            const submitPassword = () => {
                const password = document.getElementById('vncPassword').value;
                if (password) {
                    rfb.sendCredentials({ password: password });
                    passwordModal.hide();
                    document.getElementById('vncPassword').value = ''; // Clear password field
                }
            };

            document.getElementById('submitPasswordBtn').onclick = submitPassword;

            // Allow Enter key to submit
            document.getElementById('vncPassword').onkeydown = (e) => {
                if (e.key === 'Enter') {
                    submitPassword();
                }
            };

            // Handle modal close without password
            document.getElementById('passwordModal').addEventListener('hidden.bs.modal', () => {
                if (!rfb._rfbCredentials.password) {
                    // If no password was provided, disconnect
                    showNotification('VNC connection cancelled - password required', 'warning');
                    disconnect();
                }
            });
        });

        rfb.addEventListener('clipboard', (e) => {
            // Handle clipboard data if needed
        });

    } catch (e) {
        console.error('Failed to create RFB:', e);
        showNotification('Failed to connect VNC: ' + e.message, 'danger');
    }
}

function disconnect() {
    if (rfb) {
        rfb.disconnect();
        rfb = null;
    }
    connected = false;
    document.getElementById('connectBtn').disabled = false;
    document.getElementById('disconnectBtn').disabled = true;
    // Reset UI to initial state
    document.getElementById('noVNC_status').style.display = 'block';
    document.getElementById('noVNC_loading').style.display = 'none';
    document.getElementById('cancelConnectBtn').style.display = 'none';
    location.reload();
}

function cancelConnect() {
    if (rfb) {
        rfb.disconnect();
        rfb = null;
    }
    connected = false;
    document.getElementById('connectBtn').disabled = false;
    document.getElementById('disconnectBtn').disabled = true;
    // Reset UI to initial state
    document.getElementById('noVNC_status').style.display = 'block';
    document.getElementById('noVNC_loading').style.display = 'none';
    document.getElementById('cancelConnectBtn').style.display = 'none';
    showNotification('VNC connection cancelled', 'warning');
}
</script>
</body>
</html>
