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/driverqrv4.js
// ========== CONFIGURATION (การตั้งค่าระบบ) ==========
const CONFIG = {
    // API Key สำหรับเข้าถึง Longdo Map Services
    API_KEY: '4fc6a833488e90b3df56acc1388c198b',

    // Session ID สำหรับแยกข้อมูลแต่ละการใช้งาน
    SESSION_ID: 'session_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9),

    // สีเส้นทางบนแผนที่
    ROUTE_COLORS: {
        initial: {
            primary: '#A0AEC0', // เทาอมฟ้า (เส้นแสดงครั้งแรก)
            fallback: '#CBD5E0' // เทาอ่อน (สำรอง)
        },
        main: {
            primary: '#1E90FF', // น้ำเงินสด (เส้นหลัก)
            fallback: '#63B3ED' // น้ำเงินอ่อน (สำรอง)
        },
        fastest: {
            primary: '#6A5ACD', // ม่วงเข้ม (เส้นเร็วที่สุด)
            fallback: '#9370DB' // ม่วงอ่อน (สำรอง)
        }
    }
};

// ========== STATE (สถานะของระบบ) ==========
// เก็บค่าต่างๆ ที่เปลี่ยนแปลงตามการใช้งาน
const STATE = {
    currentLang: localStorage.getItem('language') || 'th', // ภาษาที่ใช้งานปัจจุบัน
    selectedOrigin: null, // ข้อมูลจุดเริ่มต้น
    selectedDestination: null, // ข้อมูลจุดหมายปลายทาง
    selectedRouteType: null, // ประเภทเส้นทางที่เลือก (main/fastest)
    routeData: {}, // ข้อมูลเส้นทางที่คำนวณแล้ว
    routeDataDebug: {}, // 🔥 ข้อมูล debug (เปรียบเทียบรถติด/ไม่มีรถติด)
    currentMapMode: 'origin', // โหมดการคลิกบนแผนที่ (origin/destination)
    map: null, // ออบเจ็กต์แผนที่ Longdo
    markers: {
        origin: null, // Marker จุดเริ่มต้น
        destination: null // Marker จุดหมายปลายทาง
    },
    searchTimeout: null, // Timeout สำหรับการค้นหา (เพื่อหน่วงเวลา)
    isAutoLocating: false // ป้องกันการเรียกหาตำแหน่ง GPS ซ้ำ
};

// ========== MARKER ICONS (ไอคอน Marker บนแผนที่) ==========
// สร้างไอคอน SVG สำหรับแสดงตำแหน่งบนแผนที่
const createMarkerIcon = (color, label) =>
    `data:image/svg+xml,${encodeURIComponent(`
    <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="50%" y="35%" text-anchor="middle" dominant-baseline="central"
            font-size="14" font-weight="bold" fill="${color}">${label}</text>
    </svg>
  `)}`;

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


// ========================================================================================================
// ========== GPS PERMISSION & AUTO-DETECT FUNCTIONS (ฟังก์ชันตรวจสอบสิทธิ์ GPS และค้นหาตำแหน่ง) ==========
// ========================================================================================================

/**
 * ตรวจสอบสิทธิ์การใช้ GPS และขอตำแหน่งปัจจุบันอัตโนมัติ
 * - ใช้ Permission API เพื่อตรวจสอบสถานะการอนุญาต
 * - แสดงข้อความแจ้งเตือนหากถูกปฏิเสธ
 * @returns {Promise<boolean>} true ถ้าสามารถใช้ GPS ได้
 */
async function checkAndRequestGPSPermission() {
    const t = TRANSLATIONS[STATE.currentLang];

    // ตรวจสอบว่า browser รองรับ Geolocation API หรือไม่
    if (!navigator.geolocation) {
        console.error('❌ Geolocation is not supported by this browser');
        return false;
    }

    // ตรวจสอบ permission status (ถ้า browser รองรับ)
    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);
            }

            // ดักฟังเมื่อ permission เปลี่ยนแปลง
            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 {
        // Browser ไม่รองรับ permission API → ขอตำแหน่งโดยตรง
        console.log('⚠️ Permissions API not supported, requesting location directly');
        showGPSAlert(t.gps_permission_message, true);
    }

    return true;
}

/**
 * แสดงกล่องแจ้งเตือน GPS แบบกำหนดสี/ไอคอนได้
 * - แสดงเป็นแถบลอยด้านบน
 * - หายเองอัตโนมัติใน 5 วินาที
 * @param {string} message - ข้อความที่จะแสดง
 * @param {boolean} isInfo - true = สีน้ำเงิน (ข้อมูล), false = สีแดง (ข้อผิดพลาด)
 */
function showGPSAlert(message, isInfo = false) {
    // สร้าง custom alert box
    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);

    // Auto remove after 5 seconds
    setTimeout(() => {
        alertDiv.style.animation = 'slideUp 0.3s ease-out';
        setTimeout(() => alertDiv.remove(), 300);
    }, 5000);

    // Add CSS animation (once)
    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);
    }
}

/**
 * ตรวจหาตำแหน่งปัจจุบันอัตโนมัติ และเติมลงช่องต้นทาง
 * - แสดงข้อความ "กำลังค้นหาตำแหน่ง" ในช่อง input
 * - เมื่อพบตำแหน่งแล้ว จะทำ reverse geocode เพื่อหาชื่อสถานที่
 * - ป้องกันการเรียกซ้ำด้วย isAutoLocating flag
 */
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);
            }

            // Reverse geocode เพื่อหาชื่อสถานที่
            reverseGeocode(
                position.coords.latitude,
                position.coords.longitude,
                'origin',
                true // isCurrentLocation = true
            );

            STATE.isAutoLocating = false;

            // แสดงข้อความสำเร็จ
            showSuccessMessage(t.location_found);
        },
        (error) => {
            console.error('❌ GPS Error:', error);
            STATE.isAutoLocating = false;

            // Reset input
            originInput.value = '';
            originInput.style.color = '';
            originInput.style.fontWeight = '';

            // แสดงข้อความ error ตามประเภท
            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, // ใช้ GPS ความแม่นยำสูง
        timeout: 10000, // Timeout 10 วินาที
        maximumAge: 0 // ไม่ใช้ cache
    }
    );
}

/**
 * แสดงข้อความแจ้งเตือนสำเร็จแบบลอย
 * - แสดงเป็นแถบสีเขียวด้านบน
 * - หายเองอัตโนมัติใน 3 วินาที
 * @param {string} message - ข้อความที่จะแสดง
 */
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);

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


// ========================================================================================================
// ========== LANGUAGE FUNCTIONS (ฟังก์ชันจัดการภาษา) ==========
// ========================================================================================================

/**
 * ตั้งค่าภาษาและรีเฟรช UI/แผนที่
 * @param {string} lang - รหัสภาษา ('th' หรือ 'en')
 */
function setLanguage(lang) {
    STATE.currentLang = lang;
    localStorage.setItem('language', lang);
    updateLanguage();
    updateLanguageSwitcher();
    reloadMap();
}

/**
 * อัปเดตตัวเลือกภาษาใน UI ให้แสดงว่าเลือกอันไหนอยู่
 */
function updateLanguageSwitcher() {
    document.querySelectorAll('.lang-option').forEach(el => el.classList.remove('active'));
    document.getElementById('lang' + STATE.currentLang.toUpperCase()).classList.add('active');
}

/**
 * อัปเดตข้อความทั้งหมดในหน้าให้เป็นภาษาที่เลือก
 * - อัปเดต title, placeholder
 * - อัปเดตข้อความในปุ่มและ label
 * - อัปเดตข้อมูลเส้นทาง (ถ้ามี)
 */
function updateLanguage() {
    const t = TRANSLATIONS[STATE.currentLang];

    // อัปเดต page title
    document.getElementById('pageTitle').textContent = t.page_title;
    document.documentElement.lang = STATE.currentLang;

    // อัปเดตข้อความทั้งหมดที่มี data-i18n
    document.querySelectorAll('[data-i18n]').forEach(el => {
        const key = el.getAttribute('data-i18n');
        if (t[key]) el.textContent = t[key];
    });

    // อัปเดต placeholder ทั้งหมด
    document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
        const key = el.getAttribute('data-i18n-placeholder');
        if (t[key]) el.placeholder = t[key];
    });

    // อัปเดตข้อความตำแหน่งปัจจุบันใน input
    updateLocationInputs();

    // อัปเดตข้อมูลเส้นทาง (ถ้ามี)
    if (STATE.routeData.main && STATE.routeData.fastest) {
        displayRoutes(STATE.routeData.main, STATE.routeData.fastest);
        displayDebugInfo(); // 🔥 อัปเดต debug info ด้วย
    }

    // อัปเดตภาษาของแผนที่
    if (STATE.map) STATE.map.language(STATE.currentLang);

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

/**
 * อัปเดตชื่อจุดเริ่มต้น/ปลายทางตามภาษาใหม่
 * - ถ้าเป็นตำแหน่งปัจจุบัน → แสดง "(ตำแหน่งปัจจุบัน)"
 * - ถ้าไม่ใช่ → ทำ reverse geocode ใหม่
 */
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);
        }
    }
}


// ========================================================================================================
// ========== MAP FUNCTIONS (ฟังก์ชันจัดการแผนที่) ==========
// ========================================================================================================

/**
 * สร้างแผนที่และตั้งค่าเริ่มต้น
 * - สร้าง Longdo Map instance
 * - ผูก event listener สำหรับการคลิกบนแผนที่
 * - ตั้งต้นแผนที่ที่กรุงเทพฯ
 */
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);
    });

    // ตั้งต้นแผนที่ที่กรุงเทพฯ (จะถูก override ด้วย GPS ถ้ามี)
    STATE.map.location({
        lon: 100.5,
        lat: 13.75
    }, true);


    // 🔥 ผูก Event Binding สำหรับคำนวณเส้นทาง (ใช้ pattern จาก test PHP)
    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.lat, oldOrigin.lon, oldOrigin.isCurrentLocation);
        }
        if (oldDestination) {
            updateLocation('destination', oldDestination.name, 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');
}

/**
 * สลับโหมดเลือกตำแหน่ง (origin/destination)
 * @param {string} mode - โหมด ('origin' หรือ 'destination')
 */
function setMapMode(mode) {
    STATE.currentMapMode = mode;
    console.log(`🎯 Map mode set to: ${mode}`);
}

/**
 * จัดการเมื่อคลิกบนแผนที่
 * - เรียก reverse geocode เพื่อหาชื่อสถานที่
 * @param {number} lat - Latitude
 * @param {number} lon - Longitude
 */
function handleMapClick(lat, lon) {
    console.log(`📍 Map clicked: ${lat}, ${lon}`);
    reverseGeocode(lat, lon, STATE.currentMapMode, false);
}


// ========================================================================================================
// ========== GEOCODING FUNCTIONS (ฟังก์ชัน Geocoding - แปลงพิกัดเป็นชื่อสถานที่) ==========
// ========================================================================================================

/**
 * Reverse Geocode - แปลงพิกัด (lat, lon) เป็นชื่อสถานที่
 * - เรียก API ของ Longdo Map
 * - จัดรูปแบบชื่อสถานที่ตามภาษา
 * - อัปเดต UI และ marker
 * @param {number} lat - Latitude
 * @param {number} lon - Longitude
 * @param {string} type - ประเภท ('origin' หรือ 'destination')
 * @param {boolean} isCurrentLocation - true ถ้าเป็นตำแหน่งปัจจุบัน
 */
async function reverseGeocode(lat, lon, type, isCurrentLocation = false) {
    const t = TRANSLATIONS[STATE.currentLang];

    try {
        const response = await fetch(
            `https://api.longdo.com/map/services/address?lon=${lon}&lat=${lat}&locale=${STATE.currentLang}&key=${CONFIG.API_KEY}`
        );
        const data = await response.json();

        // ชื่อสถานที่ที่ผ่านการจัดรูปแบบตามภาษา
        const name = formatLocationName(data) || `${lat.toFixed(6)}, ${lon.toFixed(6)}`;

        // อัปเดตตำแหน่ง โดยถ้าเป็นตำแหน่งปัจจุบันให้ใช้ t.current_location
        updateLocation(
            type,
            isCurrentLocation ? t.current_location : name,
            lat,
            lon,
            isCurrentLocation
        );

        console.log(`✓ Reverse geocode success: ${name}`);

    } catch (error) {
        console.error('❌ Reverse Geocode Error:', error);

        // ถ้าดึงชื่อไม่ได้ → ใช้ lat/lon แทน
        updateLocation(
            type,
            `${lat.toFixed(6)}, ${lon.toFixed(6)}`,
            lat,
            lon,
            isCurrentLocation
        );
    }
}

/**
 * จัดรูปแบบชื่อสถานที่จากข้อมูล API
 * - รองรับทั้งภาษาไทยและอังกฤษ
 * - เรียงข้อมูลจากละเอียด → กว้าง (เลขที่ → ถนน → ตำบล → อำเภอ → จังหวัด)
 * @param {object} data - ข้อมูลจาก API
 * @returns {string|null} ชื่อสถานที่ที่จัดรูปแบบแล้ว
 */
function formatLocationName(data) {
    const parts = [];
    const isTH = STATE.currentLang === "th";

    // เลขที่ - ต้องเปลี่ยนคำว่า "เลขที่" → "No." เมื่อเป็นภาษาอังกฤษ
    if (data.house_no) {
        parts.push(isTH ? `เลขที่ ${data.house_no}` : `No. ${data.house_no}`);
    }

    // ฟิลด์อื่นๆ - เอาค่าตาม API ได้เลย (API จะส่งมาตามภาษาที่ระบุแล้ว)
    [
        'moo', 'place', 'building', 'condominium', 'village', 'village_official',
        'sublane', 'alley', 'road', 'subdistrict', 'district', 'province'
    ].forEach(key => {
        if (data[key]) parts.push(data[key]);
    });

    return parts.length > 0 ? parts.join(' ') : null;
}


// ========================================================================================================
// ========== UPDATE LOCATION (อัปเดตตำแหน่งและ Marker) ==========
// ========================================================================================================

/**
 * อัปเดตตำแหน่ง (input + marker + state)
 * - บันทึกข้อมูลลง STATE
 * - อัปเดต input field
 * - วาด marker บนแผนที่
 * - แสดงปุ่มลบ (X)
 * @param {string} type - ประเภท ('origin' หรือ 'destination')
 * @param {string} name - ชื่อสถานที่
 * @param {number} lat - Latitude
 * @param {number} lon - Longitude
 * @param {boolean} isCurrentLocation - true ถ้าเป็นตำแหน่งปัจจุบัน
 */
function updateLocation(type, name, lat, lon, isCurrentLocation = false) {
    const locationData = {
        name,
        lat,
        lon,
        isCurrentLocation
    };
    const inputId = type;
    const markerColor = type === 'origin' ? MARKERS.green : MARKERS.red;

    // === เก็บข้อมูลลง STATE ===
    if (type === 'origin') {
        STATE.selectedOrigin = locationData;
    } else {
        STATE.selectedDestination = locationData;
    }

    // === อัปเดต Input UI ===
    const input = document.getElementById(inputId);
    input.value = name;

    // ถ้าเป็นตำแหน่งปัจจุบัน → ใช้สีเขียวและตัวหนา
    input.style.color = isCurrentLocation ? '#198754' : '';
    input.style.fontWeight = isCurrentLocation ? '600' : '';
    toggleClearButton(inputId, true);

    // === อัปเดต Marker บนแผนที่ ===
    // ลบ marker เก่า (ถ้ามี)
    if (STATE.markers[type]) {
        STATE.map.Overlays.remove(STATE.markers[type]);
    }

    // สร้าง marker ใหม่
    STATE.markers[type] = new longdo.Marker({
        lat,
        lon
    }, {
        icon: {
            url: markerColor,
            offset: {
                x: 20,
                y: 50
            }
        },
        title: name
    });

    STATE.map.Overlays.add(STATE.markers[type]);

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

    console.log(`📍 Location updated: ${type} = ${name}`);
}


// ========================================================================================================
// ========== CLEAR & TOGGLE FUNCTIONS (ฟังก์ชันลบและสลับการแสดงผล) ==========
// ========================================================================================================

/**
 * ลบข้อมูลตำแหน่ง (origin หรือ destination)
 * - ล้าง input field
 * - ลบ marker จากแผนที่
 * - ลบข้อมูลจาก STATE
 * - ซ่อนปุ่มลบ
 * - ล้างเส้นทาง (ถ้าไม่มีจุดเริ่มต้นหรือปลายทาง)
 * @param {string} type - ประเภท ('origin' หรือ 'destination')
 */
function clearInput(type) {
    const input = document.getElementById(type);

    // เคลียร์กล่องข้อความ
    input.value = '';
    input.style.color = '';
    input.style.fontWeight = '';

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

    // ซ่อนปุ่มลบ (X)
    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 sections
        const debug1 = document.getElementById('debug1');
        const debug2 = document.getElementById('debug2');
        if (debug1) debug1.classList.remove('show');
        if (debug2) debug2.classList.remove('show');

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

    console.log(`🗑️ Cleared: ${type}`);
}

/**
 * สลับการแสดงปุ่มลบ (X)
 * @param {string} inputId - ID ของ input field
 * @param {boolean} show - true = แสดง, false = ซ่อน
 */
function toggleClearButton(inputId, show) {
    const btnId = 'clear' + inputId.charAt(0).toUpperCase() + inputId.slice(1);
    const btn = document.getElementById(btnId);

    if (btn) {
        btn.classList.toggle('show', show);
    }
}


// ========================================================================================================
// ========== SEARCH FUNCTIONS (ฟังก์ชันค้นหาสถานที่) ==========
// ========================================================================================================

/**
 * ค้นหาสถานที่จาก keyword
 * - เรียก Longdo Search API
 * - แสดงผลลัพธ์ในรายการ suggestion
 * @param {string} keyword - คำค้นหา
 * @param {HTMLElement} element - element สำหรับแสดงผล
 * @param {boolean} isOrigin - true = origin, false = destination
 */
async function searchPlace(keyword, element, isOrigin) {
    if (!keyword || keyword.trim().length < 1) {
        element.style.display = 'none';
        return;
    }

    try {
        const url = `https://search.longdo.com/mapsearch/json/search?keyword=${encodeURIComponent(keyword)}&limit=5&locale=${STATE.currentLang}&key=${CONFIG.API_KEY}`;

        const response = await fetch(url);
        const data = await response.json();

        displaySuggestions(data?.data || [], element, isOrigin);

    } catch (error) {
        console.error('❌ Search Error:', error);
        displaySuggestions([], element, isOrigin);
    }
}

/**
 * แสดงรายการ suggestion จากผลการค้นหา
 * - แสดงตัวเลือก "ใช้ตำแหน่งปัจจุบัน" เสมอ
 * - แสดงผลการค้นหา (ถ้ามี)
 * @param {Array} places - รายการสถานที่
 * @param {HTMLElement} element - element สำหรับแสดงผล
 * @param {boolean} isOrigin - true = origin, false = destination
 */
function displaySuggestions(places, element, isOrigin) {
    const t = TRANSLATIONS[STATE.currentLang];
    element.innerHTML = '';

    // === ตัวเลือก "ใช้ตำแหน่งปัจจุบัน" ===
    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(isOrigin);
        element.style.display = 'none';
    };
    element.appendChild(currentItem);

    // === ผลการค้นหา ===
    if (places.length > 0) {
        // เส้นแบ่ง + label
        const separator = document.createElement('div');
        separator.className = 'suggestion-separator';
        separator.textContent = t.search_results;
        element.appendChild(separator);

        // เรียงตามชื่อ (A-Z หรือ ก-ฮ)
        places.sort((a, b) =>
            (a.name || "").localeCompare(b.name || "", "th")
        );

        places.forEach(place => {
            const item = document.createElement('div');
            item.className = 'suggestion-item';

            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
                );
                element.style.display = 'none';
            };

            element.appendChild(item);
        });
    }

    element.style.display = 'block';
}

/**
 * ใช้ตำแหน่งปัจจุบัน (GPS)
 * - ขอตำแหน่งจาก browser
 * - เลื่อนแผนที่ไปที่ตำแหน่งนั้น
 * - ทำ reverse geocode
 * @param {boolean} isOrigin - true = origin, false = destination
 */
function useCurrentLocation(isOrigin) {
    const t = TRANSLATIONS[STATE.currentLang];

    if (!navigator.geolocation) {
        alert(t.alert_gps_error);
        return;
    }

    const inputId = isOrigin ? 'origin' : 'destination';
    const inputEl = document.getElementById(inputId);

    inputEl.value = t.getting_location;

    navigator.geolocation.getCurrentPosition(
        pos => {
            const lat = pos.coords.latitude;
            const lon = pos.coords.longitude;

            // เลื่อนแผนที่
            STATE.map.location({
                lon,
                lat
            }, true);
            STATE.map.zoom(15);

            // Reverse geocode
            reverseGeocode(lat, lon, inputId, true);
        },
        error => {
            console.error('❌ GPS Error:', error);
            alert(t.alert_gps_error);
            inputEl.value = '';
        }, {
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 0
    }
    );
}


// ========================================================================================================
// ========== ROUTE FUNCTIONS (ฟังก์ชันค้นหาและจัดการเส้นทาง) ==========
// ========================================================================================================

// ========================================================================================================
// ========== ROUTE FUNCTIONS (ฟังก์ชันค้นหาและจัดการเส้นทาง) ==========
// ========================================================================================================

/**
 * 🔥 Route Calculation State Machine (ใช้ pattern จาก test PHP)
 * - คำนวณเส้นทางทีละโหมด โดยใช้ global event binding
 * - ใช้ state machine pattern เพื่อควบคุมลำดับการคำนวณ
 */
const ROUTE_CALC_STATE = {
    calculating: false,           // กำลังคำนวณอยู่หรือไม่
    currentStep: 0,               // ขั้นตอนปัจจุบัน
    results: {},                  // ผลลัพธ์ที่เก็บไว้

    // ลำดับการคำนวณ (4 ขั้นตอน)
    steps: [
        { name: 'AllDrive_Distance', routeType: 'AllDrive', mode: longdo.RouteMode.Cost, label: 'ทางด่วน (มีรถติด)' },
        { name: 'AllDrive_Traffic', routeType: 'AllDrive', mode: longdo.RouteMode.Traffic, label: 'ทางด่วน (ไม่มีรถติด)' },
        { name: 'Road_Distance', routeType: 'Road', mode: longdo.RouteMode.Cost, label: 'ทางถนน (มีรถติด)' },
        { name: 'Road_Traffic', routeType: 'Road', mode: longdo.RouteMode.Traffic, label: 'ทางถนน (ไม่มีรถติด)' }
    ]
};

/**
 * Initialize Route Event Binding (เรียกครั้งเดียวตอน initMap)
 * - ผูก event 'guideComplete' แบบ global
 * - จะทำงานทุกครั้งที่ค้นหาเส้นทางเสร็จ
 */
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 {
            // ดึงค่าจาก SDK (ตรงกับเส้นบนแผนที่ 100%)
            const distance = STATE.map.Route.distance();        // เมตร
            const distanceText = STATE.map.Route.distance(true); // "X.X km"
            const interval = STATE.map.Route.interval();         // วินาที
            const intervalText = STATE.map.Route.interval(true); // "X ชม. Y นาที"

            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');
}

/**
 * เริ่มต้นการค้นหาเส้นทาง
 * - ตรวจสอบข้อมูล
 * - เริ่ม state machine
 */
function searchRoute() {
    const t = TRANSLATIONS[STATE.currentLang];

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

    // Reset state
    ROUTE_CALC_STATE.calculating = true;
    ROUTE_CALC_STATE.currentStep = 0;
    ROUTE_CALC_STATE.results = {};

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

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

    // ตั้งค่า markers
    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();
}

/**
 * คำนวณขั้นตอนถัดไป
 * - ตั้งค่า RouteType และ Mode
 * - เรียก map.Route.search()
 */
function calculateNextStep() {
    const step = ROUTE_CALC_STATE.steps[ROUTE_CALC_STATE.currentStep];

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

    // ตั้งค่า RouteType
    if (step.routeType === 'AllDrive') {
        STATE.map.Route.enableRoute(longdo.RouteType.Tollway, true);
        //STATE.map.Route.enableRoute(longdo.RouteType.Road, false);
    } else {
        STATE.map.Route.enableRoute(longdo.RouteType.AllDrive, false);
        STATE.map.Route.enableRoute(longdo.RouteType.Road, true);
    }

    // ตั้งค่า Mode และค้นหา
    STATE.map.Route.mode(step.mode);
    STATE.map.Route.search();
}

/**
 * เมื่อคำนวณเสร็จทุกขั้นตอนแล้ว
 * - จัดเตรียมข้อมูลให้ displayRoutes() และ displayDebugInfo()
 * - แสดงผล UI
 */
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();

    // UI
    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');
}

/**
 * ตั้งค่าสีเส้นทางบนแผนที่
 * @param {string} routeType - ประเภทเส้นทาง ('initial', 'main', 'fastest')
 */

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

    try {
        // พยายามใช้ API ใหม่
        STATE.map.call('Route.line', 'road', {
            lineColor: colors.primary,
            lineWidth: 3,
            borderColor: '#000000',
            borderWidth: 1
        });
    } catch (e) {
        try {
            // Fallback API รุ่นกลาง
            STATE.map.Route.line('road', {
                lineColor: colors.fallback,
                lineWidth: 3
            });
        } catch (err2) {
            // Fallback API รุ่นเก่า
            STATE.map.Route.option({
                lineColor: colors.fallback,
                lineWidth: 3
            });
        }
    }
}

/**
 * แสดงเส้นทางบนแผนที่ (เส้นแรก - สีเทา)
 * - ใช้เป็นเส้นตัวอย่างก่อนเลือก
 */
function displayRouteOnMap() {
    STATE.map.Route.clear();

    // เพิ่ม marker ต้นทาง
    STATE.map.Route.add(new longdo.Marker({
        lon: STATE.selectedOrigin.lon,
        lat: STATE.selectedOrigin.lat
    }, {
        icon: {
            url: MARKERS.green,
            offset: {
                x: 20,
                y: 50
            }
        }
    }));

    // เพิ่ม marker ปลายทาง
    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.search();

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

// ========================================================================================================
// ========== SELECT ROUTE (กดเลือก route-card) ==========
// ========================================================================================================
/**
 * เลือกเส้นทาง (main หรือ fastest)
 * - อัปเดต UI
 * - วาดเส้นทางที่เลือกบนแผนที่
 */
function selectRoute(type) {
    STATE.selectedRouteType = type;

    // UI: ไฮไลต์การ์ดที่เลือก
    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') {
        // ทางด่วน (AllDrive)
        STATE.map.Route.enableRoute(longdo.RouteType.Tollway, true);
        // STATE.map.Route.enableRoute(longdo.RouteType.Road, false);
    } else {
        // ทางถนน (Road)
        STATE.map.Route.enableRoute(longdo.RouteType.AllDrive, false);
        STATE.map.Route.enableRoute(longdo.RouteType.Road, true);
    }

    STATE.map.Route.mode(longdo.RouteMode.Cost);

    // เพิ่ม markers
    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);

    // ไม่แสดงเส้นทาง KM
    STATE.map.Route.label(false);

    // ค้นหาเส้นทางใหม่
    STATE.map.Route.search();

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

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


/**
 * ปรับมุมมองแผนที่ให้พอดีกับเส้นทาง
 * - คำนวณ bounding box จากจุดเริ่มต้นและปลายทาง
 * - เพิ่ม padding เพื่อให้ดูสบายตา
 */
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)
        };

        // เพิ่ม padding 15%
        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);

        // Fallback: ใช้จุดกึ่งกลาง
        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);
    }
}


// ========================================================================================================
// ========== FARE CALCULATION (ฟังก์ชันคำนวณค่าโดยสาร) ==========
// ========================================================================================================
/**
 * คำนวณค่าโดยสารแท็กซี่กรุงเทพฯ
 * ตามกฎหมายปัจจุบัน:
 * - ค่าเริ่มต้น: 35 บาท (1 กม. แรก)
 * - 1-2 กม.: +6.5 บาท
 * - 2-10 กม.: 6.5 บาท/กม.
 * - 10-20 กม.: 7 บาท/กม.
 * - 20-40 กม.: 8 บาท/กม.
 * - 40-60 กม.: 8.5 บาท/กม.
 * - 60-80 กม.: 9 บาท/กม.
 * - 80+ กม.: 10.5 บาท/กม.
 * - ค่ารถติด: 3 บาท/นาที
 * @param {number} distanceKm - ระยะทาง (กิโลเมตร)
 * @param {number} timeSeconds - เวลา (วินาที)
 * @returns {number} ค่าโดยสาร (บาท)
 */
function calculateTaxiFare(distanceKm, timeSeconds) {
    // ค่าเริ่มต้น (ขึ้นรถ) 35 บาท
    let fare = 35;

    // ---------------------------------------------------------
    // 1) คิดค่าเดินทางตามระยะทาง
    // ---------------------------------------------------------
    if (distanceKm > 1) {
        let remaining = distanceKm - 1;

        // ตารางช่วงระยะทางและราคาต่อกิโลเมตร
        const rateSteps = [{
            limit: 1,
            rate: 6.5
        }, // 1-2 กม.
        {
            limit: 8,
            rate: 6.5
        }, // 2-10 กม.
        {
            limit: 10,
            rate: 7
        }, // 10-20 กม.
        {
            limit: 20,
            rate: 8
        }, // 20-40 กม.
        {
            limit: 20,
            rate: 8.5
        }, // 40-60 กม.
        {
            limit: 20,
            rate: 9
        }, // 60-80 กม.
        {
            limit: Infinity,
            rate: 10.5
        } // 80 กม. ขึ้นไป
        ];

        // คำนวณทีละช่วง
        rateSteps.forEach(({
            limit,
            rate
        }) => {
            if (remaining > 0) {
                const dist = Math.min(remaining, limit);
                fare += dist * rate;
                remaining -= dist;
            }
        });
    }

    // ---------------------------------------------------------
    // 2) ค่ารถติด (คิดเป็นนาที) = 3 บาท/นาที
    // ---------------------------------------------------------
    fare += (timeSeconds / 60) * 0;

    // ปัดค่าขึ้นให้เป็นจำนวนเต็ม
    return Math.round(fare);
}


// ========================================================================================================
// ========== DISPLAY ROUTES (แสดงข้อมูลเส้นทาง) ==========
// ========================================================================================================
/**
 * แสดงข้อมูลเส้นทางทั้ง 2 แบบบนการ์ด
 * - เส้นทางหลัก (main) - ทางด่วน
 * - เส้นทางเร็วที่สุด (fastest) - ทางถนน
 */
function displayRoutes(routeMain, routeFastest) {
    const t = TRANSLATIONS[STATE.currentLang];

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

    // --- แปลงค่าระยะทางให้เป็น Number ป้องกันค่าที่ไม่ใช่ตัวเลข ---
    const mainKM = Number(main.distance) / 1000 || 0;
    const fastestKM = Number(fastest.distance) / 1000 || 0;

    // --- คำนวณ extra_time จากข้อมูล debug ---
    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); // วินาที

    // --- คำนวณค่าโดยสารเพิ่มเติมจากรถติด (3 บาท/นาที) ---
    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;

    // --- คำนวณเวลารวม (เวลาเดิม + extra_time) ---
    const mainTotalTime = main.interval + mainExtraTime;
    const fastestTotalTime = fastest.interval + fastestExtraTime;

    // ------------------------------
    // การ์ดที่ 1 = Main (ทางด่วน)
    // ------------------------------
    document.getElementById('dist1').textContent = `${mainKM.toFixed(1)} ${t.km}`;
    document.getElementById('time1').textContent = formatTime(mainTotalTime);
    document.getElementById('cost1').textContent = `${mainFare} ${t.baht}`;

    // ------------------------------
    // การ์ดที่ 2 = Fastest (ทางถนน)
    // ------------------------------
    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}฿)`);
}


/**
 * 🔥 แสดงข้อมูล Debug สำหรับเปรียบเทียบ "มีรถติด" vs "ไม่มีรถติด"
 * ทำสำหรับทั้ง Route หลัก (main) และ Route ที่เร็วที่สุด (fastest)
 */
function displayDebugInfo() {
    const t = TRANSLATIONS[STATE.currentLang]; // ดึงข้อความตามภาษาปัจจุบัน

    // ---------------------------------------------------------
    // 🟧 1) ดึงข้อมูลของเส้นทาง Main
    // ---------------------------------------------------------
    const mainTraffic = STATE.routeDataDebug.main.Distance.data[0];     // เส้นทาง main แบบมีรถติด
    const mainNoTraffic = STATE.routeDataDebug.main.Traffic.data[0];   // เส้นทาง main แบบไม่มีรถติด

    // คำนวณค่าโดยสาร (ใช้ระยะทางเป็นกม. + เวลา interval)
    const mainFareTraffic = calculateTaxiFare(mainTraffic.distance / 1000, mainTraffic.interval);
    //const mainFareNoTraffic = calculateTaxiFare(mainNoTraffic.distance / 1000, mainNoTraffic.interval);

    // ผลกระทบจากรถติด = (ค่าที่มีรถติด) − (ค่าที่ไม่มีรถติด)
    const mainExtraTime = Math.max(mainNoTraffic.interval - mainTraffic.interval, 0);
    // const mainExtraFare = Math.max(mainFareNoTraffic - mainFareTraffic, 0);
    // const mainExtraDist = Math.max((mainNoTraffic.distance - mainTraffic.distance) / 1000, 0);

    // ---------------------------------------------------------
    // 🟩 2) แสดงผล Debug สำหรับ Route Main
    // ---------------------------------------------------------

    // ไม่มีรถติด (Base Line)
    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_dist_notraffic').textContent = `${(mainNoTraffic.distance / 1000).toFixed(1)} ${t.km}`;
    document.getElementById('debug1_time_notraffic').textContent = formatTime(mainNoTraffic.interval);
    //document.getElementById('debug1_fare_notraffic').textContent = `${mainFareNoTraffic} ${t.baht}`;

    // ผลกระทบ
    //document.getElementById('debug1_extra_distance').textContent = `${mainExtraDist.toFixed(1)} ${t.km}`;
    document.getElementById('debug1_extra_time').textContent = formatTime(mainExtraTime);
    //document.getElementById('debug1_extra_fare').textContent = `${mainExtraFare} ${t.baht}`;

    // ---------------------------------------------------------
    // 🟦 3) ดึงข้อมูลของเส้นทาง Fastest
    // ---------------------------------------------------------
    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 fastestFareNoTraffic = calculateTaxiFare(fastestNoTraffic.distance / 1000, fastestNoTraffic.interval);

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

    // ---------------------------------------------------------
    // 🟦 4) แสดงผล Debug สำหรับ Route Fastest
    // ---------------------------------------------------------

    // ไม่มีรถติด
    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_dist_notraffic').textContent = `${(fastestNoTraffic.distance / 1000).toFixed(1)} ${t.km}`;
    document.getElementById('debug2_time_notraffic').textContent = formatTime(fastestNoTraffic.interval);
    //document.getElementById('debug2_fare_notraffic').textContent = `${fastestFareNoTraffic} ${t.baht}`;

    // ผลกระทบ
    //document.getElementById('debug2_extra_distance').textContent = `${fastestExtraDist.toFixed(1)} ${t.km}`;
    document.getElementById('debug2_extra_time').textContent = formatTime(fastestExtraTime);
    // document.getElementById('debug2_extra_fare').textContent = `${fastestExtraFare} ${t.baht}`;


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


/**
 * แปลงวินาที → ชั่วโมง/นาที
 * @param {number} sec - จำนวนวินาที
 * @returns {string} เวลาในรูปแบบ "X ชม. Y นาที" หรือ "Y นาที"
 */
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}`;
}


// ========================================================================================================
// ========== CONFIRM ROUTE (บันทึกเส้นทางที่เลือก) ==========
// ========================================================================================================

/**
 * บันทึกข้อมูลเส้นทางเมื่อกดปุ่มยืนยัน
 * - บันทึกลง LocalStorage
 * - แสดงข้อความสำเร็จ
 */
async function confirmRoute() {
    const t = TRANSLATIONS[STATE.currentLang];

    if (!STATE.selectedRouteType) {
        alert(t.alert_select_route);
        return;
    }

    // เลือกเส้นทางที่ถูกคลิก
    const routeInfo = STATE.routeData[
        STATE.selectedRouteType === 'main' ? 'main' : 'fastest'
    ].data[0];

    // คำนวณราคา
    const fare = calculateTaxiFare(routeInfo.distance / 1000, routeInfo.interval);

    // จัดเตรียมข้อมูลสำหรับบันทึก
    const dataToSave = {
        sessionId: CONFIG.SESSION_ID,
        origin: {
            name: STATE.selectedOrigin.name,
            lat: STATE.selectedOrigin.lat,
            lon: STATE.selectedOrigin.lon
        },
        destination: {
            name: STATE.selectedDestination.name,
            lat: STATE.selectedDestination.lat,
            lon: STATE.selectedDestination.lon
        },
        routeType: STATE.selectedRouteType,
        distance: (routeInfo.distance / 1000).toFixed(1),
        time: formatTime(routeInfo.interval),
        fare: fare,
        timestamp: new Date().toISOString()
    };

    // บันทึกลง LocalStorage
    localStorage.setItem('routeData_' + CONFIG.SESSION_ID, JSON.stringify(dataToSave));
    console.log('💾 Data saved:', dataToSave);

    // แสดงข้อความสำเร็จ
    document.getElementById('confirmBtn').style.display = 'none';
    document.getElementById('successMessage').classList.add('active');
    document.getElementById('successMessage').scrollIntoView({
        behavior: 'smooth',
        block: 'center'
    });
}


// ========================================================================================================
// ========== QR CODE FUNCTIONS (ฟังก์ชัน QR Code) ==========
// ========================================================================================================

/**
 * สร้าง QR Code สำหรับผู้โดยสาร
 * - ใช้ QRCode.js library
 * - ลิงก์ไปหน้า passenger พร้อม session ID
 */
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
    });

    console.log('📱 QR Code generated');
}

/**
 * เปิด/ปิด QR Code Box
 * - สลับการแสดงผล
 * - เลื่อนหน้าจอมาที่ QR เมื่อเปิด
 */
function toggleQR() {
    const box = document.getElementById('qrcode-box');
    const isHidden = box.style.display === 'none' || box.style.display === '';

    box.style.display = isHidden ? 'flex' : 'none';

    // ถ้าเปิดขึ้นมา ให้เลื่อนหน้าจอมาที่ QR อัตโนมัติ
    if (isHidden) {
        scrollToQR();
    }

    console.log(`📱 QR Box ${isHidden ? 'shown' : 'hidden'}`);
}

/**
 * เลื่อนหน้าจอลงมาหา QR Code อัตโนมัติ
 */
function scrollToQR() {
    const box = document.getElementById('qrcode-box');
    box.scrollIntoView({
        behavior: 'smooth',
        block: 'center'
    });
}


// ========================================================================================================
// ========== TEST PAGE DATA SENDER (ส่งข้อมูลไปยัง test.html) ==========
// ========================================================================================================

/**
 * 🔥 ส่งข้อมูล lat/long และเส้นทางไปยัง test.html
 * - ส่งข้อมูลจุดเริ่มต้นและปลายทาง
 * - ส่งข้อมูลเส้นทางทั้งสองแบบ (มีทางด่วน/ไม่มีทางด่วน)
 * - ใช้ localStorage เพื่อถ่ายโอนข้อมูล
 */
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 fastestRoute = STATE.routeData.fastest.data[0];

        // คำนวณค่าโดยสาร
        const mainFare = calculateTaxiFare(mainRoute.distance / 1000, mainRoute.interval);
        const fastestFare = calculateTaxiFare(fastestRoute.distance / 1000, fastestRoute.interval);

        // จัดเตรียมข้อมูลส่ง
        const testData = {
            timestamp: new Date().toISOString(),
            origin: {
                name: STATE.selectedOrigin.name,
                lat: STATE.selectedOrigin.lat.toFixed(6),
                lon: STATE.selectedOrigin.lon.toFixed(6)
            },
            destination: {
                name: 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
            },
            fastestRoute: {
                type: 'ไม่มีทางด่วน (No Tollway)',
                distance: (fastestRoute.distance / 1000).toFixed(1),
                time: formatTime(fastestRoute.interval),
                fare: fastestFare
            }
        };

        // บันทึกลง localStorage พร้อม timestamp
        const storageKey = 'testRouteData_' + Date.now();
        localStorage.setItem(storageKey, JSON.stringify(testData));

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

        // ลบข้อมูลเก่าที่เกิน 10 รายการ (เพื่อไม่ให้ localStorage เต็ม)
        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);
    }
}


// ========================================================================================================
// ========== EVENT LISTENERS (ฟังก์ชันดักจับเหตุการณ์) ==========
// ========================================================================================================

/**
 * ดักจับการพิมพ์ในช่องต้นทาง
 * - แสดง/ซ่อนปุ่มลบ
 * - ค้นหาสถานที่หลังจากหยุดพิมพ์ 300ms
 */
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);
});

/**
 * ดักจับการพิมพ์ในช่องปลายทาง
 * - แสดง/ซ่อนปุ่มลบ
 * - ค้นหาสถานที่หลังจากหยุดพิมพ์ 300ms
 */
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);
});

/**
 * คลิกข้างนอก suggestion list → ปิด list
 */
document.addEventListener('click', e => {
    if (!e.target.closest('.position-relative')) {
        document.getElementById('originSuggestions').style.display = 'none';
        document.getElementById('destinationSuggestions').style.display = 'none';
    }
});

/**
 * เมื่อ focus ช่องต้นทาง → แสดง suggestion list
 */
document.getElementById('origin').addEventListener('focus', () => {
    const box = document.getElementById('originSuggestions');
    if (!box.innerHTML) displaySuggestions([], box, true);
    box.style.display = 'block';
});

/**
 * เมื่อ focus ช่องปลายทาง → แสดง suggestion list
 */
document.getElementById('destination').addEventListener('focus', () => {
    const box = document.getElementById('destinationSuggestions');
    if (!box.innerHTML) displaySuggestions([], box, false);
    box.style.display = 'block';
});


// ========================================================================================================
// ========== INITIALIZE (เริ่มต้นระบบเมื่อโหลดหน้า) ==========
// ========================================================================================================

/**
 * เริ่มต้นเมื่อ DOM พร้อม
 * - อัปเดตภาษา
 * - อัปเดตตัวเลือกภาษา
 */
document.addEventListener('DOMContentLoaded', () => {
    updateLanguage();
    updateLanguageSwitcher();
    console.log('✓ DOM ready, language initialized');
});

/**
 * เริ่มต้นเมื่อหน้าโหลดเสร็จสมบูรณ์
 * - สร้างแผนที่
 * - สร้าง QR Code
 * - ตรวจสอบและขอสิทธิ์ GPS
 * - ค้นหาตำแหน่งปัจจุบันอัตโนมัติ
 */
window.addEventListener('load', async () => {
    console.log('🚀 System initializing...');

    // 1. สร้างแผนที่
    initMap();

    // 2. สร้าง QR Code
    generateQRCode();

    // 3. รอให้แผนที่พร้อม
    await new Promise(resolve => setTimeout(resolve, 500));

    // 4. ขอสิทธิ์ GPS และค้นหาตำแหน่งอัตโนมัติ
    const hasPermission = await checkAndRequestGPSPermission();
    if (hasPermission) {
        setTimeout(() => {
            autoDetectCurrentLocation();
        }, 300);
    }

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

Youez - 2016 - github.com/yon3zu
LinuXploit