403Webshell
Server IP : 103.233.193.20  /  Your IP : 216.73.216.169
Web Server : Apache/2
System : Linux host1.itclever.com 4.18.0-553.16.1.el8_10.x86_64 #1 SMP Thu Aug 8 17:47:08 UTC 2024 x86_64
User : oriscomadm ( 1120)
PHP Version : 5.6.40
Disable Function : exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
MySQL : ON |  cURL : ON |  WGET : OFF |  Perl : OFF |  Python : OFF |  Sudo : OFF |  Pkexec : OFF
Directory :  /home/oriscomadm/domains/oriscom.com/private_html/taxi_estimate/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/oriscomadm/domains/oriscom.com/private_html/taxi_estimate/driverqr.js
// ========================================================================================================
// SECTION 1: CONFIGURATION & STATE ส่วนกำหนดค่าคงที่ (Config) และตัวแปรสถานะหลักของระบบ
// ========================================================================================================

const CONFIG = {
    API_KEY: '4fc6a833488e90b3df56acc1388c198b',  // API Key ของ Longdo Map
    SESSION_ID: 'session_[timestamp]_[random]',   // ID เซสชันไม่ซ้ำกัน

    ROUTE_COLORS: {  // สีของเส้นทางบนแผนที่
        initial: { primary: '#A0AEC0', fallback: '#CBD5E0' },  // สีเทา
        main: { primary: '#1E90FF', fallback: '#63B3ED' },     // สีน้ำเงิน
        fastest: { primary: '#6A5ACD', fallback: '#9370DB' }   // สีม่วง
    }
}

const STATE = {
    currentLang: 'th',              // ภาษาที่ใช้ (th/en)
    selectedOrigin: null,           // จุดเริ่มต้นที่เลือก
    selectedDestination: null,      // จุดหมายปลายทางที่เลือก
    selectedRouteType: null,        // ประเภทเส้นทางที่เลือก (main/fastest)
    routeData: {},                  // ข้อมูลเส้นทางที่คำนวณแล้ว
    currentMapMode: 'origin',       // โหมดการคลิกแผนที่ (origin/destination)
    map: null,                      // ออบเจ็กต์แผนที่
    markers: { origin: null, destination: null },  // หมุดบนแผนที่
    searchTimeout: null,            // ตัวจับเวลาสำหรับการค้นหา
    isAutoLocating: false           // กำลังหาตำแหน่งอัตโนมัติหรือไม่
}

const ROUTE_CALC_STATE = {
    calculating: false,    // กำลังคำนวณอยู่หรือไม่
    currentStep: 0,        // ขั้นตอนปัจจุบัน (0-3)
    results: {},           // ผลลัพธ์การคำนวณแต่ละขั้นตอน

    steps: [  // 4 ขั้นตอนการคำนวณ
        { name: 'AllDrive_Distance', routeType: 'AllDrive', mode: longdo.RouteMode.Cost },
        { name: 'AllDrive_Traffic', routeType: 'AllDrive', mode: longdo.RouteMode.Traffic },
        { name: 'Road_Distance', routeType: 'Road', mode: longdo.RouteMode.Cost },
        { name: 'Road_Traffic', routeType: 'Road', mode: longdo.RouteMode.Traffic }
    ]
}

// ========================================================================================================
// SECTION 2: MARKER & ICON HELPERS ส่วนสร้างไอคอนหมุด (Marker) สำหรับแผนที่
// ========================================================================================================

const createMarkerIcon = (color, label) => {
    // สร้าง SVG หมุดสี่เหลี่ยมหยดน้ำ พร้อมตัวอักษร S (Start) หรือ E (End)
    const svg = `
        <svg width="40" height="50" xmlns="http://www.w3.org/2000/svg">
          <path d="M20 2C11.7 2 5 8.7 5 17c0 8.3 15 31 15 31s15-22.7 15-31c0-8.3-6.7-15-15-15z"
                fill="${color}" stroke="#fff" stroke-width="2"/>
          <circle cx="20" cy="17" r="11" fill="white"/>
          <text x="20" y="22" text-anchor="middle" font-size="16" font-weight="bold" fill="${color}">${label}</text>
        </svg>
    `.trim();

    return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`;
}

const MARKERS = {
    green: createMarkerIcon('#22c55e', 'S'),  // หมุดสีเขียว (จุดเริ่มต้น)
    red: createMarkerIcon('#ef4444', 'E')     // หมุดสีแดง (จุดปลายทาง)
}

// ========================================================================================================
// SECTION 3: GPS & LOCATION DETECTION จัดการการขอสิทธิ์ GPS และการหาตำแหน่งปัจจุบัน
// ========================================================================================================

async function checkAndRequestGPSPermission() {
    const t = TRANSLATIONS[STATE.currentLang];

    if (!navigator.geolocation) {
        console.error('⌠Geolocation is not supported by this browser');
        return false;
    }

    if (navigator.permissions && navigator.permissions.query) {
        try {
            const permissionStatus = await navigator.permissions.query({ name: 'geolocation' });
            console.log('📍 GPS Permission Status:', permissionStatus.state);

            if (permissionStatus.state === 'denied') {
                showGPSAlert(t.gps_denied_message);
                return false;
            } else if (permissionStatus.state === 'prompt') {
                showGPSAlert(t.gps_permission_message, true);
            }

            permissionStatus.addEventListener('change', function () {
                console.log('🔄 GPS permission changed to:', this.state);
                if (this.state === 'granted' && !STATE.selectedOrigin) {
                    autoDetectCurrentLocation();
                }
            });
        } catch (error) {
            console.log('⚠️ Permission API not fully supported:', error);
        }
    } else {
        console.log('⚠️ Permissions API not supported, requesting location directly');
        showGPSAlert(t.gps_permission_message, true);
    }

    return true;
}

function showGPSAlert(message, isInfo = false) {
    const alertDiv = document.createElement('div');
    alertDiv.style.cssText = `
        position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
        background: ${isInfo ? '#0d6efd' : '#dc3545'}; color: white;
        padding: 15px 25px; border-radius: 10px;
        box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 10000;
        max-width: 90%; text-align: center; font-size: 14px; line-height: 1.6;
        animation: slideDown 0.3s ease-out;
    `;
    alertDiv.innerHTML = `
        <div style="display: flex; align-items: center; gap: 10px;">
            <i class="bi bi-${isInfo ? 'info-circle' : 'exclamation-triangle'}" style="font-size: 24px;"></i>
            <div style="white-space: pre-line; text-align: left;">${message}</div>
        </div>
    `;

    document.body.appendChild(alertDiv);

    setTimeout(() => {
        alertDiv.style.animation = 'slideUp 0.2s ease-in';
        setTimeout(() => alertDiv.remove(), 200);
    }, 2000);


    if (!document.getElementById('gpsAlertStyle')) {
        const style = document.createElement('style');
        style.id = 'gpsAlertStyle';
        style.textContent = `
            @keyframes slideDown {
                from { transform: translate(-50%, -100%); opacity: 0; }
                to { transform: translate(-50%, 0); opacity: 1; }
            }
            @keyframes slideUp {
                from { transform: translate(-50%, 0); opacity: 1; }
                to { transform: translate(-50%, -100%); opacity: 0; }
            }
        `;
        document.head.appendChild(style);
    }
}

function autoDetectCurrentLocation() {
    const t = TRANSLATIONS[STATE.currentLang];

    if (STATE.isAutoLocating) {
        console.log('⚠️ Already detecting location...');
        return;
    }

    STATE.isAutoLocating = true;
    const originInput = document.getElementById('origin');

    originInput.value = t.auto_detecting_location;
    originInput.style.color = '#0d6efd';
    originInput.style.fontWeight = '300';

    console.log('📍 Auto-detecting current location...');

    navigator.geolocation.getCurrentPosition(
        (position) => {
            console.log('✓ Location detected:', position.coords);

            if (STATE.map) {
                STATE.map.location({
                    lon: position.coords.longitude,
                    lat: position.coords.latitude
                }, true);
                STATE.map.zoom(15);
            }

            reverseGeocode(
                position.coords.latitude,
                position.coords.longitude,
                'origin',
                true
            );

            STATE.isAutoLocating = false;
            showSuccessMessage(t.location_found);
        },
        (error) => {
            console.error('⌠GPS Error:', error);
            STATE.isAutoLocating = false;

            originInput.value = '';
            originInput.style.color = '';
            originInput.style.fontWeight = '';

            let errorMessage = t.alert_gps_error;
            switch (error.code) {
                case error.PERMISSION_DENIED:
                    errorMessage = t.gps_denied_message;
                    break;
                case error.POSITION_UNAVAILABLE:
                    errorMessage = "ไม่สามารถหาตำแหน่งได้ กรุณาตรวจสอบว่าเปิด GPS แล้ว";
                    break;
                case error.TIMEOUT:
                    errorMessage = "หาตำแหน่งล่าช้าเกินไป กรุณาลองใหม่อีกครั้ง";
                    break;
            }

            showGPSAlert(errorMessage);
        },
        {
            enableHighAccuracy: true,
            timeout: 10000,
            maximumAge: 0
        }
    );
}

function showSuccessMessage(message) {
    const successDiv = document.createElement('div');
    successDiv.style.cssText = `
        position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
        background: #198754; color: white; padding: 12px 20px;
        border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.2);
        z-index: 10000; font-size: 16px; animation: slideDown 0.3s ease-out;
    `;
    successDiv.textContent = message;

    document.body.appendChild(successDiv);

    setTimeout(() => {
        successDiv.style.animation = 'slideUp 0.3s ease-out';
        setTimeout(() => successDiv.remove(), 300);
    }, 3000);
}

// ========================================================================================================
// SECTION 4: LANGUAGE MANAGEMENT จัดการระบบหลายภาษา (ไทย / อังกฤษ)
// ========================================================================================================

function setLanguage(lang) {
    STATE.currentLang = lang;
    localStorage.setItem('language', lang);
    updateLanguage();
    updateLanguageSwitcher();
    reloadMap();
}

function updateLanguageSwitcher() {
    document.querySelectorAll('.lang-option').forEach(el => el.classList.remove('active'));
    document.getElementById('lang' + STATE.currentLang.toUpperCase()).classList.add('active');
}

function updateLanguage() {
    const t = TRANSLATIONS[STATE.currentLang];

    document.getElementById('pageTitle').textContent = t.page_title;
    document.documentElement.lang = STATE.currentLang;

    document.querySelectorAll('[data-i18n]').forEach(el => {
        const key = el.getAttribute('data-i18n');
        if (t[key]) el.textContent = t[key];
    });

    document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
        const key = el.getAttribute('data-i18n-placeholder');
        if (t[key]) el.placeholder = t[key];
    });

    updateLocationInputs();

    if (STATE.routeData.main && STATE.routeData.fastest) {
        displayRoutes(STATE.routeData.main, STATE.routeData.fastest);
        displayDebugInfo();
    }

    if (STATE.map) STATE.map.language(STATE.currentLang);

    console.log(`🌐 Language switched to: ${STATE.currentLang}`);
}

function updateLocationInputs() {
    const t = TRANSLATIONS[STATE.currentLang];

    if (STATE.selectedOrigin) {
        if (STATE.selectedOrigin.isCurrentLocation) {
            document.getElementById('origin').value = t.current_location;
        } else {
            reverseGeocode(STATE.selectedOrigin.lat, STATE.selectedOrigin.lon, 'origin', false);
        }
    }

    if (STATE.selectedDestination) {
        if (STATE.selectedDestination.isCurrentLocation) {
            document.getElementById('destination').value = t.current_location;
        } else {
            reverseGeocode(STATE.selectedDestination.lat, STATE.selectedDestination.lon, 'destination', false);
        }
    }
}

// ========================================================================================================
// SECTION 5: MAP MANAGEMENT จัดการการทำงานของแผนที่ Longdo
// ========================================================================================================

function initMap() {
    STATE.map = new longdo.Map({
        placeholder: document.getElementById('map'),
        language: STATE.currentLang,
        zoom: 12
    });

    STATE.map.Event.bind('click', function () {
        const loc = STATE.map.location(longdo.LocationMode.Pointer);
        handleMapClick(loc.lat, loc.lon);
    });

    STATE.map.location({ lon: 100.5, lat: 13.75 }, true);

    initRouteEventBinding();

    console.log('🗺️ Map initialized');
}

function reloadMap() {
    if (!STATE.map) return;

    const oldOrigin = STATE.selectedOrigin;
    const oldDestination = STATE.selectedDestination;

    document.getElementById('map').innerHTML = '';
    initMap();

    setTimeout(() => {
        if (oldOrigin) {
            updateLocation('origin', oldOrigin.name, oldOrigin.actualName, oldOrigin.lat, oldOrigin.lon, oldOrigin.isCurrentLocation);
        }
        if (oldDestination) {
            updateLocation('destination', oldDestination.name, oldDestination.actualName, oldDestination.lat, oldDestination.lon, oldDestination.isCurrentLocation);
        }
        if (STATE.routeData.main && STATE.routeData.fastest) {
            displayRoutes(STATE.routeData.main, STATE.routeData.fastest);
        }
    }, 300);

    console.log('🔄 Map reloaded for language change');
}

function setMapMode(mode) {
    STATE.currentMapMode = mode;
    console.log(`🎯 Map mode set to: ${mode}`);
}

function handleMapClick(lat, lon) {
    console.log(`📍 Map clicked: ${lat}, ${lon}`);
    reverseGeocode(lat, lon, STATE.currentMapMode, false);
}

// ========================================================================================================
// SECTION 6: GEOCODING
// ส่วนแปลงพิกัดภูมิศาสตร์ (latitude, longitude)
// ========================================================================================================

// --------------------------------------------------------------------------------------------------------
// reverseGeocode()
// ฟังก์ชันแปลงพิกัด (lat, lon) → ชื่อสถานที่
//
// พารามิเตอร์:
// lat                = ค่าละติจูด
// lon                = ค่าลองจิจูด
// type               = ประเภทตำแหน่ง ('origin' หรือ 'destination')
// isCurrentLocation  = เป็นตำแหน่งปัจจุบันจาก GPS หรือไม่ (true / false)
//
// การทำงาน:
// 1. เรียก Longdo Address API เพื่อขอข้อมูลที่อยู่จากพิกัด
// 2. นำข้อมูลที่ได้มาเรียบเรียงเป็นชื่อสถานที่
// 3. อัปเดตค่า input, marker และ STATE ของระบบ
// 4. หากเกิดข้อผิดพลาด จะใช้พิกัดแทนชื่อสถานที่
// --------------------------------------------------------------------------------------------------------
async function reverseGeocode(lat, lon, type, isCurrentLocation = false) {
    // ดึงข้อความตามภาษาปัจจุบัน (ไทย / อังกฤษ)
    const t = TRANSLATIONS[STATE.currentLang];

    try {
        // 🔥 เรียก API สองครั้ง: ครั้งแรกภาษาปัจจุบัน (สำหรับแสดงผล), ครั้งสองภาษาไทย (สำหรับบันทึก)

        // 1️⃣ เรียก API ด้วยภาษาปัจจุบัน (สำหรับแสดงใน UI)
        const responseCurrentLang = await fetch(
            `https://api.longdo.com/map/services/address?lon=${lon}&lat=${lat}&locale=${STATE.currentLang}&key=${CONFIG.API_KEY}`
        );
        const dataCurrentLang = await responseCurrentLang.json();
        const actualName = formatLocationName(dataCurrentLang, STATE.currentLang) || `${lat.toFixed(6)}, ${lon.toFixed(6)}`;

        // 2️⃣ เรียก API ด้วยภาษาไทย (สำหรับบันทึกลงฐานข้อมูล)
        let actualNameThai = actualName; // ค่าเริ่มต้น
        if (STATE.currentLang !== 'th') {
            // ถ้าภาษาปัจจุบันไม่ใช่ภาษาไทย ให้เรียก API อีกครั้งด้วยภาษาไทย
            try {
                const responseThai = await fetch(
                    `https://api.longdo.com/map/services/address?lon=${lon}&lat=${lat}&locale=th&key=${CONFIG.API_KEY}`
                );
                const dataThai = await responseThai.json();
                actualNameThai = formatLocationName(dataThai, 'th') || actualName;
                console.log(`🇹🇭 Thai name for database: ${actualNameThai}`);
            } catch (error) {
                console.error('⚠️ Failed to get Thai name, using current language:', error);
            }
        }

        // ชื่อที่แสดงใน UI: ถ้าเป็นตำแหน่งปัจจุบัน แสดง "(ตำแหน่งปัจจุบัน)" ถ้าไม่ใช่ แสดงชื่อจริง
        const displayName = isCurrentLocation ? t.current_location : actualName;

        // อัปเดตตำแหน่ง (ต้นทาง / ปลายทาง)
        updateLocation(
            type,
            displayName,    // ชื่อที่แสดงใน input
            actualName,     // ชื่อจริงตามภาษาปัจจุบัน
            actualNameThai, // ชื่อภาษาไทย (สำหรับบันทึกฐานข้อมูล)
            lat,
            lon,
            isCurrentLocation
        );

        console.log(`✓ Reverse geocode success: ${actualName} (Thai: ${actualNameThai})`);

    } catch (error) {
        // กรณีเรียก API ไม่สำเร็จ หรือเกิดข้อผิดพลาดอื่น ๆ
        console.error('⌠Reverse Geocode Error:', error);

        // ใช้พิกัด (lat, lon) เป็นชื่อสถานที่แทน
        const coordName = `${lat.toFixed(6)}, ${lon.toFixed(6)}`;
        const displayName = isCurrentLocation ? t.current_location : coordName;

        updateLocation(
            type,
            displayName,
            coordName,
            coordName, // ใช้พิกัดทั้งสองภาษา
            lat,
            lon,
            isCurrentLocation
        );
    }
}

// --------------------------------------------------------------------------------------------------------
// formatLocationName() ฟังก์ชันจัดรูปแบบชื่อสถานที่จากข้อมูล Address API
// พารามิเตอร์: data = ข้อมูลที่อยู่ที่ได้จาก Longdo API
// การทำงาน:
// 1. ตรวจสอบภาษาปัจจุบัน (ไทย / อังกฤษ)
// 2. นำข้อมูลที่อยู่แต่ละส่วนมาเรียงลำดับให้เหมาะสม
// 3. รวมเป็นข้อความเดียวเพื่อแสดงผลให้ผู้ใช้
// 4. หากไม่มีข้อมูลเพียงพอ จะคืนค่า null
// --------------------------------------------------------------------------------------------------------
function formatLocationName(data, lang = null) {
    const parts = [];                          // เก็บส่วนประกอบของชื่อสถานที่
    const isTH = (lang || STATE.currentLang) === "th";   // ตรวจสอบว่าเป็นภาษาไทยหรือไม่

    // เพิ่มเลขที่บ้าน (ถ้ามี)
    if (data.house_no) {
        parts.push(isTH ? `เลขที่ ${data.house_no}` : `No. ${data.house_no}`);
    }

    // รายการข้อมูลที่อยู่ตามลำดับความสำคัญ
    [
        'moo',                // หมู่
        'place',              // สถานที่
        'building',           // อาคาร
        'condominium',        // คอนโด
        'village',            // หมู่บ้าน
        'village_official',   // หมู่บ้าน (ทางการ)
        'sublane',            // ซอยย่อย
        'alley',              // ซอย
        'road',               // ถนน
        'subdistrict',        // แขวง / ตำบล
        'district',           // เขต / อำเภอ
        'province'            // จังหวัด
        , 'point'
    ].forEach(key => {
        // เพิ่มเฉพาะข้อมูลที่มีค่า
        if (data[key]) parts.push(data[key]);
    });

    // รวมชื่อสถานที่ทั้งหมดเป็นสตริงเดียว
    // หากไม่มีข้อมูลเลย ให้คืนค่า null
    return parts.length > 0 ? parts.join(' ') : null;
}

// ========================================================================================================
// SECTION 7: LOCATION UPDATE & MARKERS
// จัดการตำแหน่งต้นทาง / ปลายทาง, input และ marker บนแผนที่
// ========================================================================================================

function updateLocation(type, displayName, actualName, actualNameThai, lat, lon, isCurrentLocation = false) {

    // รวมข้อมูลตำแหน่งเป็น object เดียว
    const locationData = {
        name: displayName,           // ชื่อที่แสดงใน UI
        actualName: actualName,      // ชื่อจริงตามภาษาปัจจุบัน
        actualNameThai: actualNameThai, // 🔥 ชื่อภาษาไทย (สำหรับบันทึกฐานข้อมูล)
        lat,
        lon,
        isCurrentLocation
    };

    // ใช้ type เป็น id ของ input (origin / destination)
    const inputId = type;

    // กำหนดสี marker ตามประเภทตำแหน่ง
    const markerColor = type === 'origin' ? MARKERS.green : MARKERS.red;

    // บันทึกตำแหน่งต้นทางลง STATE
    if (type === 'origin') {
        STATE.selectedOrigin = locationData;
    }
    // บันทึกตำแหน่งปลายทางลง STATE
    else {
        STATE.selectedDestination = locationData;
    }

    // ดึง input ตาม id
    const input = document.getElementById(inputId);

    // แสดงชื่อสถานที่ใน input (แสดงชื่อ UI)
    input.value = displayName;

    // ถ้าเป็นตำแหน่งปัจจุบัน → เปลี่ยนสีตัวอักษร
    input.style.color = isCurrentLocation ? '#198754' : '';

    // ถ้าเป็นตำแหน่งปัจจุบัน → ทำตัวหนา
    input.style.fontWeight = isCurrentLocation ? '600' : '';

    // แสดงปุ่มล้างข้อมูล (X)
    toggleClearButton(inputId, true);

    // ถ้ามี marker เดิม → ลบออกก่อน
    if (STATE.markers[type]) {
        STATE.map.Overlays.remove(STATE.markers[type]);
    }

    // สร้าง marker ใหม่ตามพิกัด
    STATE.markers[type] = new longdo.Marker(
        { lat, lon },          // พิกัด marker
        {
            icon: {
                url: markerColor,      // ไอคอนตามสี
                offset: { x: 20, y: 50 } // ปรับตำแหน่งไอคอน
            },
            title: actualName          // ชื่อจริงแสดงบน marker
        }
    );

    // เพิ่ม marker ลงบนแผนที่
    STATE.map.Overlays.add(STATE.markers[type]);

    // เลื่อนแผนที่ไปยังตำแหน่งที่เลือก
    STATE.map.location({ lat, lon }, true);

    // แสดง log เพื่อ debug
    console.log(`📍 Location updated: ${type} = ${displayName} (${actualName})`);
}

function clearInput(type) {

    // ดึง input ที่ต้องการล้าง
    const input = document.getElementById(type);

    // ล้างค่าข้อความใน input
    input.value = '';

    // รีเซ็ตสีตัวอักษร
    input.style.color = '';

    // รีเซ็ตความหนาตัวอักษร
    input.style.fontWeight = '';

    // ล้างข้อมูลต้นทางใน STATE
    if (type === 'origin') {
        STATE.selectedOrigin = null;
    }
    // ล้างข้อมูลปลายทางใน STATE
    else {
        STATE.selectedDestination = null;
    }

    // ซ่อนปุ่มล้างข้อมูล
    toggleClearButton(type, false);

    // ถ้ามี marker → ลบออกจากแผนที่
    if (STATE.markers[type]) {
        STATE.map.Overlays.remove(STATE.markers[type]);
        STATE.markers[type] = null;
    }

    // ถ้าข้อมูลต้นทางหรือปลายทางไม่ครบ
    if (!STATE.selectedOrigin || !STATE.selectedDestination) {

        // ลบเส้นทางออกจากแผนที่
        if (STATE.map?.Route) STATE.map.Route.clear();

        // ซ่อนส่วนแสดงเส้นทาง
        const section = document.getElementById('routesSection');
        if (section) section.style.display = 'none';

        // ซ่อนปุ่มยืนยันเส้นทาง
        const confirm = document.getElementById('confirmBtn');
        if (confirm) confirm.style.display = 'none';

        // ซ่อน debug panel ตัวที่ 1
        const debug1 = document.getElementById('debug1');
        if (debug1) debug1.classList.remove('show');

        // ซ่อน debug panel ตัวที่ 2
        const debug2 = document.getElementById('debug2');
        if (debug2) debug2.classList.remove('show');

        // รีเซ็ตข้อมูลเส้นทางหลัก
        STATE.routeData = {};

        // รีเซ็ตข้อมูลเส้นทาง debug
        STATE.routeDataDebug = {};
    }

    // แสดง log ว่าล้างข้อมูลแล้ว
    console.log(`🗑️ Cleared: ${type}`);
}


function toggleClearButton(inputId, show) {

    // สร้าง id ปุ่มล้างข้อมูลจาก inputId
    const btnId =
        'clear' +
        inputId.charAt(0).toUpperCase() + // ตัวอักษรแรกเป็นพิมพ์ใหญ่
        inputId.slice(1);                 // ต่อด้วยตัวที่เหลือ

    // ดึงปุ่มล้างข้อมูล
    const btn = document.getElementById(btnId);

    // แสดงหรือซ่อนปุ่มด้วย class 'show'
    if (btn) {
        btn.classList.toggle('show', show);
    }
}

// ========================================================================================================
// SECTION 8: SEARCH & SUGGESTIONS
// จัดการค้นหาสถานที่ และแสดงรายการแนะนำ
// ========================================================================================================

async function searchPlace(keyword, element, isOrigin) {

    // ถ้าไม่มีคำค้น หรือเป็นค่าว่าง → ซ่อนกล่องแนะนำ
    if (!keyword || keyword.trim().length < 1) {
        element.style.display = 'none';
        return;
    }

    try {
        // สร้าง URL สำหรับค้นหาสถานที่จาก Longdo Search API
        const url =
            `https://search.longdo.com/mapsearch/json/search?` +
            `keyword=${encodeURIComponent(keyword)}` + // เข้ารหัสคำค้น
            `&limit=5` +                               // จำกัดผลลัพธ์ 5 รายการ
            `&locale=${STATE.currentLang}` +            // ภาษา
            `&key=${CONFIG.API_KEY}`;                   // API Key

        // เรียก API
        const response = await fetch(url);

        // แปลงผลลัพธ์เป็น JSON
        const data = await response.json();

        // แสดงรายการแนะนำ (ถ้าไม่มีข้อมูล ส่ง array ว่าง)
        displaySuggestions(data?.data || [], element, isOrigin);

    } catch (error) {
        // แสดง error กรณีค้นหาล้มเหลว
        console.error('⌠Search Error:', error);

        // แสดงกล่องแนะนำแบบว่าง
        displaySuggestions([], element, isOrigin);
    }
}

function displaySuggestions(places, element, isOrigin) {

    // ดึงข้อความตามภาษาปัจจุบัน
    const t = TRANSLATIONS[STATE.currentLang];

    // ล้างรายการแนะนำเดิม
    element.innerHTML = '';

    // สร้างรายการ "ใช้ตำแหน่งปัจจุบัน"
    // แสดง "ใช้ตำแหน่งปัจจุบัน" เฉพาะช่องต้นทาง (Origin)
    if (isOrigin) {
        const currentItem = document.createElement('div');
        currentItem.className = 'suggestion-item current-location-item';

        currentItem.innerHTML = `
        <i class="bi bi-crosshair text-success me-2"></i>
        <strong>${t.use_current_location}</strong>
    `;

        currentItem.onclick = () => {
            useCurrentLocation(true); // ชัดเจนว่าเป็น origin
            element.style.display = 'none';
        };

        element.appendChild(currentItem);
    }

    // ถ้ามีผลลัพธ์จากการค้นหา
    if (places.length > 0) {

        // สร้างเส้นแบ่งหัวข้อ "ผลการค้นหา"
        const separator = document.createElement('div');
        separator.className = 'suggestion-separator';
        separator.textContent = t.search_results;
        element.appendChild(separator);

        // เรียงชื่อสถานที่ตามตัวอักษร
        places.sort((a, b) =>
            (a.name || "").localeCompare(b.name || "", "th")
        );

        // วนลูปแสดงแต่ละสถานที่
        places.forEach(place => {

            // สร้าง item แนะนำ
            const item = document.createElement('div');
            item.className = 'suggestion-item';

            // HTML ของรายการสถานที่
            item.innerHTML = `
                <i class="bi bi-geo-alt text-secondary me-2"></i>
                <div>
                    <div><strong>${place.name}</strong></div>
                    ${place.address
                    ? `<div class="text-muted small">${place.address}</div>`
                    : ''
                }
                </div>
            `;

            // เมื่อคลิก → แปลงพิกัดเป็นชื่อสถานที่
            item.onclick = async () => {
                await reverseGeocode(
                    place.lat,                            // ละติจูด
                    place.lon,                            // ลองจิจูด
                    isOrigin ? 'origin' : 'destination',  // ประเภทตำแหน่ง
                    false                                 // ไม่ใช่ GPS
                );
                element.style.display = 'none';
            };

            // เพิ่ม item ลงในกล่องแนะนำ
            element.appendChild(item);
        });
    }

    // แสดงกล่องแนะนำ
    element.style.display = 'block';
}

function useCurrentLocation(isOrigin) {

    // ดึงข้อความตามภาษาปัจจุบัน
    const t = TRANSLATIONS[STATE.currentLang];

    // ถ้าเบราว์เซอร์ไม่รองรับ GPS
    if (!navigator.geolocation) {
        alert(t.alert_gps_error);
        return;
    }

    // เลือก input ตามประเภท (ต้นทาง / ปลายทาง)
    const inputId = isOrigin ? 'origin' : 'destination';
    const inputEl = document.getElementById(inputId);

    // แสดงข้อความกำลังดึงตำแหน่ง
    inputEl.value = t.getting_location;

    // ขอพิกัดจาก GPS
    navigator.geolocation.getCurrentPosition(

        // กรณีได้พิกัดสำเร็จ
        pos => {
            const lat = pos.coords.latitude;   // ละติจูด
            const lon = pos.coords.longitude;  // ลองจิจูด

            // เลื่อนแผนที่ไปยังตำแหน่งปัจจุบัน
            STATE.map.location({ lon, lat }, true);

            // ซูมเข้า
            STATE.map.zoom(15);

            // แปลงพิกัดเป็นชื่อสถานที่
            reverseGeocode(lat, lon, inputId, true);
        },

        // กรณีเกิดข้อผิดพลาด
        error => {
            console.error('⌠GPS Error:', error);
            alert(t.alert_gps_error);
            inputEl.value = '';
        },

        // ตั้งค่าการดึง GPS
        {
            enableHighAccuracy: true, // ความแม่นยำสูง
            timeout: 10000,           // หมดเวลา 10 วินาที
            maximumAge: 0             // ไม่ใช้ตำแหน่งเก่า
        }
    );
}


// ========================================================================================================
// SECTION 9: ROUTE CALCULATION
// ========================================================================================================

function initRouteEventBinding() {
    STATE.map.Event.bind('guideComplete', function () {
        if (!ROUTE_CALC_STATE.calculating) return;

        const step = ROUTE_CALC_STATE.steps[ROUTE_CALC_STATE.currentStep];

        try {
            const distance = STATE.map.Route.distance();
            const distanceText = STATE.map.Route.distance(true);
            const interval = STATE.map.Route.interval();
            const intervalText = STATE.map.Route.interval(true);

            console.log(`✓ ${step.label}: ${distanceText}, ${intervalText}`);

            ROUTE_CALC_STATE.results[step.name] = {
                distance: distance,
                interval: interval,
                distanceText: distanceText,
                intervalText: intervalText
            };

            ROUTE_CALC_STATE.currentStep++;

            if (ROUTE_CALC_STATE.currentStep < ROUTE_CALC_STATE.steps.length) {
                calculateNextStep();
            } else {
                finishRouteCalculation();
            }

        } catch (error) {
            console.error('⌠Route calculation error:', error);
            ROUTE_CALC_STATE.calculating = false;
            document.getElementById('loadingSpinner').classList.remove('active');
            alert('เกิดข้อผิดพลาดในการคำนวณเส้นทาง');
        }
    });

    console.log('✓ Route event binding initialized');
}

function searchRoute() {
    const t = TRANSLATIONS[STATE.currentLang];

    if (!STATE.selectedOrigin || !STATE.selectedDestination) {
        alert(t.alert_select_locations);
        return;
    }

    ROUTE_CALC_STATE.calculating = true;
    ROUTE_CALC_STATE.currentStep = 0;
    ROUTE_CALC_STATE.results = {};

    document.getElementById('loadingSpinner').classList.add('active');
    document.getElementById('routesSection').style.display = 'none';
    document.getElementById('confirmBtn').style.display = 'none';

    console.log('🔍 Starting route calculation...');

    STATE.map.Route.clear();
    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedOrigin.lon,
        lat: STATE.selectedOrigin.lat
    }));
    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedDestination.lon,
        lat: STATE.selectedDestination.lat
    }));

    calculateNextStep();
}

function calculateNextStep() {
    const step = ROUTE_CALC_STATE.steps[ROUTE_CALC_STATE.currentStep];

    console.log(`🔍 Step ${ROUTE_CALC_STATE.currentStep + 1}/4: ${step.label}`);

    if (step.routeType === 'AllDrive') {
        STATE.map.Route.enableRoute(longdo.RouteType.Tollway, true);
    } else {
        STATE.map.Route.enableRoute(longdo.RouteType.AllDrive, false);
        STATE.map.Route.enableRoute(longdo.RouteType.Road, true);
    }

    STATE.map.Route.mode(step.mode);
    STATE.map.Route.search();
}

function finishRouteCalculation() {
    console.log('✓ All routes calculated!');

    ROUTE_CALC_STATE.calculating = false;

    STATE.routeData = {
        main: {
            data: [{
                distance: ROUTE_CALC_STATE.results.AllDrive_Distance.distance,
                interval: ROUTE_CALC_STATE.results.AllDrive_Distance.interval,
                distanceText: ROUTE_CALC_STATE.results.AllDrive_Distance.distanceText,
                intervalText: ROUTE_CALC_STATE.results.AllDrive_Distance.intervalText
            }]
        },
        fastest: {
            data: [{
                distance: ROUTE_CALC_STATE.results.Road_Distance.distance,
                interval: ROUTE_CALC_STATE.results.Road_Distance.interval,
                distanceText: ROUTE_CALC_STATE.results.Road_Distance.distanceText,
                intervalText: ROUTE_CALC_STATE.results.Road_Distance.intervalText
            }]
        }
    };

    STATE.routeDataDebug = {
        main: {
            Distance: {
                data: [{
                    distance: ROUTE_CALC_STATE.results.AllDrive_Distance.distance,
                    interval: ROUTE_CALC_STATE.results.AllDrive_Distance.interval
                }]
            },
            Traffic: {
                data: [{
                    distance: ROUTE_CALC_STATE.results.AllDrive_Traffic.distance,
                    interval: ROUTE_CALC_STATE.results.AllDrive_Traffic.interval
                }]
            }
        },
        fastest: {
            Distance: {
                data: [{
                    distance: ROUTE_CALC_STATE.results.Road_Distance.distance,
                    interval: ROUTE_CALC_STATE.results.Road_Distance.interval
                }]
            },
            Traffic: {
                data: [{
                    distance: ROUTE_CALC_STATE.results.Road_Traffic.distance,
                    interval: ROUTE_CALC_STATE.results.Road_Traffic.interval
                }]
            }
        }
    };

    displayRoutes(STATE.routeData.main, STATE.routeData.fastest);
    displayDebugInfo();
    displayRouteOnMap();
    sendDataToTestPage();

    document.getElementById('loadingSpinner').classList.remove('active');
    document.getElementById('routesSection').style.display = 'block';
    document.getElementById('debug1').classList.add('show');
    document.getElementById('debug2').classList.add('show');

    document.getElementById('routesSection').scrollIntoView({
        behavior: 'smooth',
        block: 'start'
    });

    console.log('✓ Routes displayed successfully');
}

function setRouteColor(routeType = 'initial') {
    const colors = CONFIG.ROUTE_COLORS[routeType] || CONFIG.ROUTE_COLORS.initial;

    try {
        STATE.map.call('Route.line', 'road', {
            lineColor: colors.primary,
            lineWidth: 3,
            borderColor: '#000000',
            borderWidth: 1
        });
    } catch (e) {
        try {
            STATE.map.Route.line('road', {
                lineColor: colors.fallback,
                lineWidth: 3
            });
        } catch (err2) {
            STATE.map.Route.option({
                lineColor: colors.fallback,
                lineWidth: 3
            });
        }
    }
}

function displayRouteOnMap() {
    STATE.map.Route.clear();

    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedOrigin.lon,
        lat: STATE.selectedOrigin.lat
    }, {
        icon: {
            url: MARKERS.green,
            offset: { x: 20, y: 50 }
        }
    }));

    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedDestination.lon,
        lat: STATE.selectedDestination.lat
    }, {
        icon: {
            url: MARKERS.red,
            offset: { x: 20, y: 50 }
        }
    }));

    setRouteColor();

    STATE.map.Route.mode(longdo.RouteMode.Cost);
    STATE.map.Route.enableRestrict(longdo.RouteRestrict.Bike, false);

    STATE.map.Route.search();

    console.log('🗺️ Initial route displayed on map');
}

// ========================================================================================================
// SECTION 10: ROUTE SELECTION
// ========================================================================================================

function selectRoute(type) {
    STATE.selectedRouteType = type;

    document.querySelectorAll('.route-card').forEach(c => c.classList.remove('selected'));
    document.getElementById(type === 'main' ? 'route1' : 'route2').classList.add('selected');

    //document.getElementById('confirmBtn').style.display = 'block';

    STATE.map.Route.clear();

    if (type === 'main') {
        STATE.map.Route.enableRoute(longdo.RouteType.Tollway, true);
    } else {
        STATE.map.Route.enableRoute(longdo.RouteType.AllDrive, false);
        STATE.map.Route.enableRoute(longdo.RouteType.Road, true);
    }

    STATE.map.Route.mode(longdo.RouteMode.Cost);
    STATE.map.Route.enableRestrict(longdo.RouteRestrict.Bike, false);

    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedOrigin.lon,
        lat: STATE.selectedOrigin.lat
    }, {
        icon: { url: MARKERS.green, offset: { x: 20, y: 50 } }
    }));

    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedDestination.lon,
        lat: STATE.selectedDestination.lat
    }, {
        icon: { url: MARKERS.red, offset: { x: 20, y: 50 } }
    }));

    setRouteColor(type);
    STATE.map.Route.label(false);
    STATE.map.Route.search();

    setTimeout(() => fitMapToRoute(), 800);

    console.log(`✓ Route selected: ${type}`);
}

function fitMapToRoute() {
    if (!STATE.selectedOrigin || !STATE.selectedDestination) return;

    try {
        const bounds = {
            minLon: Math.min(STATE.selectedOrigin.lon, STATE.selectedDestination.lon),
            minLat: Math.min(STATE.selectedOrigin.lat, STATE.selectedDestination.lat),
            maxLon: Math.max(STATE.selectedOrigin.lon, STATE.selectedDestination.lon),
            maxLat: Math.max(STATE.selectedOrigin.lat, STATE.selectedDestination.lat)
        };

        const padding = 0.15;
        const lonPad = (bounds.maxLon - bounds.minLon) * padding || 0.01;
        const latPad = (bounds.maxLat - bounds.minLat) * padding || 0.01;

        bounds.minLon -= lonPad;
        bounds.maxLon += lonPad;
        bounds.minLat -= latPad;
        bounds.maxLat += latPad;

        STATE.map.bound(bounds, true);

        console.log('🗺️ Map fitted to route bounds');
    } catch (err) {
        console.error('⌠Fit map error:', err);

        STATE.map.location({
            lon: (STATE.selectedOrigin.lon + STATE.selectedDestination.lon) / 2,
            lat: (STATE.selectedOrigin.lat + STATE.selectedDestination.lat) / 2
        }, true);
        STATE.map.zoom(10, true);
    }
}

// ========================================================================================================
// SECTION 11: FARE CALCULATION
// ========================================================================================================

function calculateTaxiFare(distanceKm, timeSeconds) {
    let fare = 35;

    if (distanceKm > 1) {
        let remaining = distanceKm - 1;

        const rateSteps = [
            { limit: 1, rate: 6.5 },
            { limit: 8, rate: 6.5 },
            { limit: 10, rate: 7 },
            { limit: 20, rate: 8 },
            { limit: 20, rate: 8.5 },
            { limit: 20, rate: 9 },
            { limit: Infinity, rate: 10.5 }
        ];

        rateSteps.forEach(({ limit, rate }) => {
            if (remaining > 0) {
                const dist = Math.min(remaining, limit);
                fare += dist * rate;
                remaining -= dist;
            }
        });
    }

    fare += (timeSeconds / 60) * 0;

    return Math.round(fare);
}

// ========================================================================================================
// SECTION 12: DISPLAY RESULTS
// ========================================================================================================

function displayRoutes(routeMain, routeFastest) {
    const t = TRANSLATIONS[STATE.currentLang];

    const main = routeMain.data[0];
    const fastest = routeFastest.data[0];

    const mainKM = Number(main.distance) / 1000 || 0;
    const fastestKM = Number(fastest.distance) / 1000 || 0;

    const mainTraffic = STATE.routeDataDebug.main.Distance.data[0];
    const mainNoTraffic = STATE.routeDataDebug.main.Traffic.data[0];
    const mainExtraTime = Math.max(mainNoTraffic.interval - mainTraffic.interval, 0);

    const fastestTraffic = STATE.routeDataDebug.fastest.Distance.data[0];
    const fastestNoTraffic = STATE.routeDataDebug.fastest.Traffic.data[0];
    const fastestExtraTime = Math.max(fastestNoTraffic.interval - fastestTraffic.interval, 0);

    const mainTrafficFare = Math.round((mainExtraTime / 60) * 3);
    const fastestTrafficFare = Math.round((fastestExtraTime / 60) * 3);

    const mainFare = calculateTaxiFare(mainKM, main.interval) + mainTrafficFare;
    const fastestFare = calculateTaxiFare(fastestKM, fastest.interval) + fastestTrafficFare;

    const mainTotalTime = main.interval + mainExtraTime;
    const fastestTotalTime = fastest.interval + fastestExtraTime;

    document.getElementById('dist1').textContent = `${mainKM.toFixed(1)} ${t.km}`;
    document.getElementById('time1').textContent = formatTime(mainTotalTime);
    document.getElementById('cost1').textContent = `${mainFare} ${t.baht}`;

    document.getElementById('dist2').textContent = `${fastestKM.toFixed(1)} ${t.km}`;
    document.getElementById('time2').textContent = formatTime(fastestTotalTime);
    document.getElementById('cost2').textContent = `${fastestFare} ${t.baht}`;

    console.log(`📌 Main(AllDrive): เวลา=${formatTime(mainTotalTime)} ค่าโดยสาร=${mainFare}฿ (รถติด +${mainTrafficFare}฿)`);
    console.log(`📌 Fastest(Road): เวลา=${formatTime(fastestTotalTime)} ค่าโดยสาร=${fastestFare}฿ (รถติด +${fastestTrafficFare}฿)`);

    window.routeDataForSave = {
        origin_lat: STATE.selectedOrigin.lat,
        origin_lon: STATE.selectedOrigin.lon,
        destination_lat: STATE.selectedDestination.lat,
        destination_lon: STATE.selectedDestination.lon,
        main_distance_km: mainKM,
        main_time_seconds: mainTotalTime,
        main_fare: mainFare,
        no_tollway_distance_km: fastestKM,
        no_tollway_time_seconds: fastestTotalTime,
        no_tollway_fare: fastestFare
    };

    console.log('💾 Route data prepared for saving:', window.routeDataForSave);

    sendToTestPage({
        origin: {
            name: STATE.selectedOrigin.actualName || STATE.selectedOrigin.name || document.getElementById('origin').value,
            lat: STATE.selectedOrigin.lat,
            lon: STATE.selectedOrigin.lon
        },
        destination: {
            name: STATE.selectedDestination.actualName || STATE.selectedDestination.name || document.getElementById('destination').value,
            lat: STATE.selectedDestination.lat,
            lon: STATE.selectedDestination.lon
        },
        mainRoute: {
            distance: mainKM.toFixed(1),
            time: formatTime(mainTotalTime),
            fare: mainFare
        },
        NoTollwayRoute: {
            distance: fastestKM.toFixed(1),
            time: formatTime(fastestTotalTime),
            fare: fastestFare
        }
    });
}

function displayDebugInfo() {
    const t = TRANSLATIONS[STATE.currentLang];

    const mainTraffic = STATE.routeDataDebug.main.Distance.data[0];
    const mainNoTraffic = STATE.routeDataDebug.main.Traffic.data[0];

    const mainFareTraffic = calculateTaxiFare(mainTraffic.distance / 1000, mainTraffic.interval);
    const mainExtraTime = Math.max(mainNoTraffic.interval - mainTraffic.interval, 0);

    document.getElementById('debug1_dist_traffic').textContent = `${(mainTraffic.distance / 1000).toFixed(1)} ${t.km}`;
    document.getElementById('debug1_time_traffic').textContent = formatTime(mainTraffic.interval);
    document.getElementById('debug1_fare_traffic').textContent = `${mainFareTraffic} ${t.baht}`;

    document.getElementById('debug1_time_notraffic').textContent = formatTime(mainNoTraffic.interval);
    document.getElementById('debug1_extra_time').textContent = formatTime(mainExtraTime);

    const fastestTraffic = STATE.routeDataDebug.fastest.Distance.data[0];
    const fastestNoTraffic = STATE.routeDataDebug.fastest.Traffic.data[0];

    const fastestFareTraffic = calculateTaxiFare(fastestTraffic.distance / 1000, fastestTraffic.interval);
    const fastestExtraTime = Math.max(fastestNoTraffic.interval - fastestTraffic.interval, 0);

    document.getElementById('debug2_dist_traffic').textContent = `${(fastestTraffic.distance / 1000).toFixed(1)} ${t.km}`;
    document.getElementById('debug2_time_traffic').textContent = formatTime(fastestTraffic.interval);
    document.getElementById('debug2_fare_traffic').textContent = `${fastestFareTraffic} ${t.baht}`;

    document.getElementById('debug2_time_notraffic').textContent = formatTime(fastestNoTraffic.interval);
    document.getElementById('debug2_extra_time').textContent = formatTime(fastestExtraTime);

    console.log('🔍 Debug info displayed');
}

function formatTime(sec) {
    const t = TRANSLATIONS[STATE.currentLang];
    const min = Math.round(sec / 60);
    const h = Math.floor(min / 60);
    const m = min % 60;

    return h > 0 ? `${h} ${t.hr} ${m} ${t.min}` : `${m} ${t.min}`;
}

// ========================================================================================================
// SECTION 13: CONFIRM & SAVE
// ========================================================================================================

async function confirmRoute() {
    if (!window.routeDataForSave) {
        alert('กรุณารอการคำนวณเส้นทางให้เสร็จก่อน');
        return;
    }

    if (!STATE.selectedRouteType) {
        alert('กรุณาเลือกเส้นทางก่อนยืนยัน');
        return;
    }

    try {
        document.getElementById('confirmBtn').disabled = true;
        document.getElementById('confirmBtn').innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>กำลังบันทึก...';

        // 🔥 แปลง route_used เป็นชื่อที่ชัดเจน
        let routeUsedName;
        if (STATE.selectedRouteType === 'main') {
            routeUsedName = 'Main Route';
        } else if (STATE.selectedRouteType === 'fastest') {
            routeUsedName = 'Secondary Route';
        } else {
            routeUsedName = STATE.selectedRouteType; // fallback
        }

        const dataToSave = {
            // 🔥 ใช้ชื่อภาษาไทย (actualNameThai) สำหรับบันทึกลงฐานข้อมูล
            origin_name: STATE.selectedOrigin.actualNameThai || STATE.selectedOrigin.actualName,
            origin_lat: window.routeDataForSave.origin_lat,
            origin_lon: window.routeDataForSave.origin_lon,
            destination_name: STATE.selectedDestination.actualNameThai || STATE.selectedDestination.actualName,
            destination_lat: window.routeDataForSave.destination_lat,
            destination_lon: window.routeDataForSave.destination_lon,
            main_distance_km: window.routeDataForSave.main_distance_km,
            main_time_seconds: window.routeDataForSave.main_time_seconds,
            main_fare: window.routeDataForSave.main_fare,
            no_tollway_distance_km: window.routeDataForSave.no_tollway_distance_km,
            no_tollway_time_seconds: window.routeDataForSave.no_tollway_time_seconds,
            no_tollway_fare: window.routeDataForSave.no_tollway_fare,
            route_used: routeUsedName, // 🔥 'Main route' หรือ 'Secondary route'
            route_by: 'driver', // ระบุว่ามาจากหน้าคนขับ
            meter_id: null // ไม่มี meter_id ในหน้าคนขับ
        };

        console.log('📤 Sending data to server:', dataToSave);

        const response = await fetch('save_estimate.php', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(dataToSave)
        });

        const result = await response.json();
        console.log('📥 Server response:', result);

        if (result.success) {
            document.getElementById('successMessage').classList.add('active');
            document.getElementById('confirmBtn').style.display = 'none';

            generateQRCode(result.estimate_id);

            setTimeout(() => {
                document.getElementById('successMessage').classList.remove('active');
            }, 3000);

            console.log('✅ บันทึกสำเร็จ ID:', result.estimate_id);
        } else {
            alert('เกิดข้อผิดพลาด: ' + result.message);
            document.getElementById('confirmBtn').disabled = false;
            document.getElementById('confirmBtn').innerHTML = '<i class="bi bi-check-circle"></i> <span data-i18n="confirm_btn">ยืนยันเส้นทางนี้</span>';
        }

    } catch (error) {
        console.error('⌠Error:', error);
        alert('เกิดข้อผิดพลาดในการบันทึกข้อมูล');

        document.getElementById('confirmBtn').disabled = false;
        document.getElementById('confirmBtn').innerHTML = '<i class="bi bi-check-circle"></i> <span data-i18n="confirm_btn">ยืนยันเส้นทางนี้</span>';
    }
};

// ========================================================================================================
// SECTION 14: QR CODE
// ========================================================================================================

function generateQRCode() {
    const qrDiv = document.getElementById('qrcode');
    qrDiv.innerHTML = '';

    // ดึง URL เฉพาะโฟลเดอร์หลัก เช่น https://example.com/driver
    const baseUrl = window.location.href.split('/').slice(0, -1).join('/');

    // สร้าง QR Code (ลิงก์ไปหน้า passenger)
    new QRCode(qrDiv, {
        text: baseUrl + '/passengerqp.php?session=' + CONFIG.SESSION_ID,
        width: 180,
        height: 180,
        colorDark: '#0d1b3a',
        colorLight: '#ffffff',
        correctLevel: QRCode.CorrectLevel.H
    });
}


function toggleQR() {
    const qrBox = document.getElementById('qrcode-box');
    if (qrBox.style.display === 'none' || qrBox.style.display === '') {
        qrBox.style.display = 'flex';

        // เลื่อนหน้าจอไปล่างสุด
        setTimeout(() => {
            qrBox.scrollIntoView({
                behavior: 'smooth',
                block: 'end'
            });
        }, 100);
    } else {
        qrBox.style.display = 'none';
    }
}

// ========================================================================================================
// SECTION 15: TEST PAGE INTEGRATION
// ========================================================================================================

function sendDataToTestPage() {
    if (!STATE.selectedOrigin || !STATE.selectedDestination ||
        !STATE.routeData.main || !STATE.routeData.fastest) {
        console.log('⚠️ Cannot send to test page: Missing data');
        return;
    }

    try {
        const mainRoute = STATE.routeData.main.data[0];
        const NoTollwayRoute = STATE.routeData.fastest.data[0];

        const mainFare = calculateTaxiFare(mainRoute.distance / 1000, mainRoute.interval);
        const fastestFare = calculateTaxiFare(NoTollwayRoute.distance / 1000, NoTollwayRoute.interval);

        const testData = {
            timestamp: new Date().toISOString(),
            origin: {
                name: STATE.selectedOrigin.actualName || STATE.selectedOrigin.name,
                lat: STATE.selectedOrigin.lat.toFixed(6),
                lon: STATE.selectedOrigin.lon.toFixed(6)
            },
            destination: {
                name: STATE.selectedDestination.actualName || STATE.selectedDestination.name,
                lat: STATE.selectedDestination.lat.toFixed(6),
                lon: STATE.selectedDestination.lon.toFixed(6)
            },
            mainRoute: {
                type: 'มีทางด่วน (With Tollway)',
                distance: (mainRoute.distance / 1000).toFixed(1),
                time: formatTime(mainRoute.interval),
                fare: mainFare
            },
            NoTollwayRoute: {
                type: 'ไม่มีทางด่วน (No Tollway)',
                distance: (NoTollwayRoute.distance / 1000).toFixed(1),
                time: formatTime(NoTollwayRoute.interval),
                fare: fastestFare
            }
        };

        const storageKey = 'testRouteData_' + Date.now();
        localStorage.setItem(storageKey, JSON.stringify(testData));

        console.log('📤 Data sent to test page:', testData);
        console.log('🔑 Storage key:', storageKey);

        const allKeys = Object.keys(localStorage).filter(key => key.startsWith('testRouteData_'));
        if (allKeys.length > 10) {
            allKeys.sort();
            allKeys.slice(0, allKeys.length - 10).forEach(key => localStorage.removeItem(key));
        }

    } catch (error) {
        console.error('⌠Error sending data to test page:', error);
    }
}

function sendToTestPage(data) {
    try {
        const key = `testRouteData_${Date.now()}`;
        localStorage.setItem(key, JSON.stringify(data));

        console.log('🧪 Test data sent to localStorage:', key, data);

        const allKeys = Object.keys(localStorage)
            .filter(k => k.startsWith('testRouteData_'))
            .sort();

        if (allKeys.length > 5) {
            const keysToDelete = allKeys.slice(0, allKeys.length - 5);
            keysToDelete.forEach(k => localStorage.removeItem(k));
        }

        try {
            if (window.opener) {
                window.opener.postMessage({
                    type: 'routeData',
                    data: data
                }, '*');
            }
        } catch (e) {
            // Ignore postMessage errors
        }

    } catch (error) {
        console.error('⌠Error sending to test page:', error);
    }
}

// ========================================================================================================
// SECTION 16: EVENT LISTENERS
// ========================================================================================================

document.getElementById('origin').addEventListener('input', e => {
    toggleClearButton('origin', e.target.value.length > 0);

    clearTimeout(STATE.searchTimeout);
    STATE.searchTimeout = setTimeout(() =>
        searchPlace(e.target.value, document.getElementById('originSuggestions'), true), 300);
});

document.getElementById('destination').addEventListener('input', e => {
    toggleClearButton('destination', e.target.value.length > 0);

    clearTimeout(STATE.searchTimeout);
    STATE.searchTimeout = setTimeout(() =>
        searchPlace(e.target.value, document.getElementById('destinationSuggestions'), false), 300);
});

document.addEventListener('click', e => {
    if (!e.target.closest('.position-relative')) {
        document.getElementById('originSuggestions').style.display = 'none';
        document.getElementById('destinationSuggestions').style.display = 'none';
    }
});

document.getElementById('origin').addEventListener('focus', () => {
    const box = document.getElementById('originSuggestions');
    if (!box.innerHTML) displaySuggestions([], box, true);
    box.style.display = 'block';
});

document.getElementById('destination').addEventListener('focus', () => {
    const box = document.getElementById('destinationSuggestions');
    if (!box.innerHTML) displaySuggestions([], box, false);
    box.style.display = 'block';
});

// ========================================================================================================
// SECTION 17: INITIALIZATION
// ========================================================================================================

document.addEventListener('DOMContentLoaded', () => {
    updateLanguage();
    updateLanguageSwitcher();
    console.log('✓ DOM ready, language initialized');
});

window.addEventListener('load', async () => {
    console.log('🚀 System initializing...');

    initMap();
    generateQRCode();

    await new Promise(resolve => setTimeout(resolve, 500));

    const hasPermission = await checkAndRequestGPSPermission();
    if (hasPermission) {
        setTimeout(() => {
            autoDetectCurrentLocation();
        }, 300);
    }

    console.log('✓ System initialized');
});

Youez - 2016 - github.com/yon3zu
LinuXploit