{% extends "index.twig" %}
{% block content %}
    <p><strong>The algorithms calculates the fastest route based on travel time in minutes, and the shortest way if different. </strong></p>
    <div class="calculator-container">
        <div class="form-group">
            <label for="startCity">Start town:</label>
            <select id="startCity"></select>
        </div>

        <div class="form-group">
            <label for="endCity">End town:&#160;&#160;</label>
            <select id="endCity"></select>
        </div>

        <h3> </h3>
        <button id="calculateBtn">Calculate routes</button>

        <h6><small>Routes update: 05/2025</small></h6>

        <h6 style="color: #1E90FF;">
            Note: Three towns are not used as transit stops because they don't have docks.
            It's nearly impossible to board: Shaif, Raospvan, Molam.
        </h6>
        <h6 style="color: #1E90FF;"> But you can go to these towns.</h6>

        <h4> </h4>
        <div id="result" style="font-size: 1.4em; margin: 20px 0; padding: 15px; border: 2px solid #333; border-radius: 8px; background-color: #f5f5f5;">
            <h2 style="margin-top: 0; color: #2c3e50; font-size: 1.0em; border-bottom: 1px solid #ddd; padding-bottom: 10px;"> </h2>
            <div class="path" id="pathResult" style="font-size: 1.2em; margin: 15px 0; font-weight: bold; color: #2980b9;"></div>
            <div class="distance" id="distanceResult" style="font-size: 1.3em; margin-top: 10px; padding: 8px; background-color: #e8f4fc; border-radius: 5px; font-weight: bold;"></div>
        </div>
    </div>

    <div id="dataTable"></div>


    {% block scripts %}
        <!-- Définir la variable BASE_URL pour JavaScript -->
        <script>const BASE_URL = "{{ base_url }}";</script>
        <!-- Include the separate JavaScript file -->
        <script src="{{ theme_url }}/fcts_data.inc.js"></script>
        <script>
            // Global variables to store data
            let cities = [];
            let connections = {};
            let travelTimes = {}; // Stores travel times between towns (in seconds)

            document.addEventListener('DOMContentLoaded', function() {
                // Load data, travel times, etc.
                loadData();
                loadTravelTimes();

                // Listener for the calculate button
                document.getElementById('calculateBtn').addEventListener('click', calculateRoute);
            });

            
            // Parse the travel times CSV
            function parseTravelTimesCSV(csv) {
                travelTimes = {};
                const lines = csv.split('\n');
                const headers = lines[0].split(',').map(header => header.trim());
                for (let i = 1; i < lines.length; i++) {
                    if (!lines[i].trim()) continue;
                    const values = lines[i].split(',').map(value => value.trim());
                    const fromCity = values[0];
                    if (!travelTimes[fromCity]) { travelTimes[fromCity] = {}; }
                    for (let j = 1; j < headers.length; j++) {
                        const toCity = headers[j];
                        const time = values[j];
                        travelTimes[fromCity][toCity] = (time && !isNaN(time)) ? parseInt(time, 10) : Infinity;
                    }
                    travelTimes[fromCity][fromCity] = 0;
                }
                console.log('Travel times loaded:', travelTimes);
            }


            // Parse HTML table data for connections
            function parseTableData(html) {
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');
                const table = doc.querySelector('table');
                if (!table) {
                    console.error('No data table found in the HTML doc');
                    loadData();
                    return;
                }
                const headers = Array.from(table.querySelectorAll('thead th')).slice(1)
                    .map(th => th.textContent.trim());
                cities = headers;
                const rows = Array.from(table.querySelectorAll('tbody tr'));
                rows.forEach((row, i) => {
                    const cityName = cities[i];
                    connections[cityName] = {};
                    const cells = Array.from(row.querySelectorAll('td')).slice(1);
                    cells.forEach((cell, j) => {
                        const value = cell.textContent.trim();
                        connections[cityName][cities[j]] = (value === 'x') ? 1 : Infinity;
                    });
                    connections[cityName][cityName] = 0;
                });
           //     displayTable();
                populateDropdowns();
            }


            function displayTable() {
                const tableContainer = document.getElementById('dataTable');
                let tableHTML = '<h4 style="font-family: Arial, sans-serif; color: #333; margin-bottom: 8px; font-size: 14px;">Connections Map in Veloren</h4>';
                tableHTML += '<table style="border-collapse: collapse; width: auto; font-family: Arial, sans-serif; box-shadow: 0 0 8px rgba(0,0,0,0.1); font-size: 10px;">';

                // En-tête du tableau
                tableHTML += '<thead><tr>';
                tableHTML += '<th style="border: 1px solid #ddd; padding: 2px; background-color: #f2f2f2;"></th>';
                cities.forEach(city => {
                    tableHTML += `<th style="border: 1px solid #ddd; padding: 2px; background-color: #f2f2f2;">${city}</th>`;
                });
                tableHTML += '</tr></thead>';

                // Corps du tableau
                tableHTML += '<tbody>';
                cities.forEach(cityFrom => {
                    tableHTML += `<tr><td style="border: 1px solid #ddd; padding: 2px; background-color: #fafafa;"><small>${cityFrom}</small></td>`;
                    cities.forEach(cityTo => {
                        const connected = connections[cityFrom][cityTo];
                        const displayValue = (connected === 0) ? '-' : (connected === 1 ? 'X' : '');
                        const cellStyle = displayValue === '' ? 'background-color: #ffffe0;' : '';
                        tableHTML += `<td style="border: 1px solid #ddd; padding: 1px; ${cellStyle} text-align: center;">${displayValue}</td>`;
                    });
                    tableHTML += '</tr>';
                });
                tableHTML += '</tbody></table>';

                tableContainer.innerHTML = tableHTML;
            }


            // Populate city dropdowns
            function populateDropdowns() {
                const startSelect = document.getElementById('startCity');
                const endSelect = document.getElementById('endCity');
                startSelect.innerHTML = '';
                endSelect.innerHTML = '';
                cities.forEach(city => {
                    startSelect.add(new Option(city, city));
                    endSelect.add(new Option(city, city));
                });
                if (cities.length > 1) {
                    endSelect.selectedIndex = 1;
                }
            }

            // Main calculation function updated to display both results
            function calculateRoute() {
                const startCity = document.getElementById('startCity').value;
                const endCity = document.getElementById('endCity').value;

                if (startCity === endCity) {
                    showError('Error: Please select two different towns.');
                    return;
                }

                const resultTime = fastestPathInMinutes(travelTimes, startCity, endCity);
                const resultSteps = minimumStepsPath(connections, startCity, endCity);

                // let outputHTML = "<h3>Results (waiting times at docks are shown separately):</h3>";
                let outputHTML = " ";

                // Fonction d'affichage mise à jour pour inclure en bout de ligne le temps total du trajet
                function formatRoute(title, path, stops, travelDuration, waitingDuration, totalDuration) {
                    return `<div style='margin-bottom:10px;'>
                    <h3>${title}: <small style='color: #3e9b83;'>${path.join(" → ")}</small></h3>
                    <p>
                      <strong>Number of Stops:</strong> ${stops} stop${stops > 1 ? "s" : ""} &nbsp;|&nbsp;
                      Travel : ${travelDuration} mn${travelDuration > 1 ? "s" : ""} &nbsp;+&nbsp;
                      Mean Waiting Time: ${waitingDuration} mn${waitingDuration > 1 ? "s" : ""} &nbsp;=&nbsp;
                      <strong>Total Duration:</strong> ${totalDuration} minute${totalDuration > 1 ? "s" : ""}
                    </p>
                </div>`;
                }

                // Process fastest route and compute separate durations.
                if (!resultTime.path) {
                    outputHTML += "<div><h3>Fastest Route:</h3><p>No path found.</p></div>";
                } else {
                    // Calcul du temps d'attente pour chaque segment, y compris le départ.
                    let waitTimeFastest = 0;
                    for (let i = 0; i < resultTime.path.length - 1; i++) {
                        waitTimeFastest += travelTimes[resultTime.path[i]][resultTime.path[i + 1]] / 2;
                    }
                    let travelTimeMinutesFastest = Math.round(resultTime.duration / 60);
                    let waitingMinutesFastest = Math.round(waitTimeFastest / 60);
                    let totalMinutesFastest = travelTimeMinutesFastest + waitingMinutesFastest;

                    outputHTML += formatRoute("Fastest Route", resultTime.path, resultTime.path.length - 1, travelTimeMinutesFastest, waitingMinutesFastest, totalMinutesFastest);
                }

                // Process the route by fewest stops (BFS) and compute durations similarly.
                if (!resultSteps.path) {
                    outputHTML += "<div><h3>Route by Fewest Stops:</h3><p>No path found.</p></div>";
                } else {
                    const stopsFewest = resultSteps.steps;
                    let travelTimeBFS = resultSteps.path.reduce((sum, town, i) =>
                        i < resultSteps.path.length - 1 ? sum + travelTimes[town][resultSteps.path[i + 1]] : sum, 0);
                    let waitTimeBFS = 0;
                    for (let i = 0; i < resultSteps.path.length - 1; i++) {
                        waitTimeBFS += travelTimes[resultSteps.path[i]][resultSteps.path[i + 1]] / 2;
                    }
                    let travelTimeMinutesBFS = Math.round(travelTimeBFS / 60);
                    let waitingMinutesBFS = Math.round(waitTimeBFS / 60);
                    let totalMinutesBFS = travelTimeMinutesBFS + waitingMinutesBFS;

                    outputHTML += stopsFewest < (resultTime.path ? resultTime.path.length - 1 : Infinity)
                        ? formatRoute("Route by Fewest Stops", resultSteps.path, stopsFewest, travelTimeMinutesBFS, waitingMinutesBFS, totalMinutesBFS) + "<h3>Choose your way!</h3>"
                        : "<div style='margin-bottom:10px;'><h3>Route by Fewest Stops:</h3><p>The number of stops is not fewer than the fastest route.</p></div>";


                }

                const resultDiv = document.getElementById("result");
                resultDiv.innerHTML = outputHTML;
                resultDiv.style.fontSize = "1.1em";
                resultDiv.style.display = "block";

            }

            // Function to display error messages in the result area.
            function showError(message) {
                const resultDiv = document.getElementById("result");
                resultDiv.innerHTML = `<span class="error">${message}</span>`;
                resultDiv.style.display = "block";
            }

            // BFS algorithm to compute the path with the fewest stops (segments)
            function minimumStepsPath(connections, start, end) {
                let queue = [start];
                let visited = {};
                let parent = {};
                visited[start] = true;
                parent[start] = null;

                while (queue.length > 0) {
                    let current = queue.shift();
                    if (current === end) break;
                    for (let neighbor in connections[current]) {
                        if (connections[current][neighbor] === 1 && !visited[neighbor]) {
                            visited[neighbor] = true;
                            parent[neighbor] = current;
                            queue.push(neighbor);
                        }
                    }
                }

                if (!visited[end]) return { path: null, steps: Infinity };

                let path = [];
                for (let node = end; node != null; node = parent[node]) {
                    path.unshift(node);
                }
                return { path: path, steps: path.length - 1 };
            }

            // Simple priority queue implementation
            class PriorityQueue {
                constructor() {
                    this.items = [];
                }
                enqueue(element, priority) {
                    this.items.push({ element, priority });
                    this.items.sort((a, b) => a.priority - b.priority);
                }
                dequeue() {
                    return this.items.shift();
                }
                isEmpty() {
                    return this.items.length === 0;
                }
            }

            // Dijkstra's algorithm applied to the travelTimes matrix
            function fastestPathInMinutes(matriceTemps, start, end) {
                const distances = {};
                const previous = {};
                const queue = new PriorityQueue();
                for (const node in matriceTemps) {
                    distances[node] = (node === start) ? 0 : Infinity;
                    previous[node] = null;
                    queue.enqueue(node, distances[node]);
                }
                while (!queue.isEmpty()) {
                    const current = queue.dequeue().element;
                    if (current === end) {
                        const path = [];
                        let node = end;
                        while (node !== null) {
                            path.unshift(node);
                            node = previous[node];
                        }
                        return { path, duration: distances[end] };
                    }
                    for (const neighbor in matriceTemps[current]) {
                        const travelTime = matriceTemps[current][neighbor];
                        const alt = distances[current] + travelTime;
                        if (alt < distances[neighbor]) {
                            distances[neighbor] = alt;
                            previous[neighbor] = current;
                            queue.enqueue(neighbor, alt);
                        }
                    }
                }
                return { path: null, duration: Infinity };
            }

            // Display result in the page
            function showResult(pathText, distanceText, isError = false) {
                const resultDiv = document.getElementById('result');
                const pathResult = document.getElementById('pathResult');
                const distanceResult = document.getElementById('distanceResult');
                resultDiv.style.display = 'block';
                if (isError) {
                    pathResult.innerHTML = `<span class="error">${pathText}</span>`;
                    distanceResult.textContent = '';
                } else {
                    pathResult.textContent = pathText;
                    distanceResult.textContent = distanceText;
                    }
            }

            // Fonction pour afficher l'image de la carte
            function displayMapImage() {
                // Créer un conteneur pour l'image si nécessaire
                let mapContainer = document.getElementById('mapContainer');
                if (!mapContainer) {
                    mapContainer = document.createElement('div');
                    mapContainer.id = 'mapContainer';
                    mapContainer.style.marginBottom = '20px';
                    mapContainer.style.textAlign = 'center';

                    // Insérer le conteneur avant la calculatrice
                    const calculatorContainer = document.querySelector('.calculator-container');
                    if (calculatorContainer) {
                        calculatorContainer.parentNode.insertBefore(mapContainer, calculatorContainer);
                    } else {
                        // Fallback: ajouter au début du contenu
                        const contentDiv = document.querySelector('.content');
                        if (contentDiv) {
                            contentDiv.insertBefore(mapContainer, contentDiv.firstChild);
                        } else {
                            document.body.insertBefore(mapContainer, document.body.firstChild);
                        }
                    }
                }

                // Créer l'image
                const mapImage = document.createElement('img');
                // Utiliser le chemin relatif pour l'image
                mapImage.src = BASE_URL + '/assets/map_veloren.png';
                mapImage.alt = 'Veloren Map';
                mapImage.style.maxWidth = '100%';
                mapImage.style.height = 'auto';
                mapImage.style.borderRadius = '8px';
                mapImage.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)';
                mapImage.style.margin = '10px 0';

                // Ajouter l'image au conteneur
                mapContainer.innerHTML = '';
                mapContainer.appendChild(mapImage);

                // Ajouter un titre pour l'image
                const mapTitle = document.createElement('h3');
                mapTitle.textContent = 'Veloren World Map';
                mapTitle.style.marginBottom = '10px';
                mapContainer.insertBefore(mapTitle, mapImage);
            }

            // Load data on startup
            loadData();
        </script>
    {% endblock %}
{% endblock %}

