@extends('app.app')
@section('title')
    Dashboard
@endsection
@section('customcss')
    {{-- <link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.css" /> --}}
    {{-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" integrity="sha512-gc3xjCmIy673V6MyOAZhIW93xhM9ei1I+gLbmFjUHIjocENRsLX/QUE1htk5q1XV2D/iie/VQ8DXI6Vu8bexvQ==" crossorigin="anonymous" referrerpolicy="no-referrer" /> --}}
    <link rel="stylesheet" href="{{ asset('assets/css/r.css') }}" />
    <style>
        .infoMove-plots li:hover {
            /* background: #ffd25c; */
            background: rgba(229, 41, 32, .25);
        }

        .infoMove-plots li.hover {
            /* background: #ffd25c; */
            background: rgba(229, 41, 32, .25);
        }

        .leaflet-control-container .leaflet-left {
            display: none;
        }

		.leaflet-routing-container {
			display: none !important;
		}

        #openLeftSideBar1Mobile {
            display: none;
        }

        .ptName {
            display: none;
        }

        @media (max-width: 425px) {
            #openLeftSideBar1 {
                display: none !important;
            }

            #openLeftSideBar1Mobile {
                display: block !important;
            }

            .ptName {
                display: block;
            }
        }
    </style>
@endsection
@section('content')
    <div class="container-fluid bg-white">
        <div class="row">
            {{-- list zones --}}
            <div class="col-sm-2 bg-white overflow-auto panel-right border-end d-none" id="leftSideBar1">
                <div class="row d-flex align-items-center mb-3">
                    <div class="col text-start">
                        <a href="javascript:void(0);" class="text-decoration-none text-dark" id="closeLeftSideBar1">
                            <span class="icon ion-ios-arrow-left fz-18"></span>
                        </a>
                    </div>
                    <div class="col text-end">
                        <p class="mb-0 text-bold">Zone List (<span id="c_list_zone">2</span>)</p>
                    </div>
                </div>
                <div class="row d-flex align-items-center mb-3 ptName">
                    <div class="col text-dark text-bold"><span id="ptName">{{ $client_group->c_name }}</span></div>
                </div>
                <div class="row d-flex align-items-center mb-3">
                    <div class="col text-danger"><a id="clearZone" href="javascript:void(0);"><small>hide zone</small></a></div>
                </div>
                <div class="form-group mb-3">
                    <input id="filterZoneSearch" type="text" class="form-control form-control-sm" placeholder="Search Zone">
                </div>
                <ul id="listZone" class="list-group">
                    <li class="list-group-item vehicles-list-wrapper zone-item p-1 px-2">
                        <a href="#" class="text-dark">
                            <div class="row d-flex align-items-center">
                                <div class="col-3 d-flex justify-content-center">
                                    <div class="align-items-center d-flex justify-content-center zone-icon" style="background: #B600FF">
                                        <span class="ion-android-pin text-white"></span>
                                    </div>
                                </div>
                                <div class="col ps-0">
                                    <p class="text-bold mb-0">BRK001</p>
                                    <p class="text-muted mb-0">Warehouse</p>
                                </div>
                            </div>
                        </a>
                    </li>
                    <li class="list-group-item vehicles-list-wrapper p-1 px-2">
                        <a href="#" class="text-dark">
                            <div class="row d-flex align-items-center">
                                <div class="col-3 d-flex justify-content-center">
                                    <div class="align-items-center d-flex justify-content-center zone-icon" style="background: #B600FF">
                                        <span class="ion-android-pin text-white"></span>
                                    </div>
                                </div>
                                <div class="col ps-0">
                                    <p class="text-bold mb-0">BRK002</p>
                                    <p class="text-muted mb-0">Warehouse</p>
                                </div>
                            </div>
                        </a>
                    </li>
                </ul>
            </div>
            {{-- zone detail --}}
            <div class="col-sm-2 bg-white overflow-auto panel-right border-end d-none" id="leftSideBar2">
                <div class="text-end">
                    <a href="javascript:void(0);" class="text-decoration-none text-danger" id="closeLeftSideBar2">
                        <span class="icon ion-android-close fz-18"></span>
                    </a>
                </div>
                <div class="card shadow-none border mb-3">
                    <div class="card-body p-2">
                        <div class="row d-flex align-items-center">
                            <div class="col-3 d-flex justify-content-center">
                                <div id="zd-boundary_hex_color" class="align-items-center d-flex justify-content-center zone-icon" style="background: #B600FF">
                                    <span class="ion-android-pin text-white"></span>
                                </div>
                            </div>
                            <div class="col ps-0">
                                <p id="zd-name" class="text-bold mb-0">BRK001</p>
                                <p id="zd-type_name" class="text-muted mb-0">Warehouse</p>
                            </div>
                        </div>
                    </div>
                </div>
                <ul class="list-group">
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Client</p>
                        <p id="zd-client" class="text-muted mb-0">JNE</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Tipe</p>
                        <p id="zd-type_name1" class="text-muted mb-0">Warehouse</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Jenis Zona</p>
                        <p id="zd-workflow_type_name" class="text-muted mb-0">Pickup</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Alamat</p>
                        <p id="zd-fulladdress" class="text-muted mb-0">Jl. Letjen Mt. Haryono No.Kav. 20, RW.1, Cawang, Kec.
                            Kramat jati, Kota Jakarta Timur, Daerah Khusus Ibukota Jakarta</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Kode Pos</p>
                        <p id="zd-shiptocode" class="text-muted mb-0">13630</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Pembaharuan Terakhir</p>
                        <p class="text-muted mb-0">
                            <span id="zd-updt_at">22-Sep-2020 04:43:43</span>
                            <span id="zd-updt_by">RTadmin</span>
                        </p>
                    </li>
                </ul>
            </div>
            <div class="col px-0">
                <div id="map" style="{{ Auth::user()->role != 2 ? 'height: calc(100vh - 90.52px) !important' : '' }}">
                    {{-- client logo --}}
                    {{-- <div class="card floating-menu-left mb-0" id="openLeftSideBar1">
                        <div class="card-body">
                            <div class="cNameGroup row d-flex align-items-center justify-content-between mb-1">
                                <div class="col-auto">
                                    <p id="c_name" class="mb-0 fz-14">{{ $client_group->c_name }}</p>
                                </div>
                                <div class="col-1 me-1">
                                    <a href="javascript:void(0);" class="text-decoration-none text-dark fz-18">
                                        <span class="icon ion-ios-arrow-right"></span>
                                    </a>
                                </div>
                            </div>
                            <div class="cLogoGroup row">
                                <div class="col-11 text-center ms-2">
                                    @if ($client_group)
                                        <img id="c_logo" src="{{ asset('storage/' . $client_group->c_logo) ?? asset('images/swa-nusa-logo.png') }}" alt="Client logo" class="img-fluid thumb-img-landscape-med">
                                    @else
                                        <img id="c_logo" src="{{ asset('images/swa-nusa-logo.png') }}" alt="Client logo" class="img-fluid" style="height: 40px">
                                    @endif
                                </div>
                            </div>
                        </div>
                    </div> --}}
                    <a href="javascript:void(0);" class="btn btn-sm bg-white text-decoration-none text-dark fz-18 floating-menu-left" id="openLeftSideBar1" style="width:38px;">
                        <span class="icon ion-ios-arrow-right"></span>
                    </a>
                    <a href="javascript:void(0);" class="btn btn-sm bg-white text-decoration-none text-dark fz-18 floating-menu-left" id="openLeftSideBar1Mobile" style="width:38px;">
                        <span class="icon ion-ios-arrow-right"></span>
                    </a>
                    <a href="javascript:void(0);" class="btn btn-sm bg-white text-decoration-none text-dark fz-18 floating-menu-right d-none" id="openRightSideBar1">
                        <span class="icon ion-ios-arrow-left"></span>
                    </a>
                    <div id="menuPlayback" class="floating-menu-bottom bg-light mb-0 disablePanning d-none">
                        <div class="row">
                            <div id="pgplay" class="col-auto ps-4 pe-0" style="margin-top: 0.15rem;">
                                <i id="icon-pg" class="ion ion-play icon-pg"></i>
                            </div>
                            <div class="col">
                                <div id="pgcontainer" class="slidecontainer">
                                    <input type="range" min="0" max="1000" value="0" class="slider" id="pgbar">
                                </div>
                                {{-- <div id="pgcontainer" class="pgcontainer">
                                    <div id="pgbar" class="pgbar"></div>
                                </div> --}}
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            {{-- vehicle detail --}}
            <div class="col-sm-2 bg-white overflow-auto panel-right border-end d-none" style="{{ Auth::user()->role != 2 ? 'height: calc(100vh - 90.52px) !important' : '' }}" id="rightSideBar2">
                <div class="text-end">
                    <a href="javascript:void(0);" class="text-decoration-none text-danger" id="closeRightSideBar2"><span class="icon ion-android-close fz-18"></span></a>
                </div>
                <div class="card shadow-none border">
                    <div class="card-body p-2">
                        <div class="align-items-center d-flex row">
                            <div class="col-4">
                                <img id="infoVehicles-thumb-sm" src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png" class="img-fluid thumb-img-small" alt="">
                            </div>
                            <div class="col ps-0">
                                <p id="infoVehicles-platno" class="text-bold mb-0">B 1201 SYX</p>
                                <p id="infoVehicles-addr-title" class="text-muted mb-0">Kebon Baru - Tebet</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="form-group mb-3 w-100">
                    <select name="" class="form-control select2" style="width: 100%;" id="selectFiter">
                        <option value="1">Vehicle</option>
                        <option value="2">Driver</option>
                        <option value="3">Job</option>
                        <option value="4">Travel History</option>
                    </select>
                </div>
                <ul class="list-group" id="infoVehicles">
                    <li class="list-group-item p-1">
                        <img id="infoVehicles-thumb-md" src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png" class="img-fluid thumb-img-landscape" alt="">
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Timestamp</p>
                        <p id="infoVehicles-crt" class="text-muted mb-0">20-Jan-2022 23:16:18</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Current Location</p>
                        <p id="infoVehicles-addr" class="text-muted mb-0">Kebon Baru - Tebet</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Latitude, Longitude</p>
                        <p id="infoVehicles-lat_lng" class="text-muted mb-0">-6.27013, 106.731371</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Vehicle Mileage (km)</p>
                        <p id="infoVehicles-mileage" class="text-muted mb-0">45080.83</p>
                    </li>
                    {{-- <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Batas kecepatan (kph)</p>
                        <p id="infoVehicles-speedLimit" class="text-muted mb-0">100</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Keccepatan Saat Ini (kph)</p>
                        <p id="infoVehicles-currentSpeed" class="text-muted mb-0">60</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Pengapian</p>
                        <p id="infoVehicles-ignition" class="text-muted mb-0">ON</p>
                    </li> --}}
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Engine Status</p>
                        <p id="infoVehicles-engineStatus" class="text-muted mb-0">Idling</p>
                    </li>
					
                    {{-- <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Durasi Berhenti (<span id="infoVehicles-idlingUnit">min</span>)</p>
                        <p id="infoVehicles-idlingDuration" class="text-muted mb-0">2946</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Zona Peringatan</p>
                        <p id="infoVehicles-alertZones" class="text-muted mb-0 d-block">Pasar Induk Cibitung, RAPID Office,
                            Rumah Ranko KBB, toll
                            Jorr</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Lacak di Hari Libur</p>
                        <p id="infoVehicles-isTrackHoliday" class="text-muted mb-0">Enabled</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Jadwal Pelacakan</p>
                        <p id="infoVehicles-trackSch" class="text-muted mb-0">24/7</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Perusahaan</p>
                        <p id="infoVehicles-company" class="text-muted mb-0">Swa Nusa Multimedia</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Tanggal Bergabung</p>
                        <p id="infoVehicles-serviceStart" class="text-muted mb-0">23-Aug-2018</p>
                    </li> --}}
                </ul>
                <ul class="list-group" id="infoDriver">
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Driver Information</p>
                        <p id="infoDrv-updt" class="text-muted mb-0">20-Jan-2022 23:16:18</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Driver Name</p>
                        <p id="infoDrv-name" class="text-muted mb-0">Emrsyf</p>
                    </li>
                    <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Phone</p>
                        <p class="mb-0">
                            <a href="tel:0" id="infoDrv-phone1-tel">
                                <i class="text-dark ion-ios-telephone"></i>&nbsp;
                                <span class="infoDrv-phone1-text"></span>
                            </a>
                        </p>
                        <p class="mb-0">
                            <a href="https://api.whatsapp.com/send/?phone=62&text=Halo&app_absent=0" id="infoDrv-phone1-wa" target="_blank"><i class="text-success ion-social-whatsapp"></i>
                                <span class="infoDrv-phone1-text"></span>
                            </a>
                        </p>
                    </li>
                    {{-- <li class="list-group-item p-1 px-2">
                        <p class="text-bold mb-0">Phone 2</p>
                        <p class="mb-0">
                            <a href="tel:0" id="infoDrv-phone2-tel">
                                <i class="text-dark ion-ios-telephone"></i>&nbsp;
                                <span class="infoDrv-phone2-text"></span>
                            </a>
                        </p>
                        <p class="mb-0">
                            <a href="https://api.whatsapp.com/send/?phone=62&text=Halo&app_absent=0" id="infoDrv-phone2-wa" target="_blank"><i class="text-success ion-social-whatsapp"></i>
                                <span class="infoDrv-phone2-text"></span>
                            </a>
                        </p>
                    </li> --}}
                </ul>
                <div id="infoJob">
                    {{-- @for ($i = 0; $i < 20; $i++)
                        <li class="list-group-item p-1 px-2">
                            <p class="text-bold mb-0">#902192102910</p>
                            <div class="row d-flex align-items-center justify-content-between">
                                <div class="col-auto">
                                    <small class="text-muted">Client name</small>
                                    <p id="" class="mb-0">JNE</p>
                                </div>
                                <div class="col-auto">
                                    <small class="text-muted">Destination</small>
                                    <p id="" class="mb-0">JKT-01</p></div>
                            </div>
                        </li>
                    @endfor --}}
                    {{-- <ul class="list-group mb-3">
                        <li class="list-group-item p-1 px-2">
                            <div class="row d-flex align-items-center justify-content-between">
                                <div class="col-12">
                                    <small class="text-muted">Client</small>
                                    <p id="infoJob-ord_client_name" class="mb-0">PT</p>
                                </div>
                            </div>
                        </li>
                    </ul> --}}
                    <ul class="list-group mb-3">
                        <li class="list-group-item p-1 px-2">
                            {{-- <p class="text-bold mb-0">#902192102910</p> --}}
                            <div class="row d-flex align-items-center justify-content-between">
                                <div class="col-12">
                                    <small class="text-muted">Origin</small>
                                    {{-- <p id="infoJob-pck_city" class="">Jakarta</p> --}}
                                    <p id="infoJob-pck_name" class="mb-1 text-bold">JKT-01</p>
                                    <p id="infoJob-pck_addr" class="mb-0">Jl. Pancoran Timur Raya No.9, RT.8/RW.9, Pancoran, Kec. Pancoran, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12780</p>
                                </div>
                            </div>
                        </li>
                        <li class="list-group-item p-1 px-2">
                            {{-- <p class="text-bold mb-0">#902192102910</p> --}}
                            <div class="row d-flex align-items-center justify-content-between">
                                <div class="col-12">
                                    <small class="text-muted">Destination</small>
                                    {{-- <p id="infoJob-drop_city" class="">Indramayu</p> --}}
                                    <p id="infoJob-drop_name" class="mb-1 text-bold">IND-01</p>
                                    <p id="infoJob-drop_addr" class="mb-0">Jl. Jend. Sudirman, Karanganyar, Kec. Indramayu, Kabupaten Indramayu, Jawa Barat</p>
                                </div>
                            </div>
                        </li>
                    </ul>
                    <ul class="list-group">
                        <li class="list-group-item p-1 px-2">
                            {{-- <p class="text-bold mb-0">#902192102910</p> --}}
                            <div class="row d-flex align-items-center justify-content-between">
                                <div class="col-12">
                                    <small class="text-muted">Status</small>
                                    <p id="infoJob-ord_stts" class="mb-0">On Going</p>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
                <ul class="list-group" id="infoMovement">
                    <li class="list-group-item p-1 px-2 mb-2" style="border-radius: 0.25rem;">
                        <p class="text-bold mb-0">Trip History</p>
                        <p id="infoVehicles-infoMove" class="text-muted mb-0">Most Recent</p>
                    </li>
                    <div>
                        <div class="mb-2">
                            <label class="text-muted">From</label>
                            <!-- <input class="form-control" id="historyStartDate"> -->
                            <input class="form-control" id="historyStartDate" value="25-08-2025 00:00">
                        </div>
                        <div class="mb-2">
                            <label class="text-muted">To</label>
                            <!-- <input class="form-control" id="historyEndDate"> -->
                            <input class="form-control" id="historyEndDate" value="25-08-2025 23:00">
                        </div>
						<button class="btn btn-primary btn-sm w-100 mb-3" id="historySearch">Search</button>
                    </div>
                    <div id="infoMove-plots" class="infoMove-plots">
                        {{-- <a href="#" class="plotMove-item">
                            <li class="list-group-item p-1 px-2">
                                <p class="text-bold mb-0">Number</p>
                                <p class="text-muted mb-0">${Number(obj.latitude).toFixed(6)} - ${Number(obj.longitude).toFixed(6)}</p>
                                <p class="text-muted mb-0">${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}</p>
                            </li>
                        </a> --}}
                    </div>
                </ul>
            </div>
            {{-- vehicle list & filter --}}
            <div class="col-sm-2 bg-white overflow-auto panel-right" style="{{ Auth::user()->role != 2 ? 'height: calc(100vh - 90.52px) !important' : '' }}" id="rightSideBar1">
                {{-- filter --}}
                <div class="row d-flex align-items-center mb-3 justify-content-between">
                    <div class="col-auto">
                        <div class="row">
                            <div class="col-auto text-start align-items-center d-flex">
                                <a href="javascript:void(0);" class="mb-0 text-bold text-dark" id="filterVhcZone" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Filter Vehicles Within and Outside the Zone">
                                    <span class="ion-android-car me-1" style="font-size: 17px">
                                    </span>
                                </a>
                                <span id="c_vhc_zone">-</span>
                            </div>
                            <div class="col-auto text-start align-items-center d-flex">
                                <a href="javascript:void(0);" class="mb-0 text-bold text-dark me-2" id="filterVhcMarker" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Marker Info">
                                    <span class="ion-android-pin me-2 text-muted" style="font-size: 17px"></span>
                                </a>
                            </div>
                            {{-- <div class="col-auto text-start align-items-center d-flex">
                                <a href="javascript:void(0);" class="mb-0 text-bold text-dark" id="filterVhcGps" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Vehicle GPS Filter">
                                    <span class="ion-pinpoint me-1 text-muted" style="font-size: 17px"></span>
                                </a>
                                <span id="c_vhc_gps">-</span>
                            </div>
                            <div class="col-auto text-start align-items-center d-flex">
                                <a href="javascript:void(0);" class="mb-0 text-bold text-dark" id="filterVhcGsm" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Vehicle GSM Filter">
                                    <span class="ion-android-wifi me-1 text-muted" style="font-size: 17px"></span>
                                </a>
                                <span id="c_vhc_gsm">-</span>
                            </div> --}}
                        </div>
                    </div>
                    <div class="col-auto">
                        <div class="">
                            <div class="col text-end align-items-center d-flex">
                                {{-- <a href="javascript:void(0);" class="mb-0 text-bold text-dark me-2" id="filterVhcMarker" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Marker Info">
                                    <span class="ion-android-pin me-2 text-muted" style="font-size: 17px"></span>
                                </a> --}}
                                <a href="javascript:void(0);" class="text-decoration-none text-dark fz-18" id="closeRightSideBar1">
                                    <span class="icon ion-ios-arrow-right"></span>
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="form-group mb-3">
                    <input type="text" id="filterVhcSearch" class="form-control form-control-sm" placeholder="Search Vehicle">
                </div>
                {{-- vehicle list --}}
                <ul id="listTrucks" class="list-group">
                    {{-- <li class="list-group-item vehicles-list-wrapper p-1 px-2">
                        <a href="#" class="text-dark">
                            <div class="row d-flex align-items-center">
                                <div class="col-3">
                                    <img src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png"
                                        class="img-fluid" alt="">
                                </div>
                                <div class="col ps-0">
                                    <p class="text-bold mb-0">B 1201 SYX</p>
                                    <p class="text-muted mb-0">Kebon Baru - Tebet</p>
                                </div>
                            </div>
                        </a>
                    </li>
                    <li class="list-group-item vehicles-list-wrapper p-1 px-2">
                        <a href="#" class="text-dark">
                            <div class="row d-flex align-items-center">
                                <div class="col-3">
                                    <img src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png"
                                        class="img-fluid" alt="">
                                </div>
                                <div class="col ps-0">
                                    <p class="text-bold mb-0">B 1202 SYX</p>
                                    <p class="text-muted mb-0">Kebon Baru - Tebet</p>
                                </div>
                            </div>
                        </a>
                    </li> --}}
                </ul>
            </div>
        </div>
    </div>
    <div class="footer-dashboard">
        <div class="container-fluid">
            <div class="row">
                <div class="col d-flex align-content-center">
                    <span class="badge p-1 ps-3 pe-3 bg-danger me-2">Stopped</span>
                    <span class="badge p-1 ps-3 pe-3 bg-warning me-2">Idling</span>
                    <span class="badge p-1 ps-3 pe-3 bg-success">Moving</span>
				</div>
				<div class="col text-end" id="tripInfo">
					<span class="badge p-1 ps-3 pe-3 bg-info me-2" style="background-color:#C0392B !important;">Trip 1</span>
					<span class="badge p-1 ps-3 pe-3 bg-info me-2" style="background-color:#2980B9 !important;">Trip 2</span>
					<span class="badge p-1 ps-3 pe-3 bg-info me-2" style="background-color:#27AE60 !important;">Trip 3</span>
					<span class="badge p-1 ps-3 pe-3 bg-info me-2" style="background-color:#D35400 !important;">Trip 4</span>
					<span class="badge p-1 ps-3 pe-3 bg-info me-2" style="background-color:#F39C12 !important;">Trip 5</span>
                </div>
            </div>
        </div>
    </div>
@endsection

@section('customjs')
    <script src="{{ asset('assets/vendor/leaflet-1.7.1/leaflet-src.js') }}"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.jsdelivr.net/npm/leaflet-rotatedmarker@0.2.0/leaflet.rotatedMarker.min.js"></script>
    <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script>
	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
					
    <script>
        'use strict';
		
        const State = {
            isDrawPolygon: 0,
            timingRouteAnimation: 100,
            storage_lara: "{{ asset('storage') }}/",
            ord_code: 0,
            zone_boundary_type: {
                circle: "{{ App\Models\Zone::ZONE_BOUNDARY_CIRCLE }}",
                polygon: "{{ App\Models\Zone::ZONE_BOUNDARY_POLYGON }}",
                rectangle: "{{ App\Models\Zone::ZONE_BOUNDARY_RECTANGLE }}",
            },
            zone_status: {
                active: "{{ App\Models\Zone::STATUS_ACTIVE }}",
                inactive: "{{ App\Models\Zone::STATUS_INACTIVE }}",
            },
            stts_engine: {
                idling: "{{ App\Models\Tracks::STTS_EN_IDLING }}",
                moving: "{{ App\Models\Tracks::STTS_EN_MOVING }}",
                stoping: "{{ App\Models\Tracks::STTS_EN_STOPING }}",
            },
            stts_gps: {
                active: "{{ App\Models\Tracks::STTS_GPS_ON }}",
                inactive: "{{ App\Models\Tracks::STTS_GPS_OFF }}",
            },
            stts_gsm: {
                no_signal: "{{ App\Models\Tracks::STTS_GSM_NO_SIGNAL }}",
                bad_signal: "{{ App\Models\Tracks::STTS_GSM_BAD_SIGNAL }}",
                weak_signal: "{{ App\Models\Tracks::STTS_GSM_WEAK_SIGNAL }}",
                good_signal: "{{ App\Models\Tracks::STTS_GSM_GOOD_SIGNAL }}",
                strong_signal: "{{ App\Models\Tracks::STTS_GSM_STRONG_SIGNAL }}",
            },
            stts_ignition: {
                active: "{{ App\Models\Tracks::STTS_IGNITION_ON }}",
                inactive: "{{ App\Models\Tracks::STTS_IGNITION_OFF }}",
                low: "{{ App\Models\Tracks::STTS_IGNITION_LOW }}",
                high: "{{ App\Models\Tracks::STTS_IGNITION_HIGH }}",
            },
            stts_filterDetail: {
                vehicles: 1,
                driver: 2,
                assignJob: 3,
                lastMove: 4,
            },
            stts_order: {
                wait: "{{ App\Models\Orders::STTS_WAIT }}",
                confirm: "{{ App\Models\Orders::STTS_CONFIRM }}",
                have_get_vhc: "{{ App\Models\Orders::STTS_HAVE_GET_VHC }}",
                pck: "{{ App\Models\Orders::STTS_PCK }}",
                go: "{{ App\Models\Orders::STTS_GO }}",
                arv: "{{ App\Models\Orders::STTS_ARV }}",
                drop: "{{ App\Models\Orders::STTS_DROP }}",
                client_pay: "{{ App\Models\Orders::STTS_CLIENT_PAY }}",
                vendor_payed: "{{ App\Models\Orders::STTS_VENDOR_PAYED }}",
                close: "{{ App\Models\Orders::STTS_CLOSE }}",
                cancel: "{{ App\Models\Orders::STTS_CANCEL }}",
            },
            statusFilterPopupVhcMarker: 1, // 0=>hidden,1=>nopol,2=>speed,3=>address
            eventFilterPopupVhcMarker: null,
            statusFilterVhcGps: 0, // 0=>all,1=>active,2=>not
            lastStatusFilterVhcGps: 0,
            isShowToltipFilterVhcGps: 0,
            eventFilterVhcGps: null,
            statusFilterVhcGsm: 0, // 0=>all,1=>active,2=>not
            lastStatusFilterVhcGsm: 0,
            isShowToltipFilterVhcGsm: 0,
            eventFilterVhcGsm: null,
            statusFilterVhcZone: 0, // 0=>all,1=>inside,2=>outside
            lastStatusFilterVhcZone: 0,
            isShowToltipFilterVhcZone: 1,
            eventFilterVhcZone: null,
            eventRemoveListTrucks: null,
            eventRemoveRouteStartEnd: null,
            eventRemoveDetailPlotMovement: null,
            eventHideTruckNotSelected: null,
            eventHideAllTruck: null,
            inShowVid: null,
            inShowLastMove: null,
            loadedLastMoveVid: null,
            lastShowVids: [],
            inShowZid: null,
            delay_typing_front: 1000,
            delay_hideTruckNotSelected: 1000,
            delay_auto_refresh: 1 * (60 * 1000), // per n minute
            historyStartDate: '',
            historyEndDate: '',
            isPanning: true,
            playback: {
                stts: 0, // 0=>not,1=>play,2=>pause,3=>resume,4=>stop
                crntIndicator: 0,
                minIndicator: 0,
                maxIndicator: 0,
                intrvl: null, // setInterval()
                intrvlTime: 1000, // 200 per ms
            },
        };

        const Icon = {
            hub: function() {
                return L.icon({
                    iconUrl: "{{ asset('assets/icons/pin-resto.png') }}",
                    iconSize: [38, 48],
                    iconAnchor: [20, 46], // lb, rt, bottom, rb. Positive
                    popupAnchor: [0, -32],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            destination: function() {
                return L.icon({
                    iconUrl: "{{ asset('assets/icons/pin-tujuan.png') }}",
                    iconSize: [38, 48],
                    iconAnchor: [20, 46], // lb, rt, bottom, rb. Positive
                    popupAnchor: [0, -32],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            point: function() {
                return L.icon({
                    // iconUrl: 'https://www.nicepng.com/png/full/101-1015767_map-marker-circle-png.png',
                    iconUrl: "{{ asset('assets/icons/maps-marker-circle-blue-radius.png') }}",
                    iconSize: [38, 38],
                    // iconAnchor: [20, 46], // lb, rt, bottom, rb. Positive
                    // popupAnchor: [0, -32],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            startNav: function() {
                return L.icon({
                    iconUrl: 'https://image.flaticon.com/icons/png/512/803/803559.png',
                    iconSize: [38, 38],
                    iconAnchor: [20, 16], // lb, rt, bottom, rb. Positive
                    // popupAnchor: [0, -32],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            titikAwal: function() {
                return L.icon({
                    iconUrl: "{{ asset('images/start.png') }}",
                    iconSize: [30, 30],
                    iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
                    // popupAnchor: [0, -32],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            titikAkhir: function() {
                return L.icon({
                    iconUrl: "{{ asset('images/finish.png') }}",
                    iconSize: [30, 30],
                    iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
                    // popupAnchor: [0, -32],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            vechicleIcon: function() {
                return L.icon({
                    iconUrl: "{{ asset('images/2active.png') }}",
                    iconSize: [30, 30],
                    iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
                    popupAnchor: [-3, -35],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            vhcIdleIcon: function() {
                return L.icon({
                    iconUrl: "{{ asset('images/2idle.png') }}",
                    iconSize: [30, 30],
                    iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
                    popupAnchor: [-3, -35],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
            vhcStopIcon: function() {
                return L.icon({
                    iconUrl: "{{ asset('images/2stop.png') }}",
                    iconSize: [30, 30],
                    iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive
                    popupAnchor: [-3, -35],
                    // shadowUrl: 'my-icon-shadow.png',
                    // shadowSize: [68, 95],
                    // shadowAnchor: [22, 94]
                });
            },
        };

        const Wrapper = {
            activate: function() {
                Wrapper.init();
                Leaflet.activate();
                Menu.activate();
                Trucks.activate();
                Filter.activate();
                PgBar.activate();
            },
            init: function() {
                const queryString = Helper.initQueryString();
                State.ord_code = queryString.ord_code;

                if (Wrapper.checkIsMobileDevice()) {
                    $('#rightSideBar1').addClass('d-none');
                    $('#openRightSideBar1').removeClass('d-none');
                }

				$('#historyStartDate, #historyEndDate').datetimepicker({
					format:'d-m-Y H:i',
					defaultTime:'00:00',
					closeOnDateSelect: true,
					// mask:true
				});
            },
            calcIdlingDur: function(lst_idle_unix, lst_speed) {
                let now = moment();
                let idlingDur = 0;
                let last_idle = moment.unix(lst_idle_unix);
                let unit = 'min';
                if (lst_speed <= 0 || lst_speed == null || lst_speed == '' || typeof lst_speed == 'undefined') {
                    if (last_idle.isValid()) {
                        let diff = moment.duration(now.diff(last_idle));
                        idlingDur = diff.asMinutes();
                        // parsing to hour
                        if (idlingDur > 60) {
                            idlingDur = idlingDur / 60;
                            unit = 'hour';
                        }
                    }
                }
                return {
                    unit,
                    dur: idlingDur.toFixed(0),
                };
            },
            calcPeriodeDate: function(startDate, endDate) {
                if (startDate.format('YYYY-MM-DD HH:mm') === 'Invalid date') {
                    Helper.toast('Warning', 'just now', 'Start date of the period is not valid');
                    return {
                        isValid: false
                    };
                }
                if (endDate.format('YYYY-MM-DD HH:mm') === 'Invalid date') {
                    Helper.toast('Warning', 'just now', 'End date of the period is not valid');
                    return {
                        isValid: false
                    };
                }
                // endDate.add(23, 'hour').add(59, 'minutes').add(59, 'seconds');
                const duration = moment.duration(endDate.diff(startDate));
                const diffDays = duration.days();
                if (diffDays > 30) {
                    Helper.toast('Warning', 'just now', 'Maximum period is 1 month');
                    return {
                        isValid: false
                    };
                }
                if (diffDays < 0) {
                    Helper.toast('Warning', 'just now', 'Invalid period range');
                    return {
                        isValid: false
                    };
                }
                return {
                    isValid: true,
                    data: {
                        startDate,
                        endDate
                    }
                };
            },
            checkIsMobileDevice: function() {
                return (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
            },
        };

        // ## centering + zoom
        // Leaflet.map.fitBounds([
        //     [40.712, -74.227],
        //     [40.774, -74.125]
        // ]);
        // ## centering with animation
        // Leaflet.map.panTo([40.712, -74.227], { duration: 5 });
        const Leaflet = {
            map: null,
            activate: function() {
                // centering indonesia country => .setView([-1.38116, 117.6168817], 5.4);
                // Leaflet.map = L.map('map').setView([-7.1451449, 109.9776078], 8); // centering javanese province
                // Leaflet.map = L.map('map').setView([-7.8241413, 112.9071746], 9); // centering east java province
                // Leaflet.map = L.map('map').setView([-6.2106272, 106.8477106], 9); // centering east java province
                Leaflet.map = L.map('map').setView([-8.90507, 125.9945732], 10); // centering timor leste
                L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
                    attribution: 'Map data &copy; <a href="https://www.mapbox.com/feedback/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
                    // maxZoom: 20,
                    // minZoom: 4,
                    id: 'mapbox/streets-v11',
                    tileSize: 512,
                    zoomOffset: -1,
                    accessToken: 'pk.eyJ1IjoibWV1c2luZmlybWFyeSIsImEiOiJja3lsd2xveDAydGhqMnVxaHJsZ2ZncG8yIn0.f7MJAyawHUdCegw7sWjrww',
                }).addTo(Leaflet.map);
                Leaflet.events();
                L.control.scale({
                    position: 'bottomright'
                }).addTo(Leaflet.map);
                L.control.zoom({
                    position: 'bottomright'
                }).addTo(Leaflet.map);
            },
            events: function() {
                Leaflet.map.on('click', function(e) {
                    // e.latlng.lat, e.latlng.lng
                });
                // https://gis.stackexchange.com/questions/104507/disable-panning-dragging-on-leaflet-map-for-div-within-map // number 2 from bottom
                $('.disablePanning').on('mousedown', function() {
                    if (State.isPanning) {
                        State.isPanning = false;
                        Leaflet.map.dragging.disable();
                    }
                });
                $('.disablePanning').on('mouseup', function() {
                    if (!State.isPanning) {
                        State.isPanning = true;
                        Leaflet.map.dragging.enable();
                    }
                });
            },
            addMarkers: function(locs = [], cb = null) {
                if (locs.constructor === Array) {
                    let markers = [];
                    for (let i = 0; i < locs.length; i++) {
                        let label = locs[i]?.label || '';
                        let marker = new L.marker([locs[i].lat, locs[i].lng], locs[i]?.options);
                        let popup = new L.Popup({
                            autoClose: false,
                            closeOnClick: true,
                        }).setContent(locs[i]?.label || '').setLatLng([locs[i].lat, locs[i].lng]);
                        // marker.bindPopup(locs[i]?.label || '');
                        marker.bindPopup(popup);
                        marker.bindTooltip(locs[i]?.label || '');
                        markers.push(marker);
                        if (cb) cb(marker);
                        marker.addTo(Leaflet.map);
                    }
                    return markers;
                } else if (locs.constructor === Object) {
                    let label = locs.label;
                    let marker = new L.marker([locs.lat, locs.lng], locs?.options);
                    let popup = new L.Popup({
                        autoClose: false,
                        closeOnClick: true,
                    }).setContent(locs?.label || '').setLatLng([locs.lat, locs.lng]);
                    // marker.bindPopup(locs?.label || '');
                    marker.bindPopup(popup);
                    marker.bindTooltip(locs?.label || '');
                    if (cb) cb(marker);
                    marker.addTo(Leaflet.map);
                    return marker;
                }
            },
            addCircles: function(locs = [], cb = null) {
                if (locs.constructor === Array) {
                    let circles = [];
                    for (let i = 0; i < locs.length; i++) {
						// invisible circle
						if(locs[i].options?.markerOpacity == 0){
							locs[i].options.opacity = 0
							locs[i].options.fill = false
						}
                        let circle = L.circle([locs[i].lat, locs[i].lng], locs[i]?.options);
                        circle.bindPopup(locs[i]?.label || '');
                        circle.bindTooltip(locs[i]?.label || '');
                        circles.push(circle);
                        if (cb) cb(circle, i);
                        circle.addTo(Leaflet.map);
                    }
                    return circles;
                } else if (locs.constructor === Object) {
                    let circle = L.circle([locs.lat, locs.lng], locs?.options);
                    circle.bindPopup(locs?.label || '');
                    circle.bindTooltip(locs?.label || '');
                    if (cb) cb(circle);
                    circle.addTo(Leaflet.map);
                    return circle;
                }
            },
            addPolylines: function(locs = [], cb = null) {
                let latLngs = [];
                for (let i = 0; i < locs.length; i++) {
                    latLngs.push([locs[i].lat, locs[i].lng]);
                }
                let polyline = L.polyline(latLngs, locs[0]?.options).addTo(Leaflet.map);

                if (cb) cb(polyline);
                return polyline;
            },
            addRoutes: function(locs = [], cb = null) {
                let latLngs = [];
                for (let i = 0; i < locs.length; i++) {
                    latLngs.push([locs[i].lat, locs[i].lng]);
                }
				// let routes = L.Routing.control({
				// 	waypoints: latLngs.reverse(), // reverse to make first point as start
				// 	// router: L.Routing.osrmv1(),
				// 	router: L.Routing.osrmv1({
				// 		serviceUrl: "https://brilianapps.britimorleste.tl:5001/route/v1",
				// 	}),
				// 	show: false,
				// 	itinerary: null, // 👈 completely removes the panel
				// 	addWaypoints: false, // ❌ prevent adding points by clicking
				// 	draggableWaypoints: false, // ❌ prevent dragging markers
				// 	routeWhileDragging: false, // optional: don’t reroute while dragging
				// 	createMarker: () => null,
				// 	lineOptions:{
				// 		styles: [{ color: locs[0]?.options?.color, weight: 3, opacity: 0.7 }],
				// 	},
				// }).addTo(Leaflet.map)

				function fetchOsrm(points) {
					// balik koordinat: [lat, lon] -> [lon, lat]
					const coords = points

					// hints: N-1 semicolon
					const hints = ";".repeat(points.length - 1);

					const body = {
						coordinates: coords,
						overview: "false",
						alternatives: "true",
						steps: "true",
						hints: hints
					};

					let config = {
						method: 'post',
						maxBodyLength: Infinity,
						url: 'https://brilianapps.britimorleste.tl/osrm-backend/post-route/v1/driving/',
						headers: {
							'Content-Type': 'application/json'
						},
						data: body
					};

					return axios.request(config)
						.then((response) => {
							// console.log(JSON.stringify(response.data));
							return response.data; // supaya bisa dipakai di luar
						})
						.catch((error) => {
							console.error("Error:", err.message);
							return null;
						});

				}

				function decodeOSRMGeometry(encoded) {
					const coordinates = [];
					let index = 0,
						lat = 0,
						lng = 0;

					while (index < encoded.length) {
						let result = 1,
							shift = 0,
							b;
						do {
							b = encoded.charCodeAt(index++) - 63 - 1;
							result += b << shift;
							shift += 5;
						} while (b >= 0x1f);
						lat += (result & 1 ? ~(result >> 1) : result >> 1);

						result = 1;
						shift = 0;
						do {
							b = encoded.charCodeAt(index++) - 63 - 1;
							result += b << shift;
							shift += 5;
						} while (b >= 0x1f);
						lng += (result & 1 ? ~(result >> 1) : result >> 1);

						coordinates.push([lat / 1e5, lng / 1e5]);
					}

					return coordinates;
				}

				let routes
				fetchOsrm(latLngs).then(osrm => {
					if (!osrm) return console.log("OSRM gagal");

					const coords = osrm.routes[0].legs.flatMap(leg =>
						leg.steps.flatMap(step =>
							decodeOSRMGeometry(step.geometry)
						)
					);

					routes = L.polyline(coords, {
						color: locs[0]?.options?.color,
						weight: 3,
						opacity: 0.8
					}).addTo(Leaflet.map);
					Leaflet.map.fitBounds(coords.map(c => L.latLng(c[0], c[1])));
				});


                if (cb) cb(routes);
                return routes;
            },
            // start custom polylines
            addCustomPolylines: function(locs = [], cb = null) {
                const radius = 0.5 /* corner smooth radius, keep value in range 0 - 0.5 to avoid artifacts */
                let latLngs = [];

                for (let i = 0; i < locs.length; i++) {
                    latLngs.push([locs[i].lat, locs[i].lng]);
                }

                let SmoothPoly = L.Polyline.extend({
                    // override default method to use custom points-to-path method
                    _updatePath: function() {
                        let path = Leaflet.roundPathCorners(this._parts, radius)
                        this._renderer._setPath(this, path);
                    }
                })

                let polyline = new SmoothPoly(latLngs, locs[0]?.options).addTo(Leaflet.map);

                if (cb) cb(polyline);
                return polyline;
            },
            roundPathCorners: function(rings, radius) {
                function moveTowardsFractional(movingPoint, targetPoint, fraction) {
                    return {
                        x: movingPoint.x + (targetPoint.x - movingPoint.x) * fraction,
                        y: movingPoint.y + (targetPoint.y - movingPoint.y) * fraction
                    };
                }

                function pointForCommand(cmd) {
                    return {
                        x: parseFloat(cmd[cmd.length - 2]),
                        y: parseFloat(cmd[cmd.length - 1])
                    };
                }
                let resultCommands = [];
                if (+radius) {
                    // negative numbers create artifacts
                    radius = Math.abs(radius);
                } else {
                    radius = 0.15;
                }
                for (let i = 0, len = rings.length; i < len; i++) {
                    let commands = rings[i];
                    // start point
                    resultCommands.push(["M", commands[0].x, commands[0].y]);
                    for (let cmdIndex = 1; cmdIndex < commands.length; cmdIndex++) {
                        let prevCmd = resultCommands[resultCommands.length - 1];
                        let curCmd = commands[cmdIndex];
                        let nextCmd = commands[cmdIndex + 1];
                        if (nextCmd && prevCmd) {
                            // Calc the points we're dealing with
                            let prevPoint = pointForCommand(prevCmd); // convert to Object
                            let curPoint = curCmd;
                            let nextPoint = nextCmd;
                            // The start and end of the cuve are just our point moved towards the previous and next points, respectivly
                            let curveStart, curveEnd;
                            curveStart = moveTowardsFractional(
                                curPoint,
                                prevCmd.origPoint || prevPoint,
                                radius
                            );
                            curveEnd = moveTowardsFractional(
                                curPoint,
                                nextCmd.origPoint || nextPoint,
                                radius
                            );
                            // Adjust the current command and add it
                            curCmd = Object.values(curveStart);
                            curCmd.origPoint = curPoint;
                            curCmd.unshift("L");
                            resultCommands.push(curCmd);
                            // The curve control points are halfway between the start/end of the curve and
                            // calculate curve, if radius is different than 0
                            if (radius) {
                                let startControl = moveTowardsFractional(curveStart, curPoint, 0.5);
                                let endControl = moveTowardsFractional(curPoint, curveEnd, 0.5);
                                // Create the curve
                                let curveCmd = [
                                    "C",
                                    startControl.x,
                                    startControl.y,
                                    endControl.x,
                                    endControl.y,
                                    curveEnd.x,
                                    curveEnd.y
                                ];
                                // Save the original point for fractional calculations
                                curveCmd.origPoint = curPoint;
                                resultCommands.push(curveCmd);
                            }
                        } else {
                            // Pass through commands that don't qualify
                            let el = Object.values(curCmd);
                            el.unshift("L");
                            resultCommands.push(el);
                        }
                    }
                }
                return (
                    resultCommands.reduce(function(str, c) {
                        return str + c.join(" ") + " ";
                    }, "") || "M0 0"
                );
            },
            // end custom polylines
            addPolygons: function(locs = [], cb = null) {
                let latLngs = [];
                for (let i = 0; i < locs.length; i++) {
                    latLngs.push([locs[i].lat, locs[i].lng]);
                }
                let polygon = L.polygon(latLngs, locs[0]?.options).addTo(Leaflet.map);
                polygon.bindPopup(locs[0]?.label || '');
                polygon.bindTooltip(locs[0]?.label || '');

                if (cb) cb(polygon);
                return polygon;
            },
            addWaypoints: function(locs = [], cb = null) {
                let latLngs = [];
                for (let i = 0; i < locs.length; i++) {
                    latLngs.push(L.latLng(locs[i].lat, locs[i].lng));
                }
                let control = L.Routing.control({
                    waypoints: latLngs,
                    show: false,
                    waypointMode: 'snap',
                    createMarker: function() {}
                }).addTo(Leaflet.map);
                if (cb) cb(control);
                return control;
            },
            drawPolygon: function(lat, lng, options = {}) {
                let polygon = L.polygon([
                    [lat, lng]
                ], options).addTo(Leaflet.map);
                return polygon;
            },
            eventMarkerClick: function(marker, cb = null) {
                marker.on('click', function(e) {
                    // console.log(e.target.options); // get passing data from set marker: https://stackoverflow.com/questions/17423261/how-to-pass-data-with-marker-in-leaflet-js
                    Leaflet.map.invalidateSize();
                    if (Leaflet.map.getZoom() <= 14) {
                        Leaflet.map.setView(e.target.getLatLng(), 14);
                    }
                    if (cb) cb(e);
                });
            },
            clearLayer: function(type = 'all', cb = null) {
                if (type == 'all') {
                    if (State.eventRemoveListTrucks) window.dispatchEvent(State.eventRemoveListTrucks);
                    if (State.eventRemoveRouteStartEnd) window.dispatchEvent(State.eventRemoveRouteStartEnd);
                    if (State.eventRemoveDetailPlotMovement) window.dispatchEvent(State
                        .eventRemoveDetailPlotMovement);
                    if (State.eventRemoveListZones) window.dispatchEvent(State.eventRemoveListZones);
                    if (cb) cb();
                } else if (type == 'eventRemoveListTrucks') {
                    if (State.eventRemoveListTrucks) {
                        window.dispatchEvent(State.eventRemoveListTrucks);
                        if (cb) cb();
                    }
                } else if (type == 'eventRemoveRouteStartEnd') {
					// console.log('clear route eventRemoveRouteStartEnd');
                    if (State.eventRemoveRouteStartEnd) {
                        window.dispatchEvent(State.eventRemoveRouteStartEnd);
                        if (cb) cb();
                    }
                } else if (type == 'eventRemoveDetailPlotMovement') {
                    if (State.eventRemoveDetailPlotMovement) {
                        window.dispatchEvent(State.eventRemoveDetailPlotMovement);
                        if (cb) cb();
                    }
                } else if (type == 'eventRemoveListZones') {
                    if (State.eventRemoveListZones) {
                        window.dispatchEvent(State.eventRemoveListZones);
                        if (cb) cb();
                    }
                } else if (type == 'eventAboutTruck') {
                    if (State.eventRemoveListTrucks) window.dispatchEvent(State.eventRemoveListTrucks);
                    if (State.eventRemoveRouteStartEnd) window.dispatchEvent(State.eventRemoveRouteStartEnd);
                    if (State.eventRemoveDetailPlotMovement) window.dispatchEvent(State
                        .eventRemoveDetailPlotMovement);
                    if (cb) cb();
                }
            },
            filterLayer: function(type = 'all', cb = null) {
                if (type == 'all') {
                    if (State.eventFilterPopupVhcMarker) window.dispatchEvent(State.eventFilterPopupVhcMarker);
                    if (State.eventFilterVhcGps) window.dispatchEvent(State.eventFilterVhcGps);
                    if (State.eventFilterVhcGsm) window.dispatchEvent(State.eventFilterVhcGsm);
                    if (State.eventFilterVhcZone) window.dispatchEvent(State.eventFilterVhcZone);
                    if (cb) cb();
                } else if (type == 'eventFilterPopupVhcMarker') {
                    if (State.eventFilterPopupVhcMarker) {
                        window.dispatchEvent(State.eventFilterPopupVhcMarker);
                        if (cb) cb();
                    }
                } else if (type == 'eventFilterVhcGps') {
                    if (State.eventFilterVhcGps) {
                        window.dispatchEvent(State.eventFilterVhcGps);
                        if (cb) cb();
                    }
                } else if (type == 'eventFilterVhcGsm') {
                    if (State.eventFilterVhcGsm) {
                        window.dispatchEvent(State.eventFilterVhcGsm);
                        if (cb) cb();
                    }
                } else if (type == 'eventFilterVhcZone') {
                    if (State.eventFilterVhcZone) {
                        window.dispatchEvent(State.eventFilterVhcZone);
                        if (cb) cb();
                    }
                }
            },
            hideLayer: function(type = 'all', cb = null) {
                if (type == 'all') {
                    if (State.eventHideAllTruck) window.dispatchEvent(State.eventHideAllTruck);
                    if (cb) cb();
                } else if (type == 'eventHideTruckNotSelected') {
                    if (State.eventHideTruckNotSelected) {
                        if (State.eventHideTruckNotSelected) {
                            window.dispatchEvent(State.eventHideTruckNotSelected);
                            if (cb) cb();
                        }
                    }
                } else if (type == 'eventHideAllTruck') {
                    if (State.eventHideAllTruck) {
                        if (State.eventHideAllTruck) {
                            window.dispatchEvent(State.eventHideAllTruck);
                            if (cb) cb();
                        }
                    }
                }
            },
        };

        const Menu = {
            activate: function() {
                $('.select2').select2();
                $('#openRightSideBar1').on('click', function() {
                    $('#rightSideBar1').removeClass('d-none');
                    $('#rightSideBar1').addClass('d-block');
                    $(this).removeClass('d-block');
                    $(this).addClass('d-none');
                    Leaflet.map.invalidateSize();
                })
                $('#closeRightSideBar1').on('click', function() {
                    $('#rightSideBar1').addClass('d-none');
                    // if (Wrapper.checkIsMobileDevice()) {
                    //     $('#openLeftSideBar1Mobile').removeClass('d-none');
                    //     $('#openLeftSideBar1Mobile').addClass('d-block');
                    // }
                    $('#openRightSideBar1').removeClass('d-none');
                    $('#openRightSideBar1').addClass('d-block');
                    $('#rightSideBar2').addClass('d-none');
                    Leaflet.map.invalidateSize();
                })
                $('#openLeftSideBar1Mobile').on('click', function() {
                    Zone.bundleGetListZones(true);
                    $('#leftSideBar1').removeClass('d-none');
                    $('#leftSideBar1').addClass('d-block');
                    $(this).removeClass('d-block');
                    $(this).addClass('d-none');
                    Leaflet.map.invalidateSize();
                });

                $('#closeRightSideBar2').on('click', function() {
                    $('#rightSideBar2').addClass('d-none');
                    Leaflet.map.invalidateSize();
                    State.inShowVid = null;
                    Leaflet.clearLayer('eventAboutTruck');
                    Trucks.bundleGetListTrucks(true);
                })
                $('#openLeftSideBar1').on('click', function() {
                    Zone.bundleGetListZones(true);
                    $('#leftSideBar1').removeClass('d-none');
                    $('#leftSideBar1').addClass('d-block');
                    $(this).removeClass('d-block');
                    $(this).addClass('d-none');
                    Leaflet.map.invalidateSize();
                })
                $('#closeLeftSideBar1').on('click', function() {
                    Zone.bundleGetListZones(false);
                    $('#leftSideBar1').addClass('d-none');
                    if (Wrapper.checkIsMobileDevice()) {
                        $('#openLeftSideBar1Mobile').removeClass('d-none');
                        $('#openLeftSideBar1Mobile').addClass('d-block');
                    } else {
                        $('#openLeftSideBar1').removeClass('d-none');
                        $('#openLeftSideBar1').addClass('d-block');
                    }
                    Leaflet.map.invalidateSize();
                })

                $('#listZone').on('click', '.zone-item', function(e) {
                    $('#leftSideBar2').removeClass('d-none');
                    $('#leftSideBar2').addClass('d-block');
                });

                $('#closeLeftSideBar2').on('click', function() {
                    $('#leftSideBar2').addClass('d-none');
                    Leaflet.map.invalidateSize();
                })

                $('#selectFiter').on('select2:select', function(e) {
                    Menu.showViewDetailVehicle($(this).val());
                });

                Menu.showViewDetailVehicle(State.stts_filterDetail.vehicles);

                Menu.eventListVehicle();
                Menu.eventListMovement();
                Menu.eventListZone();
                Menu.eventFilter();
                Menu.eventFilterHistoryDate();
            },
            showViewDetailVehicle: async function(type) {
                if (type == State.stts_filterDetail.vehicles) { // vehicles
                    $('#infoVehicles').removeClass('d-none');
                    $('#infoVehicles').addClass('d-block');
                    $('#infoDriver').addClass('d-none');
                    $('#infoJob').addClass('d-none');
                    $('#infoMovement').addClass('d-none');
                } else if (type == State.stts_filterDetail.driver) { // driver
                    $('#infoVehicles').addClass('d-none');
                    $('#infoDriver').removeClass('d-none');
                    $('#infoDriver').addClass('d-block');
                    $('#infoJob').addClass('d-none');
                    $('#infoMovement').addClass('d-none');
                } else if (type == State.stts_filterDetail.assignJob) { // assign job
                    $('#infoVehicles').addClass('d-none');
                    $('#infoDriver').addClass('d-none');
                    $('#infoJob').removeClass('d-none');
                    $('#infoJob').addClass('d-block');
                    $('#infoMovement').addClass('d-none');
                } else if (type == State.stts_filterDetail.lastMove) { // last movement
                    $('#infoVehicles').addClass('d-none');
                    // $('#infoDriver').addClass('d-none');
                    $('#infoJob').addClass('d-none');
                    $('#infoMovement').removeClass('d-none');
                    $('#infoMovement').addClass('d-block');
                    // if (State.inShowVid) {
                    //     let cache = !(State.inShowVid != State.loadedLastMoveVid);
                    //     Trucks.bundleShowRouteTruck(cache); // jika data yang diload sebelumnya beda, maka tidak mengambil dari cache
                    // }
                }
            },
            eventListVehicle: function() {
                $('#listTrucks').on('click', '.vhc-item', async function(e) {
                    let clicked = $(e.target)
                    let vid = clicked.closest('.vhc-item').data('vid');
                    if (Trucks.lists) {
                        for (let i = 0; i < Trucks.lists.length; i++) {
                            if (Trucks.lists[i].vid == vid) {
                                Trucks.showDetailGeneral(Trucks.lists[i]);
                                Leaflet.hideLayer('eventHideTruckNotSelected');
                                Leaflet.clearLayer('eventRemoveRouteStartEnd', async function() {
                                    await Trucks.bundleGetListTrucks(true);
                                    setTimeout(() => {
                                        Leaflet.hideLayer('eventHideTruckNotSelected');
                                    }, State.delay_hideTruckNotSelected);
                                });
                                Leaflet.clearLayer('eventRemoveDetailPlotMovement');
                                $('#selectFiter').val(State.stts_filterDetail.vehicles).trigger('change');
                                $('#selectFiter').val(State.stts_filterDetail.vehicles).trigger('select2:select');
                                $('#rightSideBar2').removeClass('d-none');
                                if (Trucks.lists[i]?.lst_lat == null || Trucks.lists[i]?.lst_lng == null) {
                                    Helper.toast('Warning', 'just now',
                                        `Last location for this vehicle not found\n${Trucks.lists[i].nopol1} ${Trucks.lists[i].nopol2} ${Trucks.lists[i].nopol3}`
                                    );
                                    continue;
                                }
                                // Leaflet.map.fitBounds([
                                //     [Trucks.lists[i].lst_lat, Trucks.lists[i].lst_lng],
                                // ]);
                                if (Leaflet.map.getZoom() <= 14) {
                                    Leaflet.map.setView([Trucks.lists[i].lst_lat, Trucks.lists[i].lst_lng],
                                        14);
                                } else {
                                    Leaflet.map.setView([Trucks.lists[i].lst_lat, Trucks.lists[i].lst_lng]);
                                }
                            }
                        }
                    }
                });
            },
            showToListMovement: function(obj) {
                /**
                 * fix DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains
                 * because of string Cawang–Pluit
                 * solution: https://stackoverflow.com/questions/23223718/failed-to-execute-btoa-on-window-the-string-to-be-encoded-contains-characte
                 * window.btoa( unescape(encodeURIComponent(str) ) is deprecated => window.btoa(encodeURIComponent(str))
                 */
                // <p class="text-muted mb-0">${(obj?.city_text || obj?.state_text || 'address')} - ${(obj?.postcode || 'postcode')}</p>
                // <p class="text-muted mb-0">${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}</p> // yang ini mix

                // <p class="text-success mb-0">Device Time: ${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm')}</p>
                // <p class="text-danger mb-0">Server Time: ${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm')}</p>
                // <p class="${(obj.pre_milleage >= 3) ? 'text-warning' : 'text-muted'} mb-0">Pre Milleage: ${(obj.pre_milleage).toFixed(3)} Km</p>

                // $('#infoMove-plots').append(`
            //     <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}">
            //         <li class="list-group-item p-1 px-2">
            //             <p class="text-bold mb-0">${obj.key_index}</p>
            //             <p class="text-bold mb-0">Time: ${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm')}</p>
            //             <p class="text-muted mb-0">Speed: ${(typeof obj.speed != 'undefined') ? obj.speed : '0'}</p>
            //             <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p>
            //             <p class="text-muted mb-0">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 25)}</p>
            //         </li>
            //     </a>
            // `);
                let arrIdx = Helper.getIndexReversedSequence(obj.key_index - 1, Trucks.last_move.length - 1);
                // +7
                // $('#infoMove-plots').append(`
            //     <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}">
            //         <li class="list-group-item p-1 px-2">
            //             <p class="text-bold mb-0">${arrIdx + 1}</p>
            //             <p class="text-bold mb-0">Time: ${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm:ss')}</p>
            //             <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p>
            //             <p class="text-muted mb-2">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 255)}</p>
            //             <p class="mb-0">Current speed: ${Number(obj.speed)}km/h</p>
            //         </li>
            //     </a>
            // `);
                $('#infoMove-plots').append(`
                    <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}">
                        <li class="list-group-item p-1 px-2">
                            <p class="text-bold mb-0">${arrIdx + 1}</p>
                            <p class="text-bold mb-0">Time: ${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm:ss')}</p>
                            <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p>
                            <p class="text-muted mb-2">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 255)}</p>
                            <p class="mb-0">Current speed: ${Number(obj.speed)}km/h</p>
                        </li>
                    </a>
                `);
            },
            eventListMovement: function() {
                $('#infoMove-plots').on('click', '.plotMove-item', function(e) {
                    let tr = JSON.parse(decodeURIComponent(window.atob($(e.target).closest('.plotMove-item').data('obj'))));
					// console.log("tr", tr);
					
                    let arrIdx = Helper.getIndexReversedSequence(tr.key_index - 1, Trucks.last_move.length - 1);
					// console.log("arrIdx", arrIdx);
					
                    PgBar.setCrntVal(arrIdx);
                    Menu.createMarkerDetailPlotMovement(tr);
                })
            },
            createMarkerDetailPlotMovement: function(tr, opt = {}) {
                Leaflet.clearLayer('eventRemoveDetailPlotMovement');
                let marker = Leaflet.addMarkers({
                    lat: tr.latitude,
                    lng: tr.longitude,
                    // label: `<b>${tr.key_index}</b><br>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}<br>${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof tr.lst_speed != 'undefined') ? tr.lst_speed : '0'}<br>${tr.latitude},${tr.longitude}<br>${decodeURIComponent(tr?.fulladdress || 'address')}`,
                    label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>${decodeURIComponent(tr?.fulladdress || 'address')}.<br><br>Current speed: ${tr?.speed}km/h`,
                    //label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${moment.unix(tr?.lst_loc_crt_s).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(tr?.fulladdress || 'address')}.<br><br>Current speed: ${tr?.speed}km/h`,
                    options: {
                        // icon: Icon.destination()
                    }
                });
                marker.openPopup();

                let curr_zoom = Leaflet.map.getZoom();
                if (opt.nozoom) {
                    Leaflet.map.setView([tr.latitude, tr.longitude], curr_zoom);
                } else {
                    if (curr_zoom <= 16) {
                        Leaflet.map.setView([tr.latitude, tr.longitude], 16);
                    } else {
                        Leaflet.map.setView([tr.latitude, tr.longitude], curr_zoom);
                    }
                }
                // remove marker, circle, event listener and all about this marker
                State.eventRemoveDetailPlotMovement = new CustomEvent('eventRemoveDetailPlotMovement', {
                    marker,
                });
                window.addEventListener('eventRemoveDetailPlotMovement', function handler(e) {
                    marker.removeEventListener('click');
                    marker.remove();
                    e.currentTarget.removeEventListener(e.type,
                        handler); // window.removeEventListener('remove', this.handler, true);
                    State.eventRemoveDetailPlotMovement = null;
                });
            },
            clearListMovements: function() {
                $('#infoMove-plots').html('');
            },
            eventListZone: function() {
                $('#listZone').on('click', '.zone-item', function(e) {
                    let clicked = $(e.target)
                    let zid = clicked.closest('.zone-item').data('zid');
                    if (Zone.lists) {
                        for (let i = 0; i < Zone.lists.length; i++) {
                            if (Zone.lists[i].id == zid) {
                                Zone.showDetailGeneral(Zone.lists[i]);
                                let boundary_latlngs = JSON.parse(Zone.lists[i].boundary_latlngs);
                                let fitBounds = [];
                                for (let row of boundary_latlngs) {
                                    let corner = L.latLng(row.lat, row.lng);
                                    fitBounds.push(L.latLngBounds(corner, corner));
                                }
                                Leaflet.map.fitBounds(fitBounds);
                                // if circle
                                // if (Leaflet.map.getZoom() <= 14) {
                                //     Leaflet.map.setView([Zone.lists[i].lst_lat, Zone.lists[i].lst_lng],
                                //         14)
                                // }
                            }
                        }
                    }
                });
                $('#clearZone').on('click', function() {
                    Leaflet.clearLayer('eventRemoveListZones', null);
                });
            },
            eventFilter: function() {
                $('#filterVhcMarker').on('click', function() {
                    Leaflet.filterLayer('eventFilterPopupVhcMarker');
                });
                $('#filterVhcGps').on('click', function() {
                    Leaflet.filterLayer('eventFilterVhcGps');
                });
                $('#filterVhcGsm').on('click', function() {
                    Leaflet.filterLayer('eventFilterVhcGsm');
                });
                $('#filterVhcZone').on('click', function() {
                    Leaflet.filterLayer('eventFilterVhcZone');
                });
                // searching
                let timeoutFilterVhcSearch = null;
                $('#filterVhcSearch').on('keyup', function() {
                    clearTimeout(timeoutFilterVhcSearch);

                    timeoutFilterVhcSearch = setTimeout(() => {
                        Menu.handlerFilterVhcSearch($('#filterVhcSearch').val());
                    }, State.delay_typing_front);
                });
                let timeoutFilterZoneSearch = null;
                $('#filterZoneSearch').on('keyup', function() {
                    clearTimeout(timeoutFilterZoneSearch);

                    timeoutFilterZoneSearch = setTimeout(() => {
                        Menu.handlerFilterZoneSearch($('#filterZoneSearch').val());
                    }, State.delay_typing_front);
                });
            },
            eventFilterHistoryDate: function() {
                $('#historySearch').on('click', function(e) {
					e.preventDefault();
					// console.log("change history date", this.id, this.value);
					const value = this.value;
					const id = this.id;
					if(State[id] == moment(value, "DD-MM-YYYY HH:mm").unix())
						return false;

					const date0 = moment($('#historyStartDate').val(), "DD-MM-YYYY HH:mm")
					const date1 = moment($('#historyEndDate').val(), "DD-MM-YYYY HH:mm")
                    const {
                        isValid,
                        data
                    } = Wrapper.calcPeriodeDate(
						date0,
						date1
					)
                    if (!isValid) return false;
					// console.log("isValid", isValid, data);
					
                    State.historyStartDate = date0.unix();
                    State.historyEndDate = date1.unix();

                    Leaflet.clearLayer('eventRemoveRouteStartEnd');
                    Trucks.bundleShowRouteTruck(false);
                });
                // $('#historyEndDate').on('change', function(e) {
                //     const {
                //         isValid,
                //         data
                //     } = Wrapper.calcPeriodeDate(moment($('#historyStartDate').val()), moment($('#historyEndDate').val()))
                //     if (!isValid) return false;
                //     State.historyStartDate = data.startDate.unix();
                //     State.historyEndDate = data.endDate.unix();

                //     Leaflet.clearLayer('eventRemoveRouteStartEnd');
                //     Trucks.bundleShowRouteTruck(false);
                // });
                $('#historyStartDate').on('clearFilterHistoryDate', function(e) {
					// default date today
                    // State.historyStartDate = moment().startOf('day').unix();
                    // State.historyEndDate = moment().endOf('day').unix();
					// $('#historyStartDate').val(moment().startOf('day').format('DD-MM-YYYY HH:mm'));
					// $('#historyEndDate').val(moment().endOf('day').format('DD-MM-YYYY HH:mm'));

					// for testing purpose
                    State.historyStartDate = '1756054800';
                    State.historyEndDate = '1756141140';
					$('#historyStartDate').val("25-08-2025 00:00");
					$('#historyEndDate').val("25-08-2025 23:59");
				});
            },
            handlerFilterPopupVhcMarker: function(markers) {
                if (State.inShowLastMove) {
                    Helper.toast('Warning', 'just now', 'Cannot show marker info when see last movement');
                    return false;
                }
                // 0=>hidden,1=>nopol,2=>speed,3=>address
                let latLng = Leaflet.map.getCenter();
                for (let marker of markers) {
                    let mdata = marker.options.mdata;
                    if (!State.lastShowVids.includes(mdata.vid)) {
                        continue;
                    }
                    if (State.statusFilterPopupVhcMarker === 0) {
                        // let content =
                        //     `<div class="bg-color"><b>${mdata.nopol1} ${mdata.nopol2} ${mdata.nopol3}</b></div>`;
                        // marker.bindTooltip(content);
                        // marker.closePopup();
                    } else if (State.statusFilterPopupVhcMarker === 1) {
                        // let content =
                        //     `<div class="bg-color"><b>${mdata.nopol1} ${mdata.nopol2} ${mdata.nopol3}</b></div>`;
                        let content = `<b>${mdata.nopol1} ${mdata.nopol2} ${mdata.nopol3}</b>`;
                        if (mdata?.ord_pck_ktname && mdata?.ord_drop_ktname) {
                            content += `<div style="margin-bottom:10px;"><strong>${mdata?.ord_c_pt_name}</strong></div>`;
                            content += `<div style="margin-bottom:0;">Origin</div>`;
                            content += `<div style="margin-bottom:0.25rem;"><strong>${mdata?.ord_pck_ktname}</strong></div>`;
                            content += `<div style="margin-bottom:0;">Destination</div>`;
                            content += `<div style="margin-bottom:0;"><strong>${mdata?.ord_drop_ktname}</strong></div>`;
                        }
                        marker.setPopupContent(content);
                        marker.bindTooltip(content);
                        marker.openPopup();
                    } else if (State.statusFilterPopupVhcMarker === 2) {
                        // cara lama
                        // let speedOrIdle = (typeof mdata.lst_speed != 'undefined') ? mdata.lst_speed : 0;
                        // if (mdata.stts_engine == State.stts_engine.idling) speedOrIdle = 0;
                        // if (speedOrIdle === 0) {
                        //     let idlingDur = Wrapper.calcIdlingDur(mdata?.lst_idle_at, mdata?.lst_speed);
                        //     if (idlingDur.unit == 'hour') {
                        //         let min = idlingDur.dur * 60;
                        //         if (idlingDur.dur <= 1) {
                        //             speedOrIdle = ` <= ${min.toFixed(0)} min`;
                        //         } else if (idlingDur.dur > 6) {
                        //             speedOrIdle = ' > 6 hr';
                        //         } else if (idlingDur.dur > 4) {
                        //             speedOrIdle = ' > 4 hr';
                        //         } else if (idlingDur.dur > 2) {
                        //             speedOrIdle = ' > 2 hr';
                        //         } else if (idlingDur.dur > 1) {
                        //             speedOrIdle = ' > 1 hr';
                        //         }
                        //     } else if (idlingDur.unit == 'min') {
                        //         let hr = idlingDur.dur / 60;
                        //         if (hr <= 1) {
                        //             speedOrIdle = ` <= ${idlingDur.dur} min`;
                        //         } else if (hr > 6) {
                        //             speedOrIdle = ' > 6 hr';
                        //         } else if (hr > 4) {
                        //             speedOrIdle = ' > 4 hr';
                        //         } else if (hr > 2) {
                        //             speedOrIdle = ' > 2 hr';
                        //         } else if (hr > 1) {
                        //             speedOrIdle = ' > 1 hr';
                        //         }
                        //     }
                        // } else {
                        //     speedOrIdle += ' Kph';
                        // }

                        // differentation minute / hour
                        function getDiff(last) {
                            let now = moment(); // as start
                            let end = moment.unix(last ?? now.unix()); // as end
                            let duration = moment.duration(end.diff(now));
                            let diff = duration.asMinutes() * -1;
                            let unit = 'min';
                            // parsing to hour
                            if (diff > 60) {
                                diff = diff / 60;
                                unit = 'hr';
                            }
                            return {
                                duration,
                                diff,
                                unit,
                            }
                        }

                        let speedOrIdle = '-';
                        let a = getDiff(mdata.lst_idle_at);
                        let diff = a.diff.toFixed(0);
                        let unit = a.unit;

                        if (mdata.stts_engine == State.stts_engine.moving) {
                            speedOrIdle = `${mdata.lst_speed} Kph`;
                            if (typeof mdata.lst_speed == 'undefined' || mdata.lst_speed == 0 || mdata.lst_speed == null) {
                                speedOrIdle = `> ${diff} ${unit}`;
                            }
                        } else if (mdata.stts_engine == State.stts_engine.idling) {
                            speedOrIdle = `> ${diff} ${unit}`;
                        } else if (mdata.stts_engine == State.stts_engine.stoping) {
                            a = getDiff(mdata.lst_stop_at);
                            diff = a.diff.toFixed(0);
                            unit = a.unit;
                            speedOrIdle = `> ${diff} ${unit}`;
                        }

                        let content = `<div class="bg-color"><b>${speedOrIdle}</b></div>`;
                        marker.setPopupContent(content);
                        marker.bindTooltip(content);
                        marker.openPopup();
                    } else if (State.statusFilterPopupVhcMarker === 3) {
                        let content =
                            `<div class="bg-color"><b>${Helper.shortenText(decodeURIComponent(mdata?.lst_fulladdress || 'address'), 100)}</b></div>`;
                        marker.setPopupContent(content);
                        marker.bindTooltip(content);
                        marker.openPopup();
                    }
                    Leaflet.map.setView(latLng);
                }

                if (State.statusFilterPopupVhcMarker === 3) {
                    State.statusFilterPopupVhcMarker = 1;
                } else {
                    State.statusFilterPopupVhcMarker += 1;
                }
            },
            handlerFilterVhcGps: function(markers) {
                if (State.inShowVid) {
                    Helper.toast('Warning', 'just now', 'Cannot filter when see detail vehicle');
                    return false;
                }
                // 0=>all,1=>active,2=>not
                if (State.statusFilterVhcGps === 2) {
                    State.statusFilterVhcGps = 0;
                } else {
                    State.statusFilterVhcGps += 1;
                }
                State.lastShowVids = [];

                function show(marker, mdata) {
                    marker.setOpacity(1);
                    $(`.vhc-item[data-vid="${mdata.vid}"]`).removeClass('d-none');
                    State.lastShowVids.push(mdata.vid);
                }

                function hide(marker, mdata) {
                    marker.setOpacity(0);
                    $(`.vhc-item[data-vid="${mdata.vid}"]`).addClass('d-none');
                }

                function validate(marker, mdata) {
                    if ((State.statusFilterVhcGsm === 1 || State.statusFilterVhcGsm === 2) && (State.statusFilterVhcZone === 1 || State.statusFilterVhcZone === 2)) {
                        if (Menu.isFilterVhc_Gsm(mdata) && Menu.isFilterVhc_Zone(mdata)) {
                            show(marker, mdata);
                        }
                    } else if (State.statusFilterVhcGsm === 1 || State.statusFilterVhcGsm === 2) {
                        if (Menu.isFilterVhc_Gsm(mdata)) {
                            show(marker, mdata);
                        }
                    } else if (State.statusFilterVhcZone === 1 || State.statusFilterVhcZone === 2) {
                        if (Menu.isFilterVhc_Zone(mdata)) {
                            show(marker, mdata);
                        }
                    } else {
                        show(marker, mdata);
                    }
                }
                let latLng = Leaflet.map.getCenter();
                let c_vhc_gps = 0;
                for (let marker of markers) {
                    let mdata = marker.options.mdata;
                    if (State.statusFilterVhcGps === 0) {
                        c_vhc_gps += 1;
                        validate(marker, mdata);
                        $($('#filterVhcGps > span')[0]).removeClass('text-danger text-success').addClass(
                            'text-muted');
                        $('#filterVhcGps').attr('data-bs-original-title', 'Filter vehicle GPS');
                        if (State.isShowToltipFilterVhcGps) $('#filterVhcGps').tooltip('show');
                    } else if (State.statusFilterVhcGps === 1) {
                        if (mdata.stts_gps == State.stts_gps.active) {
                            c_vhc_gps += 1;
                            validate(marker, mdata);
                        } else {
                            hide(marker, mdata);
                        }
                        $($('#filterVhcGps > span')[0]).removeClass('text-muted text-danger').addClass(
                            'text-success');
                        $('#filterVhcGps').attr('data-bs-original-title', 'Filter vehicle GPS Active');
                        if (State.isShowToltipFilterVhcGps) $('#filterVhcGps').tooltip('show');
                    } else if (State.statusFilterVhcGps === 2) {
                        if (mdata.stts_gps != State.stts_gps.active) {
                            c_vhc_gps += 1;
                            validate(marker, mdata);
                        } else {
                            hide(marker, mdata);
                        }
                        $($('#filterVhcGps > span')[0]).removeClass('text-success text-muted').addClass(
                            'text-danger');
                        $('#filterVhcGps').attr('data-bs-original-title', 'Filter vehicle GPS Inactive');
                        if (State.isShowToltipFilterVhcGps) $('#filterVhcGps').tooltip('show');
                    }
                    Leaflet.map.setView(latLng);
                }

                $('#c_vhc_gps').text(c_vhc_gps);
                State.lastStatusFilterVhcGps = State.statusFilterVhcGps;
            },
            handlerFilterVhcGsm: function(markers) {
                if (State.inShowVid) {
                    Helper.toast('Warning', 'just now', 'Cannot filter when see detail vehicle');
                    return false;
                }
                // 0=>all,1=>active,2=>not
                if (State.statusFilterVhcGsm === 2) {
                    State.statusFilterVhcGsm = 0;
                } else {
                    State.statusFilterVhcGsm += 1;
                }
                State.lastShowVids = [];

                function show(marker, mdata) {
                    marker.setOpacity(1);
                    $(`.vhc-item[data-vid="${mdata.vid}"]`).removeClass('d-none');
                    State.lastShowVids.push(mdata.vid);
                }

                function hide(marker, mdata) {
                    marker.setOpacity(0);
                    $(`.vhc-item[data-vid="${mdata.vid}"]`).addClass('d-none');
                }

                function validate(marker, mdata) {
                    if ((State.statusFilterVhcGps === 1 || State.statusFilterVhcGps === 2) && (State.statusFilterVhcZone === 1 || State.statusFilterVhcZone === 2)) {
                        if (Menu.isFilterVhc_Gps(mdata) && Menu.isFilterVhc_Zone(mdata)) {
                            show(marker, mdata);
                        }
                    } else if (State.statusFilterVhcGps === 1 || State.statusFilterVhcGps === 2) {
                        if (Menu.isFilterVhc_Gps(mdata)) {
                            show(marker, mdata);
                        }
                    } else if (State.statusFilterVhcZone === 1 || State.statusFilterVhcZone === 2) {
                        if (Menu.isFilterVhc_Zone(mdata)) {
                            show(marker, mdata);
                        }
                    } else {
                        show(marker, mdata);
                    }
                }
                let latLng = Leaflet.map.getCenter();
                let c_vhc_gsm = 0;
                for (let marker of markers) {
                    let mdata = marker.options.mdata;
                    if (State.statusFilterVhcGsm === 0) {
                        c_vhc_gsm += 1;
                        validate(marker, mdata);
                        $($('#filterVhcGsm > span')[0]).removeClass('text-danger text-success').addClass(
                            'text-muted');
                        $('#filterVhcGsm').attr('data-bs-original-title', 'Filter vehicle GSM');
                        if (State.isShowToltipFilterVhcGsm) $('#filterVhcGsm').tooltip('show');
                    } else if (State.statusFilterVhcGsm === 1) {
                        if (mdata.stts_gsm >= State.stts_gsm.bad_signal) {
                            if (mdata.lst_heartbeat > 0) {
                                c_vhc_gsm += 1;
                                validate(marker, mdata);
                            } else {
                                hide(marker, mdata);
                            }
                        } else {
                            hide(marker, mdata);
                        }
                        $($('#filterVhcGsm > span')[0]).removeClass('text-muted text-danger').addClass(
                            'text-success');
                        $('#filterVhcGsm').attr('data-bs-original-title', 'Filter vehicle GSM Active');
                        if (State.isShowToltipFilterVhcGsm) $('#filterVhcGsm').tooltip('show');
                    } else if (State.statusFilterVhcGsm === 2) {
                        if (mdata.stts_gsm <= State.stts_gsm.no_signal) {
                            c_vhc_gsm += 1;
                            validate(marker, mdata);
                        } else {
                            if (mdata.lst_heartbeat < 1) {
                                c_vhc_gsm += 1;
                                validate(marker, mdata);
                            } else {
                                hide(marker, mdata);
                            }
                        }
                        $($('#filterVhcGsm > span')[0]).removeClass('text-success text-muted').addClass(
                            'text-danger');
                        $('#filterVhcGsm').attr('data-bs-original-title', 'Filter vehicle GSM No Signal');
                        if (State.isShowToltipFilterVhcGsm) $('#filterVhcGsm').tooltip('show');
                    }
                    Leaflet.map.setView(latLng);
                }

                $('#c_vhc_gsm').text(c_vhc_gsm);
                State.lastStatusFilterVhcGsm = State.statusFilterVhcGsm;
            },
            handlerFilterVhcZone: function(markers) {
                if (State.inShowVid) {
                    Helper.toast('Warning', 'just now', 'Cannot filter when see detail vehicle');
                    return false;
                }
                // 0=>all,1=>inside,2=>outside
                if (State.statusFilterVhcZone === 2) {
                    State.statusFilterVhcZone = 0;
                } else {
                    State.statusFilterVhcZone += 1;
                }
                State.lastShowVids = [];

                function show(marker, mdata) {
                    marker.setOpacity(1);
                    $(`.vhc-item[data-vid="${mdata.vid}"]`).removeClass('d-none');
                    State.lastShowVids.push(mdata.vid);
                }

                function hide(marker, mdata) {
                    marker.setOpacity(0);
                    $(`.vhc-item[data-vid="${mdata.vid}"]`).addClass('d-none');
                }

                function validate(marker, mdata) {
                    if ((State.statusFilterVhcGps === 1 || State.statusFilterVhcGps === 2) && (State.statusFilterVhcGsm === 1 || State.statusFilterVhcGsm === 2)) {
                        if (Menu.isFilterVhc_Gps(mdata) && Menu.isFilterVhc_Gsm(mdata)) {
                            show(marker, mdata);
                        }
                    } else if (State.statusFilterVhcGps === 1 || State.statusFilterVhcGps === 2) {
                        if (Menu.isFilterVhc_Gps(mdata)) {
                            show(marker, mdata);
                        }
                    } else if (State.statusFilterVhcGsm === 1 || State.statusFilterVhcGsm === 2) {
                        if (Menu.isFilterVhc_Gsm(mdata)) {
                            show(marker, mdata);
                        }
                    } else {
                        show(marker, mdata);
                    }
                }
                let latLng = Leaflet.map.getCenter();
                let c_vhc_zone = 0;
                for (let marker of markers) {
                    let mdata = marker.options.mdata;
                    if (State.statusFilterVhcZone === 0) {
                        c_vhc_zone += 1;
                        validate(marker, mdata);
                        $($('#filterVhcZone > span')[0]).removeClass('text-danger text-success').addClass(
                            'text-muted');
                        $('#filterVhcZone').attr('data-bs-original-title', 'Filter vehicle inside & outside zone');
                        if (State.isShowToltipFilterVhcZone) $('#filterVhcZone').tooltip('show');
                    } else if (State.statusFilterVhcZone === 1) {
                        if (mdata.inside_zones != null) {
                            c_vhc_zone += 1;
                            validate(marker, mdata);
                        } else {
                            hide(marker, mdata);
                        }
                        $($('#filterVhcZone > span')[0]).removeClass('text-muted text-danger').addClass(
                            'text-success');
                        $('#filterVhcZone').attr('data-bs-original-title', 'Filter vehicle inside zone');
                        if (State.isShowToltipFilterVhcZone) $('#filterVhcZone').tooltip('show');
                    } else if (State.statusFilterVhcZone === 2) {
                        if (mdata.inside_zones == null) {
                            c_vhc_zone += 1;
                            validate(marker, mdata);
                        } else {
                            hide(marker, mdata);
                        }
                        $($('#filterVhcZone > span')[0]).removeClass('text-success text-muted').addClass(
                            'text-danger');
                        $('#filterVhcZone').attr('data-bs-original-title', 'Filter vehicle outside zone');
                        if (State.isShowToltipFilterVhcZone) $('#filterVhcZone').tooltip('show');
                    }
                    Leaflet.map.setView(latLng);
                }

                $('#c_vhc_zone').text(c_vhc_zone);
                State.lastStatusFilterVhcZone = State.statusFilterVhcZone;
            },
            handlerFilterVhcSearch: function(search) {
                let vhcItems = $('#listTrucks').find('.vhc-item');
                for (let item of vhcItems) {
                    let vid = $(item).data('vid');
                    let textNopol = $($(item).find('.textNopol')[0]).text();
                    let textAddr = $($(item).find('.textAddr')[0]).text();

                    if (textNopol.toLowerCase().indexOf(search.toLowerCase()) > -1) {
                        $(item).removeClass('d-none');
                    } else if (textAddr.toLowerCase().indexOf(search.toLowerCase()) > -1) {
                        $(item).removeClass('d-none');
                    } else {
                        $(item).addClass('d-none');
                    }
                }
            },
            handlerFilterZoneSearch: function(search) {
                let zoneItems = $('#listZone').find('.zone-item');
                for (let item of zoneItems) {
                    let zid = $(item).data('zid');
                    let textZoneName = $($(item).find('.textZoneName')[0]).text();
                    let textZoneType = $($(item).find('.textZoneType')[0]).text();

                    if (textZoneName.toLowerCase().indexOf(search.toLowerCase()) > -1) {
                        $(item).removeClass('d-none');
                    } else if (textZoneType.toLowerCase().indexOf(search.toLowerCase()) > -1) {
                        $(item).removeClass('d-none');
                    } else {
                        $(item).addClass('d-none');
                    }
                }
            },
            isFilterVhc_GpsGsmZone: function(truck) {
                // if return false no filter, true there filter
                if (Menu.isFilterVhc_Gps(truck)) return true;
                if (Menu.isFilterVhc_Gsm(truck)) return true;
                if (Menu.isFilterVhc_Zone(truck)) return true;
                return false;
            },
            isFilterVhc_Gps: function(truck) {
                // if return false no filter, true there filter
                if (State.statusFilterVhcGps === 0) {} else if (State.statusFilterVhcGps === 1) {
                    if (truck.stts_gps == State.stts_gps.active) return true;
                } else if (State.statusFilterVhcGps === 2) {
                    if (truck.stts_gps != State.stts_gps.active) return true;
                }
                return false;
            },
            isFilterVhc_Gsm: function(truck) {
                // if return false no filter, true there filter
                if (State.statusFilterVhcGsm === 0) {} else if (State.statusFilterVhcGsm === 1) {
                    if (truck.stts_gsm >= State.stts_gsm.bad_signal) return true;
                } else if (State.statusFilterVhcGsm === 2) {
                    if (truck.stts_gsm <= State.stts_gsm.no_signal) return true;
                }
                return false;
            },
            isFilterVhc_Zone: function(truck) {
                // if return false no filter, true there filter
                if (State.statusFilterVhcZone === 0) {} else if (State.statusFilterVhcZone === 1) {
                    if (truck.inside_zones != null) return true;
                } else if (State.statusFilterVhcZone === 2) {
                    if (truck.inside_zones == null) return true;
                }
                return false;
            },
            isLastFilterVhc_Gps: function(truck) {
                // if return false no filter, true there filter
                if (State.lastStatusFilterVhcGps === 0) {} else if (State.lastStatusFilterVhcGps === 1) {
                    if (truck.stts_gps == State.stts_gps.active) return true;
                } else if (State.lastStatusFilterVhcGps === 2) {
                    if (truck.stts_gps != State.stts_gps.active) return true;
                }
                return false;
            },
            isLastFilterVhc_Gsm: function(truck) {
                // if return false no filter, true there filter
                if (State.lastStatusFilterVhcGsm === 0) {} else if (State.lastStatusFilterVhcGsm === 1) {
                    if (truck.stts_gsm >= State.stts_gsm.bad_signal) return true;
                } else if (State.lastStatusFilterVhcGsm === 2) {
                    if (truck.stts_gsm <= State.stts_gsm.no_signal) return true;
                }
                return false;
            },
            isLastFilterVhc_Zone: function(truck) {
                // if return false no filter, true there filter
                if (State.lastStatusFilterVhcZone === 0) {} else if (State.lastStatusFilterVhcZone === 1) {
                    if (truck.inside_zones != null) return true;
                } else if (State.lastStatusFilterVhcZone === 2) {
                    if (truck.inside_zones == null) return true;
                }
                return false;
            },
        }

        const Trucks = {
            lists: null,
            last_move: null,
            activate: function() {
                Trucks.bundleGetListTrucks(false);
                Trucks.event();
            },
            event: function() {
                setInterval(async () => {
                    if (State.inShowLastMove) return false;
                    await Trucks.bundleGetListTrucks(false);
                    if (State.inShowVid) {
                        setTimeout(() => {
                            Leaflet.hideLayer('eventHideTruckNotSelected');
                        }, State.delay_hideTruckNotSelected);
                    }
                    State.loadedLastMoveVid = null;
                    if ($('#selectFiter').val() == State.stts_filterDetail.vehicles) {
                        setTimeout(() => {
                            if (Trucks.lists) {
                                for (let i = 0; i < Trucks.lists.length; i++) {
                                    if (Trucks.lists[i].vid == State.inShowVid) {
                                        Trucks.showDetailGeneral(Trucks.lists[i]);
                                    }
                                }
                            }
                        }, 1000);
                    }
                }, State.delay_auto_refresh);
            },
            bundleGetListTrucks: async function(cache = false) {
                Leaflet.clearLayer('eventRemoveListTrucks');
                Trucks.lists = await Trucks.getListTrucks(cache);
                Trucks.showToLists(Trucks.lists);
                Trucks.showListsToMap(Trucks.lists);
            },
            getListTrucks: async function(cache = false) {
                if (cache) {
                    if (Trucks.lists == null) {
                        return (await Trucks.reqListTrucks()).data;
                    } else {
                        return Trucks.lists;
                    }
                }
                return (await Trucks.reqListTrucks()).data;
            },
            reqListTrucks: function(params) {
                return new Promise((resolve, reject) => {
                    let url = "{{ route('api_list_currect_track_vhc') }}?cptid=" + AppState.current_company;
                    if (State.ord_code) {
                        url += "&ord_code=" + State.ord_code;
                    }
                    $.ajax({
                        url,
                        method: 'GET',
                        crossDomain: true,
                        processData: true,
                        headers: {
                            'x-api-key': Helper.getCookie('_trtk'),
                        },
                        data: params,
                        success: (data, textStatus, jqXHR) => {
                            if (data.meta.type != 'success') {
                                resolve({
                                    type: 'fail',
                                    data: null,
                                });
                                Helper.toast('Warning', 'just now', data.meta.message);
                                return false;
                            }
                            resolve({
                                type: 'success',
                                data: data.data,
                            });
                        },
                        error: (jqXHR, textStatus, error) => {
                            if (jqXHR.status >= 500) {
                                Helper.toast('Error', 'just now', 'Cannot get lists vehicles');
                            } else {
                                Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
                                    .message);
                            }
                            resolve({
                                type: 'error',
                                data: null,
                            });
                        }
                    })
                });
            },
            showToLists: function(trucks) {
                $('#listTrucks').html('');
                let str = '',
                    refilter = '';
                let c_vhc_gps = 0,
                    c_vhc_gsm = 0,
                    c_vhc_zone = 0;
                State.statusFilterVhcGps = (State.lastStatusFilterVhcGps) ? State.lastStatusFilterVhcGps : State.statusFilterVhcGps;
                State.statusFilterVhcGsm = (State.lastStatusFilterVhcGsm) ? State.lastStatusFilterVhcGsm : State.statusFilterVhcGsm;
                State.statusFilterVhcZone = (State.lastStatusFilterVhcZone) ? State.lastStatusFilterVhcZone : State.statusFilterVhcZone;
                for (let i = 0; i < trucks.length; i++) {
                    // refilter list trucks
                    refilter = 'd-none';
                    if (State.lastStatusFilterVhcGps !== 0 || State.lastStatusFilterVhcGsm !== 0 || State.lastStatusFilterVhcZone !== 0) {
                        c_vhc_gps = Number($('#c_vhc_gps').text());
                        c_vhc_gsm = Number($('#c_vhc_gsm').text());
                        c_vhc_zone = Number($('#c_vhc_zone').text());
                        if (State.lastStatusFilterVhcGps !== 0) {
                            if ((State.lastStatusFilterVhcGsm === 1 || State.lastStatusFilterVhcGsm === 2) && (State.lastStatusFilterVhcZone === 1 || State.lastStatusFilterVhcZone === 2)) {
                                if (Menu.isLastFilterVhc_Gps(trucks[i]) && Menu.isLastFilterVhc_Gsm(trucks[i]) && Menu.isLastFilterVhc_Zone(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gps += 1;
                                    // c_vhc_gsm += 1;
                                    // c_vhc_zone += 1;
                                }
                            } else if (State.lastStatusFilterVhcGsm === 1 || State.lastStatusFilterVhcGsm === 2) {
                                if (Menu.isLastFilterVhc_Gps(trucks[i]) && Menu.isLastFilterVhc_Gsm(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gps += 1;
                                    // c_vhc_gsm += 1;
                                }
                            } else if (State.lastStatusFilterVhcZone === 1 || State.lastStatusFilterVhcZone === 2) {
                                if (Menu.isLastFilterVhc_Gps(trucks[i]) && Menu.isLastFilterVhc_Zone(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gps += 1;
                                    // c_vhc_zone += 1;
                                }
                            } else {
                                if (Menu.isLastFilterVhc_Gps(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gps += 1;
                                    // c_vhc_gsm += 1;
                                    // c_vhc_zone += 1;
                                } else {
                                    // c_vhc_gsm += 1;
                                    // c_vhc_zone += 1;
                                }
                            }
                        } else if (State.lastStatusFilterVhcGsm !== 0) {
                            if ((State.lastStatusFilterVhcGps === 1 || State.lastStatusFilterVhcGps === 2) && (State.lastStatusFilterVhcZone === 1 || State.lastStatusFilterVhcZone === 2)) {
                                if (Menu.isLastFilterVhc_Gsm(trucks[i]) && Menu.isLastFilterVhc_Gps(trucks[i]) && Menu.isLastFilterVhc_Zone(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gsm += 1;
                                    // c_vhc_gps += 1;
                                    // c_vhc_zone += 1;
                                }
                            } else if (State.lastStatusFilterVhcGps === 1 || State.lastStatusFilterVhcGps === 2) {
                                if (Menu.isLastFilterVhc_Gsm(trucks[i]) && Menu.isLastFilterVhc_Gps(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gsm += 1;
                                    // c_vhc_gps += 1;
                                }
                            } else if (State.lastStatusFilterVhcZone === 1 || State.lastStatusFilterVhcZone === 2) {
                                if (Menu.isLastFilterVhc_Gsm(trucks[i]) && Menu.isLastFilterVhc_Zone(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gsm += 1;
                                    // c_vhc_zone += 1;
                                }
                            } else {
                                if (Menu.isLastFilterVhc_Gsm(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_gsm += 1;
                                    // c_vhc_gps += 1;
                                    // c_vhc_zone += 1;
                                } else {
                                    // c_vhc_gps += 1;
                                    // c_vhc_zone += 1;
                                }
                            }
                        } else if (State.lastStatusFilterVhcZone !== 0) {
                            if ((State.lastStatusFilterVhcGps === 1 || State.lastStatusFilterVhcGps === 2) && (State.lastStatusFilterVhcGsm === 1 || State.lastStatusFilterVhcGsm === 2)) {
                                if (Menu.isLastFilterVhc_Zone(trucks[i]) && Menu.isLastFilterVhc_Gps(trucks[i]) && Menu.isLastFilterVhc_Gsm(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_zone += 1;
                                    // c_vhc_gps += 1;
                                    // c_vhc_gsm += 1;
                                }
                            } else if (State.lastStatusFilterVhcGps === 1 || State.lastStatusFilterVhcGps === 2) {
                                if (Menu.isLastFilterVhc_Zone(trucks[i]) && Menu.isLastFilterVhc_Gps(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_zone += 1;
                                    // c_vhc_gps += 1;
                                }
                            } else if (State.lastStatusFilterVhcGsm === 1 || State.lastStatusFilterVhcGsm === 2) {
                                if (Menu.isLastFilterVhc_Zone(trucks[i]) && Menu.isLastFilterVhc_Gsm(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_zone += 1;
                                    // c_vhc_gsm += 1;
                                }
                            } else {
                                if (Menu.isLastFilterVhc_Zone(trucks[i])) {
                                    refilter = '';
                                    // c_vhc_zone += 1;
                                    // c_vhc_gps += 1;
                                    // c_vhc_gsm += 1;
                                } else {
                                    // c_vhc_gps += 1;
                                    // c_vhc_gsm += 1;
                                }
                            }
                        }
                    } else {
                        // without filter
                        refilter = '';
                        c_vhc_gps += 1;
                        c_vhc_gsm += 1;
                        c_vhc_zone += 1;
                        State.lastShowVids.push(trucks[i].vid);
                    }

                    // list trucks
                    // <img src="${State.storage_lara}${trucks[i].fvhc_img}" class="img-fluid" alt="">
                    // <img src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png" class="img-fluid" alt="">
                    // <p class="text-muted mb-0"> ${(trucks[i]?.lst_city_text || trucks[i]?.lst_state_text || 'address')} - ${(trucks[i]?.lst_postcode || 'postcode')}</p>
                    str += `
                    <li class="list-group-item vehicles-list-wrapper p-1 px-2 vhc-item ${refilter}" data-vid="${trucks[i].vid}">
                        <a href="#" class="text-dark">
                            <div class="row d-flex align-items-center">
                                <div class="col-4">
                                    <img src="${State.storage_lara}${trucks[i].fvhc_img}" class="img-fluid thumb-img-small" alt="">
                                </div>
                                <div class="col ps-0">
                                    <p class="text-bold mb-0 textNopol">${trucks[i].nopol1} ${trucks[i].nopol2} ${trucks[i].nopol3}</p>
                                    <p class="text-muted mb-0 textAddr">${Helper.shortenText(decodeURIComponent(trucks[i]?.lst_fulladdress || 'address'), 25)}</p>
                                </div>
                            </div>
                        </a>
                    </li>
                    `;
                }
                $('#c_vhc_zone').text(c_vhc_zone);
                $('#c_vhc_gsm').text(c_vhc_gsm);
                $('#c_vhc_gps').text(c_vhc_gps);
                $('#listTrucks').html(str);
            },
            showListsToMap: function(trucks) {
                // let locations = trucks.map((tr) => {
                //     let at = moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')
                //     return {
                //         lat: tr.lst_lat,
                //         lng: tr.lst_lng,
                //         label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${at}<br>${tr.lst_lat},${tr.lst_lng}`,
                //         options: {
                //             mdata: tr,
                //         },
                //     };
                // });
                let locations = [];
                for (let i = 0; i < trucks.length; i++) {
                    if (trucks[i]?.lst_lat == null || trucks[i]?.lst_lng == null) {
                        continue;
                    }
                    let icon_stts_engine = Icon.vechicleIcon(); // moving
                    if (trucks[i].stts_engine == State.stts_engine.moving) {
                        icon_stts_engine = Icon.vechicleIcon();
                        if (trucks[i].lst_speed == 0 || trucks[i].lst_speed == null) {
                            icon_stts_engine = Icon.vhcIdleIcon();
                        }
                    } else if (trucks[i].stts_engine == State.stts_engine.idling) {
                        icon_stts_engine = Icon.vhcIdleIcon();
                    } else if (trucks[i].stts_engine == State.stts_engine.stoping) {
                        icon_stts_engine = Icon.vhcStopIcon();
                    }
                    // no updated data more than 1 day
                    if (trucks[i]?.lst_loc_crt < moment().subtract(24, 'hour').unix()) {
                        icon_stts_engine = Icon.vhcStopIcon();
                    }
                    let templateLabel = `<b>${trucks[i].nopol1} ${trucks[i].nopol2} ${trucks[i].nopol3}</b>`;
                    if (trucks[i]?.ord_pck_ktname && trucks[i]?.ord_drop_ktname) {
                        templateLabel += `<div style="margin-bottom:0;"><strong>${trucks[i]?.ord_c_pt_name}</strong></div>`;
                        templateLabel += `<div style="margin-bottom:0;">Dari</div>`;
                        templateLabel += `<div style="margin-bottom:0.25rem;"><strong>${trucks[i]?.ord_pck_ktname}</strong></div>`;
                        templateLabel += `<div style="margin-bottom:0;">Ke</div>`;
                        templateLabel += `<div style="margin-bottom:0;"><strong>${trucks[i]?.ord_drop_ktname}</strong></div>`;
                    }
                    locations.push({
                        lat: trucks[i].lst_lat,
                        lng: trucks[i].lst_lng,
                        // label: `<b>${trucks[i].nopol1} ${trucks[i].nopol2} ${trucks[i].nopol3}</b><br>${moment.unix(trucks[i]?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof trucks[i].lst_speed != 'undefined') ? trucks[i].lst_speed : '0'}<br>${Number(trucks[i].lst_lat).toFixed(5)},${Number(trucks[i].lst_lng).toFixed(6)}<br>${Helper.shortenText(decodeURIComponent(trucks[i]?.lst_fulladdress || 'address'), 25)}`,
                        label: templateLabel,
                        options: {
                            mdata: trucks[i],
                            icon: icon_stts_engine,
                            // autoClose: false,
                        },
                    });
                }

                let markers = Leaflet.addMarkers(locations, function(marker) {
                    Leaflet.eventMarkerClick(marker, function(e) {
                        let tr = e.target.options.mdata;
                        $('#selectFiter').val(1).trigger('change');
                        $('#selectFiter').val(1).trigger('select2:select');
                        Trucks.showDetailGeneral(tr);
                        $('#rightSideBar2').removeClass('d-none');
                    });
                });

                for (let m of markers) {
                    if (!State.lastShowVids.includes(m.options.mdata.vid)) {
                        m.setOpacity(0);
                    }
                }

                // filter popup
                State.eventFilterPopupVhcMarker = new CustomEvent('eventFilterPopupVhcMarker', {
                    detail: {
                        markers,
                    },
                });

                function handlerFilterPopupVhcMarker(e) {
                    Menu.handlerFilterPopupVhcMarker(e.detail.markers);
                }
                window.addEventListener('eventFilterPopupVhcMarker', handlerFilterPopupVhcMarker);

                // filter vehicle gps
                State.eventFilterVhcGps = new CustomEvent('eventFilterVhcGps', {
                    detail: {
                        markers,
                    },
                });

                function handlerFilterVhcGps(e) {
                    Menu.handlerFilterVhcGps(e.detail.markers);
                }
                window.addEventListener('eventFilterVhcGps', handlerFilterVhcGps);

                // filter vehicle gsm
                State.eventFilterVhcGsm = new CustomEvent('eventFilterVhcGsm', {
                    detail: {
                        markers,
                    },
                });

                function handlerFilterVhcGsm(e) {
                    Menu.handlerFilterVhcGsm(e.detail.markers);
                }
                window.addEventListener('eventFilterVhcGsm', handlerFilterVhcGsm);

                // filter vehicle zone
                State.eventFilterVhcZone = new CustomEvent('eventFilterVhcZone', {
                    detail: {
                        markers,
                    },
                });

                function handlerFilterVhcZone(e) {
                    Menu.handlerFilterVhcZone(e.detail.markers);
                }
                window.addEventListener('eventFilterVhcZone', handlerFilterVhcZone);

                // hide all truck
                State.eventHideAllTruck = new CustomEvent('eventHideAllTruck', {
                    detail: {
                        markers,
                    },
                });

                function handlerHideAllTruck(e) {
                    for (let marker of e.detail.markers) {
                        marker.setOpacity(0);
                    }
                }
                window.addEventListener('eventHideAllTruck', handlerHideAllTruck);

                // hide truck not selected
                State.eventHideTruckNotSelected = new CustomEvent('eventHideTruckNotSelected', {
                    detail: {
                        markers,
                    },
                });

                function handlerHideTruckNotSelected(e) {
                    for (let marker of e.detail.markers) {
                        if (State.inShowVid == marker.options.mdata.vid) {
                            marker.setOpacity(1);
                            continue;
                        }
                        marker.setOpacity(0);
                    }
                }
                window.addEventListener('eventHideTruckNotSelected', handlerHideTruckNotSelected);

                // remove marker, circle, event listener and all about this marker
                State.eventRemoveListTrucks = new CustomEvent('eventRemoveListTrucks', {
                    detail: {
                        markers,
                    },
                });
                window.addEventListener('eventRemoveListTrucks', function handler(e) {
                    for (let marker of e.detail.markers) {
                        marker.removeEventListener('click');
                        marker.removeEventListener('moveend');
                        marker.remove();
                    }
                    e.currentTarget.removeEventListener(e.type,
                        handler); // window.removeEventListener('remove', this.handler, true);
                    window.removeEventListener('eventFilterPopupVhcMarker', handlerFilterPopupVhcMarker);
                    window.removeEventListener('eventFilterVhcGps', handlerFilterVhcGps);
                    window.removeEventListener('eventFilterVhcGsm', handlerFilterVhcGsm);
                    window.removeEventListener('eventFilterVhcZone', handlerFilterVhcZone);
                    window.removeEventListener('eventHideTruckNotSelected', handlerHideTruckNotSelected);
                    window.removeEventListener('eventHideAllTruck', handlerHideAllTruck);
                    State.eventRemoveListTrucks = null;
                    State.statusFilterPopupVhcMarker = 1;
                    State.eventFilterPopupVhcMarker = null;
                    State.statusFilterVhcGps = 0;
                    State.eventFilterVhcGps = null;
                    State.statusFilterVhcGsm = 0;
                    State.eventFilterVhcGsm = null;
                    State.statusFilterVhcZone = 0;
                    State.eventFilterVhcZone = null;
                    State.eventHideTruckNotSelected = null;
                    State.eventHideAllTruck = null;
                });
            },
            showDetailGeneral: function(truck) {
                State.inShowVid = truck.vid;
                // title
                // <img src="https://products.unitedtractors.com/wp-content/uploads/2021/03/udtruck-GWE370.png" class="img-fluid" alt="">
                // $('#infoVehicles-thumb-md').attr('src',`${State.storage_lara}${truck?.fvhc_img}`);
                $('#infoVehicles-thumb-md').attr('src',
                    `${State.storage_lara}${truck?.fvhc_img}`);
                // $('#infoVehicles-thumb-sm').attr('src',`${State.storage_lara}${truck?.fvhc_img}`);
                $('#infoVehicles-thumb-sm').attr('src',
                    `${State.storage_lara}${truck?.fvhc_img}`);
                $('#infoVehicles-platno').text(`${truck?.nopol1} ${truck?.nopol2} ${truck?.nopol3}`);
                // vehicles
                $('#infoVehicles-crt').text(moment.unix(truck?.lst_loc_crt).format('DD MMM YYYY HH:mm'));
                // $('#infoVehicles-crt').text(moment.unix(truck?.lst_loc_crt_s).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss'));
                // ${(truck?.city_text || truck?.state_text || 'address')} - ${(truck?.postcode || 'postcode')}
                if (truck?.ignition == State.stts_ignition.high) {
                    $('#infoVehicles-ignition').text('ON');
                } else {
                    $('#infoVehicles-ignition').text('OFF');
                }

                if (truck?.stts_engine == State.stts_engine.moving) {
                    $('#infoVehicles-engineStatus').text('MOVING');
                    if (truck?.lst_speed == 0 || truck?.lst_speed == null) {
                        $('#infoVehicles-engineStatus').text('IDLING');
                    }
                } else if (truck?.stts_engine == State.stts_engine.idling) {
                    $('#infoVehicles-engineStatus').text('IDLING');
                } else if (truck?.stts_engine == State.stts_engine.stoping) {
                    $('#infoVehicles-engineStatus').text('STOPPED');
                }

                // no updated data more than 1 day
                if (truck?.lst_loc_crt < moment().subtract(24, 'hour').unix()) {
                    $('#infoVehicles-ignition').text('OFF');
                    $('#infoVehicles-engineStatus').text('STOPPED');
                }
                $('#infoVehicles-addr-title').text(
                    `${Helper.shortenText(decodeURIComponent(truck?.lst_fulladdress || 'address'), 25)}`);
                $('#infoVehicles-addr').text(
                    `${Helper.shortenText(decodeURIComponent(truck?.lst_fulladdress || 'address'), 25)}`);
                $('#infoVehicles-lat_lng').text(Number(truck?.lst_lat).toFixed(5) + ', ' + Number(truck?.lst_lng).toFixed(6));
                $('#infoVehicles-mileage').text(Number(truck?.vhc_sum_milleage_1).toFixed(0));
                $('#infoVehicles-speedLimit').text(truck?.speed_limit);
                $('#infoVehicles-currentSpeed').text(truck?.lst_speed);
                let idlingDur = Wrapper.calcIdlingDur(truck?.lst_idle_at, truck?.lst_speed);
                $('#infoVehicles-idlingDuration').text(idlingDur.dur);
                $('#infoVehicles-idlingUnit').text(idlingDur.unit);
                $('#infoVehicles-alertZones').text('-');
                $('#infoVehicles-isTrackHoliday').text(truck?.is_track_holiday_text);
                $('#infoVehicles-trackSch').text(truck?.track_schedule);
                $('#infoVehicles-company').text(truck?.client_group_name);
                $('#infoVehicles-serviceStart').text(moment.unix(truck?.vhc_crt).format('DD MMM YYYY HH:mm:ss'));
                // driver
                $('#infoDrv-updt').text((truck?.ord_crt) ? moment.unix(truck?.ord_crt).format('DD MMM YYYY HH:mm:ss') : '-');
                $('#infoDrv-name').text(truck?.ord_drv_name ?? 'Off Duty');
                $('.infoDrv-phone1-text').text((truck?.ord_drv_phone_val) ? Helper.splitEvery4Char('0' + truck?.ord_drv_phone_val) : '-');
                $('#infoDrv-phone1-tel').attr('tel:0' + (truck?.ord_drv_phone_val ?? ''));
                $('#infoDrv-phone1-wa').attr('https://api.whatsapp.com/send/?phone=62' + (truck?.ord_drv_phone_val ?? '') + '&text=Halo&app_absent=0');
                $('.infoDrv-phone2-text').text((truck?.ord_drv_phone2_val) ? Helper.splitEvery4Char('0' + truck?.ord_drv_phone2_val) : '-');
                $('#infoDrv-phone2-tel').attr('tel:0' + (truck?.ord_drv_phone2_val ?? ''));
                $('#infoDrv-phone2-wa').attr('https://api.whatsapp.com/send/?phone=62' + (truck?.ord_drv_phone2_val ?? '') + '&text=Halo&app_absent=0');

                // job
                // $('#infoJob').html('');
                // for (let i = 0; i < 20; i++) {
                //     $('#infoJob').append(`
            //         <li class="list-group-item p-1 px-2">
            //             <p class="text-bold mb-0">#902192${truck.vid}${Math.floor(Math.random()*90000) + 10000}</p>
            //             <div class="row d-flex align-items-center justify-content-between">
            //                 <div class="col-auto">
            //                     <small class="text-muted">Client name</small>
            //                     <p id="" class="mb-0">JNE</p>
            //                 </div>
            //                 <div class="col-auto">
                                // <small class="text-muted">Destination</small>
            //                     <p id="" class="mb-0">JKT-01</p></div>
            //             </div>
            //         </li>
            //     `);
                // }
                $('#infoJob-ord_client_name').text(truck?.ord_c_pt_name ?? '-');
                $('#infoJob-pck_city').text(truck?.ord_pck_ktname ?? '-')
                $('#infoJob-pck_name').text(truck?.ord_pck_name ?? '-');
                $('#infoJob-pck_addr').text(truck?.ord_pck_addr ?? '-');
                $('#infoJob-drop_city').text(truck?.ord_drop_ktname ?? '-')
                $('#infoJob-drop_name').text(truck?.ord_drop_name ?? '-');
                $('#infoJob-drop_addr').text(truck?.ord_drop_addr ?? '-');
                let txtOrdStts = 'Not in order';
                if (State.stts_order.wait == truck?.ord_stts) {
                    txtOrdStts = 'Waiting for Confirmation';
                } else if (State.stts_order.confirm == truck?.ord_stts) {
                    txtOrdStts = 'Searching for Vehicle';
                } else if (State.stts_order.have_get_vhc == truck?.ord_stts) {
                    txtOrdStts = 'Vehicle Heading to Pickup Location';
                } else if (State.stts_order.pck == truck?.ord_stts) {
                    txtOrdStts = 'Order Successfully Picked Up';
                } else if (State.stts_order.go == truck?.ord_stts) {
                    txtOrdStts = 'Heading to Delivery Location';
                } else if (State.stts_order.arv == truck?.ord_stts) {
                    txtOrdStts = 'Arrived at Delivery Location';
                } else if (State.stts_order.drop == truck?.ord_stts) {
                    txtOrdStts = 'Delivery Completed';
                } else if (State.stts_order.client_pay == truck?.ord_stts) {
                    // txtOrdStts = 'Invoicing to Client';
                    txtOrdStts = 'Completed (Waiting for Payment)';
                } else if (State.stts_order.vendor_payed == truck?.ord_stts) {
                    // txtOrdStts = 'Payment to Vendor';
                    txtOrdStts = 'Completed (Awaiting Vendor Payment)';
                } else if (State.stts_order.close == truck?.ord_stts) {
                    txtOrdStts = 'Completed';
                } else if (State.stts_order.cancel == truck?.ord_stts) {
                    txtOrdStts = 'Cancelled';
                }

                $('#infoJob-ord_stts').text(txtOrdStts);

                // last movement
                // $('#infoVehicles-infoMove').text('Last 24H from ' + moment.unix(truck?.lst_loc_crt).format('DD MMM YYYY HH:mm'));
            },
            bundleShowRouteTruck: async function(cache = false) {
                Menu.clearListMovements();
                if (State.inShowVid != State.loadedLastMoveVid) $('#historyStartDate').trigger('clearFilterHistoryDate');

				const getLastMove = await Trucks.getLastMove(State.inShowVid, cache);
				Trucks.last_move = getLastMove.flat()
				
                if (Trucks.last_move.length < 1) {
                    Helper.toast('Data Not Found', 'just now', 'There are no last data', 'bg-warning');
                    Trucks.last_move = null;
                    return false;
                }
                Trucks.showLastMoveToView(getLastMove);
            },
            getLastMove: async function(vid, cache = false) {
                State.loadedLastMoveVid = vid;
                State.inShowLastMove = vid;
                if (cache) {
                    if (Trucks.last_move == null) {
                        return (await Trucks.reqLastMove({
                            vid
                        })).data;
                    } else {
                        return Trucks.last_move;
                    }
                }
                return (await Trucks.reqLastMove({
                    vid
                })).data;
            },
            reqLastMove: function(params) {
                return new Promise((resolve, reject) => {
                    $.ajax({
                        url: "{{ route('api_last_move_track_vhc') }}?start_date=" + `${State.historyStartDate}&end_date=${State.historyEndDate}`,
                        method: 'GET',
                        crossDomain: true,
                        processData: true,
                        headers: {
                            'x-api-key': Helper.getCookie('_trtk'),
                        },
                        data: params,
                        success: (data, textStatus, jqXHR) => {
                            if (data.meta.type != 'success') {
                                resolve({
                                    type: 'fail',
                                    data: null,
                                });
                                Helper.toast('Warning', 'just now', data.meta.message);
                                return false;
                            }
                            resolve({
                                type: 'success',
                                data: data.data,
                            });
                        },
                        error: (jqXHR, textStatus, error) => {
                            if (jqXHR.status >= 500) {
                                Helper.toast('Error', 'just now', 'Cannot get lists trucks');
                            } else {
                                Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
                                    .message);
                            }
                            resolve({
                                type: 'error',
                                data: null,
                            });
                        }
                    })
                });
            },
            showLastMoveToView: function(truckRoutes) {
                // Leaflet.clearLayer('eventAboutTruck');
                Leaflet.hideLayer('eventHideAllTruck');
                // Trucks.routeStartEnd(truckRoutes);
                Trucks.routeStartEndGroupTrip(truckRoutes);
            },
            // routeStartEnd: function(truckRoutes) {
				//     let key_length = truckRoutes.length;
				//     let polyTruckRoutes = truckRoutes.map((obj, key) => {
						
				//         obj.key_index = key + 1 // key_length - key;
				//         // lists per detail info movement
				//         Menu.showToListMovement(obj);
				//         return {
				//             lat: obj.latitude,
				//             lng: obj.longitude,
				//             options: {
				//                 // polyline
				//                 smoothFactor: 1.0,
				//                 noClip: true,
				//                 bubblingMouseEvents: false,
				//                 // circle
				//                 radius: 5,
				// 				// markerOpacity: 0
				//             },
				//             // circle
				//             // label: `<b>${obj.key_index}</b><br>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}<br>${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof obj.speed != 'undefined') ? obj.speed : '0'}<br>${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}<br>${decodeURIComponent(obj?.fulladdress || 'address')}`,
				//             // label: `<b>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}</b><br>${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>${decodeURIComponent(obj?.fulladdress || 'address')}`,
				//             label: `<b>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}</b><br>${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(obj?.fulladdress || 'address')}`,
				//         }
				//     });

				//     let polyline = Leaflet.addPolylines(polyTruckRoutes);
				//     Leaflet.map.fitBounds(polyline.getBounds());
				//     // let ctrWaypoint = Leaflet.addWaypoints(polyTruckRoutes.slice(0, 100))

				//     Leaflet.addCircles(polyTruckRoutes, function(circle, i) {
				//         window.addEventListener('eventRemoveRouteStartEnd', function handler(e) {
				//             circle.remove();
				//         });
				//         circle.on('click', function() {
				//             PgBar.syncToPlotTravelHistory(i);
				//         })
				//     });

				//     let start = truckRoutes.at(-1);
				//     let finish = truckRoutes.at(0);
				//     // ${(start?.city_text || start?.state_tex || 'address't)} - ${(start?.postcode || 'postcode')}
				//     // ${(finish?.city_text || finish?.state_text || 'address')} - ${(finish?.postcode || 'postcode')}
				//     let startMarker = Leaflet.addMarkers({
				//         lat: start.latitude,
				//         lng: start.longitude,
				//         label: `<b>Start Poin</b><br>${start.nopol1} ${start.nopol2} ${start.nopol3}<br>${moment.unix(start?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}<br>${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}<br>${decodeURIComponent(start.fulladdress || 'address')}`,
				//         // label: `<b>Start Poin</b><br>${start.nopol1} ${start.nopol2} ${start.nopol3}<br>${moment.unix(start?.lst_loc_crt_s).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}<br>Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}<br>${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}<br>${decodeURIComponent(start.fulladdress || 'address')}`,
				//         options: {
				//             icon: Icon.titikAwal(),
				//             // rotationAngle: 290
				//         }
				//     });
				//     let finishMarker = Leaflet.addMarkers({
				//         lat: finish.latitude,
				//         lng: finish.longitude,
				//         label: `<b>End Poin</b><br>${finish.nopol1} ${finish.nopol2} ${finish.nopol3}<br>${moment.unix(finish?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof finish.lst_speed != 'undefined') ? finish.lst_speed : '0'}<br>${Number(finish.latitude).toFixed(5)},${Number(finish.longitude).toFixed(6)}<br>${decodeURIComponent(finish.fulladdress || 'address')}`,
				//         //label: `<b>End Poin</b><br>${finish.nopol1} ${finish.nopol2} ${finish.nopol3}<br>${moment.unix(finish?.lst_loc_crt_s).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}<br>Speed: ${(typeof finish.lst_speed != 'undefined') ? finish.lst_speed : '0'}<br>${Number(finish.latitude).toFixed(5)},${Number(finish.longitude).toFixed(6)}<br>${decodeURIComponent(finish.fulladdress || 'address')}`,
				//         options: {
				//             icon: Icon.titikAkhir()
				//         }
				//     });

				//     // remove marker, circle, event listener and all about this marker
				//     State.eventRemoveRouteStartEnd = new CustomEvent('eventRemoveRouteStartEnd', {
				//         startMarker,
				//         finishMarker,
				//         polyline,
				//         polyline,
				//     });
				//     window.addEventListener('eventRemoveRouteStartEnd', function handler(e) {
				//         startMarker.removeEventListener('click');
				//         startMarker.removeEventListener('moveend');
				//         startMarker.remove();
				//         finishMarker.removeEventListener('click');
				//         finishMarker.removeEventListener('moveend');
				//         finishMarker.remove();
				//         polyline.remove();
				//         e.currentTarget.removeEventListener(e.type,
				//             handler); // window.removeEventListener('remove', this.handler, true);
				//         State.eventRemoveRouteStartEnd = null;
				//         State.inShowLastMove = null;

				//         PgBar.tglMenuPlayback(false);
				//         PgBar.reset();
				//     });

				//     PgBar.setMinMax(0, truckRoutes.length - 1);
            // },
            routeStartEndGroupTrip:  function(truckRoutes) {
				const colors = [
					"#2980B9",  // Dark Blue
					"#C0392B", // Dark Red
					"#27AE60", // Dark Green
					"#D35400", // Dark Orange
					"#F39C12", // Dark Yellow/Gold
				]
				let i = 1
				let polyTruckRoutes = truckRoutes.map((groupTrip, key0) => {
					return groupTrip.map((obj, key) => {
						obj.key_index = i++
						// console.log("obj", obj.key_index);
						
						Menu.showToListMovement(obj)
						
						// add start end marker per group trip
						if(key == 0 || key == groupTrip.length - 1)
							Leaflet.addMarkers({
								lat: obj.latitude,
								lng: obj.longitude,
								label: `
									<b>Start Poin</b><br>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}<br>
									${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>
									Speed: ${(typeof obj.lst_speed != 'undefined') ? obj.lst_speed : '0'}<br>
									${Number(obj.latitude).toFixed(5)},${Number(obj.longitude).toFixed(6)}<br>
									${decodeURIComponent(obj.fulladdress || 'address')}
								`,
								// label: `<b>Start Poin</b><br>${start.nopol1} ${start.nopol2} ${start.nopol3}<br>${moment.unix(start?.lst_loc_crt_s).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}<br>Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}<br>${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}<br>${decodeURIComponent(start.fulladdress || 'address')}`,
								options: {
									icon: (key == 0) ? Icon.titikAkhir() : (key == (groupTrip.length - 1)) ? Icon.titikAwal() : null,
									// rotationAngle: 290
								}
							})

						return {
							lat: obj.latitude,
							lng: obj.longitude,
							options: {
								// polyline
								color : colors[key0 % colors.length],
								smoothFactor : 0,
								noClip : true,
								bubblingMouseEvents : false,
								// circle
								radius: 5,
								markerOpacity: 0
							},
							label: `<b>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}</b><br>${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(obj?.fulladdress || 'address')}`,
							// startLast : (key == 0) ? 0 : (key == (groupTrip.length - 1)) ? 1 : null,
						}
					})					
				})
				// console.log("truckRoutes update", polyTruckRoutes);

				polyTruckRoutes.forEach(async (poly, idx) => {
					// console.log("poly", poly);					
					// let polyline = Leaflet.addRoutes(poly)
					// let polyline = Leaflet.addPolylines(poly)

					// let circlesStartStop = []
					// Leaflet.addCircles(poly, function(circle, i) {
					// 	if(i == 0 || i == (polyTruckRoutes.length - 1))
					// 		circlesStartStop.push(circle)

					// 	window.addEventListener('eventRemoveRouteStartEnd', function handler(e) {
					// 		circle.remove();
					// 	});
					// 	circle.on('click', function() {
					// 		PgBar.syncToPlotTravelHistory(i);
					// 	})
					// });
					function addCirclesAsync(poly) {
						return new Promise(resolve => {
							let circles = [];

							Leaflet.addCircles(poly, function(circle, i) {
								if (i === 0 || i === (poly.length - 1)) {
									circles.push(circle);
								}

								circle.on('click', function() {
									PgBar.syncToPlotTravelHistory(i);
								});

								// ✅ When last point processed, resolve
								if (i === poly.length - 1) {
									resolve(circles);
								}
							});
						});
					}

					let circlesStartStop = [];
					for (let [idx, poly] of polyTruckRoutes.entries()) {
						let polyline = Leaflet.addRoutes(poly);

						// wait for all circles
						circlesStartStop = await addCirclesAsync(poly);

						// keep event + removal logic here
						State.eventRemoveRouteStartEnd = new CustomEvent('eventRemoveRouteStartEnd', {
							detail: { polyline, circlesStartStop }
						});

						window.addEventListener('eventRemoveRouteStartEnd', function(e) {
							// polyline.remove();
							circlesStartStop.forEach(c => c.remove());
						});
					}
					
					// // remove marker, circle, event listener and all about this marker
					State.eventRemoveRouteStartEnd = new CustomEvent('eventRemoveRouteStartEnd', {
						detail: {
							polyline,
							circlesStartStop
						}
					});

					window.addEventListener('eventRemoveRouteStartEnd', function (e) {
						polyline.remove();
						circlesStartStop.forEach(c => c.remove())
					});
				})

                window.addEventListener('eventRemoveRouteStartEnd', function handler(e) {
                    e.currentTarget.removeEventListener(e.type,
                        handler); // window.removeEventListener('remove', this.handler, true);
                    State.eventRemoveRouteStartEnd = null;
                    State.inShowLastMove = null;

                    PgBar.tglMenuPlayback(false);
                    PgBar.reset();
                });

                PgBar.setMinMax(0, Trucks.last_move.length - 1);
            },
            routePerPoint: function() {
                Leaflet.addMarkers(truckRoutes.routes.map((obj) => {
                    return {
                        lat: obj.lat,
                        lng: obj.lng,
                        options: {
                            icon: Icon.point(),
                            vhc_id: truckRoutes.vhc_id,
                            gps_id: truckRoutes.gps_id
                        }
                    };
                }));
            },
            routeStartEndWithStops: function() {
                Leaflet.addPolylines(truckRoutes.routes.map((obj) => {
                    return {
                        lat: obj.lat,
                        lng: obj.lng,
                        options: {}
                    }
                }), function(polyline) {
                    // zoom the map to the polyline
                    // Leaflet.map.fitBounds(polyline.getBounds());
                });
                Leaflet.addMarkers([{
                    ...truckRoutes.routes.at(0),
                    label: 'Lokasi Mulai Perjalanan Truk',
                    options: {
                        icon: Icon.startNav(),
                        rotationAngle: 290
                    }
                }]);
                Leaflet.addMarkers([{
                    ...truckRoutes.routes.at(20),
                    label: 'Lokasi Berhenti Truk',
                    options: {
                        icon: Icon.point()
                    }
                }]);
                Leaflet.addMarkers([{
                    ...truckRoutes.routes.at(40),
                    label: 'Lokasi Berhenti Truk',
                    options: {
                        icon: Icon.point()
                    }
                }]);
                Leaflet.addMarkers([{
                    ...truckRoutes.routes.at(60),
                    label: 'Lokasi Berhenti Truk',
                    options: {
                        icon: Icon.point()
                    }
                }]);
                Leaflet.addMarkers([{
                    ...truckRoutes.routes.at(-1),
                    label: 'Lokasi Tujuan Truk',
                    options: {
                        icon: Icon.destination()
                    }
                }]);
            },
            routeAnimationStartShringkingToEnd: function() {
                let polyline = null,
                    marker = null,
                    timeouts = [];
                for (let i = 0; i < truckRoutes.routes.length; i++) {
                    timeouts.push(setTimeout(() => {
                        if (polyline) polyline.remove();
                        if (marker) marker.remove();

                        // jika typeof variable !== 'undefined'
                        if (!!truckRoutes.routes.at(i + 1)) {
                            polyline = Leaflet.addPolylines(truckRoutes.routes.slice((i + 1)).map((
                                obj) => {
                                return {
                                    lat: obj.lat,
                                    lng: obj.lng,
                                    options: {}
                                }
                            }), function(polyline) {
                                // zoom the map to the polyline
                                Leaflet.map.fitBounds(polyline.getBounds());
                            });
                        }

                        marker = Leaflet.addMarkers({
                            ...truckRoutes.routes.at(i),
                            label: 'Lokasi Truk',
                            options: {
                                icon: Icon.startNav(),
                                rotationAngle: 0
                            }
                        });
                    }, (i + 1) * State.timingRouteAnimation));
                }
                // remove marker, polyline, event listener and all about this marker
                State.eventRemoveRouteAnimationStartShrinkingToEnd = new CustomEvent(
                    'eventRemoveRouteAnimationStartShrinkingToEnd', {
                        marker: marker,
                        polyline: polyline
                    });

                window.addEventListener('eventRemoveRouteAnimationStartShrinkingToEnd', function handler(e) {
                    for (let i = 0; i < timeouts.length; i++) {
                        clearTimeout(timeouts[i]);
                    }
                    if (marker) marker.remove();
                    if (polyline) polyline.remove();
                    e.currentTarget.removeEventListener(e.type,
                        handler); // window.removeEventListener('remove', this.handler, true);
                    State.eventRemoveRouteAnimationStartShrinkingToEnd = null;
                });
            },
            routeAnimationStartFootprintsTillEnd: function() {
                let polyline = null,
                    marker = null,
                    timeouts = [];
                for (let i = 0; i < truckRoutes.routes.length; i++) {
                    timeouts.push(setTimeout(() => {
                        if (polyline) polyline.remove();
                        if (marker) marker.remove();

                        polyline = Leaflet.addPolylines(truckRoutes.routes.slice(0, (i + 1)).map((
                            obj) => {
                            return {
                                lat: obj.lat,
                                lng: obj.lng,
                                options: {}
                            }
                        }), function(polyline) {
                            // zoom the map to the polyline
                            Leaflet.map.fitBounds(polyline.getBounds());
                        });

                        marker = Leaflet.addMarkers({
                            ...truckRoutes.routes.at(i),
                            label: 'Lokasi Truk',
                            options: {
                                icon: Icon.startNav(),
                                rotationAngle: 0
                            }
                        });
                    }, (i + 1) * State.timingRouteAnimation));
                }
                // remove marker, polyline, event listener and all about this marker
                State.eventRemoveRouteAnimationStartFootprintsTillEnd = new CustomEvent(
                    'eventRemoveRouteAnimationStartFootprintsTillEnd', {
                        marker: marker,
                        polyline: polyline
                    });

                window.addEventListener('eventRemoveRouteAnimationStartFootprintsTillEnd', function handler(e) {
                    for (let i = 0; i < timeouts.length; i++) {
                        clearTimeout(timeouts[i]);
                    }
                    if (marker) marker.remove();
                    if (polyline) polyline.remove();
                    e.currentTarget.removeEventListener(e.type,
                        handler); // window.removeEventListener('remove', this.handler, true);
                    State.eventRemoveRouteAnimationStartFootprintsTillEnd = null;
                });
            },
        }

        const Zone = {
            lists: null,
            activate: function() {
                Zone.bundleGetListZones(false);
            },
            bundleGetListZones: async function(cache = false) {
                Zone.lists = await Zone.getListZones(cache);
                Zone.showToLists(Zone.lists);
                Zone.showListsToMap(Zone.lists);
            },
            getListZones: async function(cache = false) {
                if (cache) {
                    if (Zone.lists == null) {
                        return (await Zone.reqListZones()).data;
                    } else {
                        return Zone.lists;
                    }
                }
                return (await Zone.reqListZones()).data;
            },
            reqListZones: function(params) {
                return new Promise((resolve, reject) => {
                    $.ajax({
                        url: "{{ route('api_universal_list_zones') }}?status=" + State.zone_status.active + "&cptid=" + AppState.current_company,
                        method: 'GET',
                        crossDomain: true,
                        processData: true,
                        headers: {
                            'x-api-key': Helper.getCookie('_trtk'),
                        },
                        data: params,
                        success: (data, textStatus, jqXHR) => {
                            if (data.meta.type != 'success') {
                                resolve({
                                    type: 'fail',
                                    data: null,
                                });
                                Helper.toast('Warning', 'just now', data.meta.message);
                                return false;
                            }
                            resolve({
                                type: 'success',
                                data: data.data,
                            });
                        },
                        error: (jqXHR, textStatus, error) => {
                            if (jqXHR.status >= 500) {
                                Helper.toast('Error', 'just now', 'Cannot get lists trucks');
                            } else {
                                Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
                                    .message);
                            }
                            resolve({
                                type: 'error',
                                data: null,
                            });
                        }
                    })
                });
            },
            showToLists: function(zones) {
                $('#listZone').html('');
                let str = '';
                for (let i = 0; i < zones.length; i++) {
                    str += `
                    <li class="list-group-item vehicles-list-wrapper zone-item p-1 px-2" data-zid="${zones[i].id}">
                        <a href="#" class="text-dark">
                            <div class="row d-flex align-items-center">
                                <div class="col-3 d-flex justify-content-center">
                                    <div class="align-items-center d-flex justify-content-center zone-icon" style="background: ${zones[i].boundary_hex_color}">
                                        <span class="ion-android-pin text-white"></span>
                                    </div>
                                </div>
                                <div class="col ps-0">
                                    <p class="text-bold mb-0 textZoneName">${zones[i].name}</p>
                                    <p class="text-muted mb-0 textZoneType">${zones[i].type_name}</p>
                                </div>
                            </div>
                        </a>
                    </li>
                    `;
                }
                $('#c_list_zone').text(zones.length);
                $('#listZone').html(str);
            },
            showListsToMap: function(zones) {
                let locations = []; // [{ lat,lng,label,options:{} }]
                let circles = [],
                    polygons = [];

                for (let i = 0; i < zones.length; i++) {
                    let boundary_latlngs = JSON.parse(zones[i].boundary_latlngs);
                    boundary_latlngs = boundary_latlngs.map((obj) => {
                        return {
                            lat: obj.lat,
                            lng: obj.lng,
                            label: `<b>${zones[i].name}</b><br>${decodeURIComponent(zones[i].fulladdress || 'address')}`,
                            options: {
                                mdata: zones[i],
                                color: zones[i].boundary_hex_color,
                                fillColor: zones[i].boundary_hex_color,
                                radius: zones[i].boundary_radius,
                            },
                        };
                    });
                    if (zones[i].boundary_type == State.zone_boundary_type.circle) {
                        let circle = Leaflet.addCircles(boundary_latlngs[0]);
                        circles.push(circle);
                    } else if (zones[i].boundary_type == State.zone_boundary_type.polygon || zones[i]
                        .boundary_type == State.zone_boundary_type.rectangle) {
                        let polygon = Leaflet.addPolygons(boundary_latlngs);
                        polygons.push(polygon);
                    } else {
                        Helper.toast('Error', 'just now', 'unknown boundary type');
                        continue;
                    }
                }

                // remove marker, circle, event listener and all about this marker
                State.eventRemoveListZones = new CustomEvent('eventRemoveListZones', {
                    circles,
                    polygons
                });
                window.addEventListener('eventRemoveListZones', function handler(e) {
                    for (let circle of circles) {
                        circle.removeEventListener('click');
                        circle.remove();
                    }
                    for (let polygon of polygons) {
                        polygon.removeEventListener('click');
                        polygon.remove();
                    }
                    e.currentTarget.removeEventListener(e.type,
                        handler); // window.removeEventListener('remove', this.handler, true);
                    State.eventRemoveListZones = null;
                });
            },
            showDetailGeneral: function(zone) {
                State.inShowZid = zone.zid;
                $('#zd-name').text(zone.name);
                $('#zd-boundary_hex_color').css('background-color', zone.boundary_hex_color || '#000000')
                $('#zd-type_name').text(zone.type_name);
                $('#zd-type_name1').text(zone.type_name);
                $('#zd-client').text(zone.client_group_name);
                $('#zd-workflow_type_name').text(zone.workflow_type_name);
                $('#zd-fulladdress').text(decodeURIComponent(zone.fulladdress || 'address'));
                $('#zd-shiptocode').text(zone.shiptocode);
                $('#zd-updt_at').text(moment(zone.updt).format('DD MMM YYYY HH:mm'));
                $('#zd-updt_by').text(zone.updt_name);
            },
        }

        const Client = {
            client: null,
            activate: function() {
                Client.bundleGetClient(false);
            },
            bundleGetClient: async function(cache = false) {
                Client.client = await Client.getClient(cache);
                Client.showToView(Client.client);
            },
            getClient: async function(cache = false) {
                if (cache) {
                    if (Client.client == null) {
                        return (await Client.reqClient()).data;
                    } else {
                        return Client.client;
                    }
                }
                return (await Client.reqClient()).data;
            },
            reqClient: function(params) {
                return new Promise((resolve, reject) => {
                    $.ajax({
                        url: "{{ route('api_universal_show_client_pt') }}?cptid=" + AppState.current_company,
                        method: 'GET',
                        crossDomain: true,
                        processData: true,
                        headers: {
                            'x-api-key': Helper.getCookie('_trtk'),
                        },
                        data: params,
                        success: (data, textStatus, jqXHR) => {
                            if (data.meta.type != 'success') {
                                resolve({
                                    type: 'fail',
                                    data: null,
                                });
                                Helper.toast('Warning', 'just now', data.meta.message);
                                return false;
                            }
                            resolve({
                                type: 'success',
                                data: data.data,
                            });
                        },
                        error: (jqXHR, textStatus, error) => {
                            if (jqXHR.status >= 500) {
                                Helper.toast('Error', 'just now', 'Cannot get company information');
                            } else {
                                Helper.toast('Error', 'just now', jqXHR.responseJSON.meta
                                    .message);
                            }
                            resolve({
                                type: 'error',
                                data: null,
                            });
                        }
                    })
                });
            },
            showToView: function(client) {
                $('#c_name').text(client.c_name);
                $('#ptName').text(client.c_name);
                $('#c_logo').attr('src', State.storage_lara + '/' + client.c_logo);
            },
        }

        const Filter = {
            activate: function() {
                Filter.event();
            },
            event: function() {},
            triggerFilterCompany: async function() {
                Leaflet.clearLayer('all');
                // client
                await Client.bundleGetClient(false);
                // trucks
                State.loadedLastMoveVid = null;
                State.inShowZid = null;
                State.lastShowVids = [];
                await Trucks.bundleGetListTrucks(false);
                // zones
                State.inShowZid = null;
                await Zone.bundleGetListZones(false);
            },
        }

        const PgBar = {
            activate: function() {
                PgBar.event();
            },
            event: function() {
                $('#pgplay').on('click', function(e) {
                    const click = $(e.target);
                    if (State.playback.stts === 0 || State.playback.stts === 2 || State.playback.stts === 4) {
                        PgBar.resume();
                    } else if (State.playback.stts === 1 || State.playback.stts === 3) {
                        PgBar.pause();
                    }
                });

                document.getElementById('pgbar').oninput = function() {
                    this.value = Number(this.value);
                    this.min = Number(this.min);
                    this.max = Number(this.max);

                    State.playback.crntPgIndicator = this.value;
                    let indicator = Helper.getPercentRange(this.value, this.min, this.max);
                    this.style.background = `linear-gradient(to right, var(--bs-blue) 0%, var(--bs-blue) ${indicator}%, #d3d3d3 0%)`;

                    let arrIdx = Helper.getIndexReversedSequence(this.value, this.max);
                    if (Trucks.last_move === null || Trucks.last_move.length < 1) {} else {
                        let tr = Trucks.last_move[arrIdx];
                        setTimeout(() => {
                            Menu.createMarkerDetailPlotMovement(tr);
                        }, 1);
                    }

                    PgBar.syncToPlotTravelHistory(arrIdx);
                }
            },
            setMinMax: function(min, max) {
                min = Number(min);
                max = Number(max);
                PgBar.reset();
                PgBar.tglMenuPlayback(true);
                const bar = document.getElementById('pgbar');
                bar.min = min;
                bar.max = max;
                State.playback.minIndicator = min;
                State.playback.maxIndicator = max;
            },
            setCrntVal: function(val) {
                val = Number(val);
                State.playback.crntIndicator = val;
                const bar = document.getElementById('pgbar');
                bar.value = State.playback.crntIndicator;
                let indicator = Helper.getPercentRange(bar.value, bar.min, bar.max);
                bar.style.background = `linear-gradient(to right, var(--bs-blue) 0%, var(--bs-blue) ${indicator}%, #d3d3d3 0%)`;
            },
            reset: function() {
                State.playback.stts = 0;
                State.playback.crntIndicator = 0;
                State.playback.minIndicator = 0;
                State.playback.maxIndicator = 1000;
                clearInterval(State.playback.intrvl);
                const bar = document.getElementById('pgbar');
                bar.min = State.playback.minIndicator;
                bar.max = State.playback.maxIndicator;
                bar.value = State.playback.crntIndicator;
                bar.style.background = `linear-gradient(to right, var(--bs-blue) 0%, var(--bs-blue) ${0}%, #d3d3d3 0%)`;
                PgBar.tglIconPlayback(State.playback.stts);
            },
            resume: function() {
                // not allowed
                if (State.playback.stts === 1 || State.playback.stts === 3) return false;
                if (Trucks.last_move === null || Trucks.last_move.length < 1) {
                    Helper.toast('Warning', 'just now', 'Data riwayat tidak ada');
                    return false;
                }
                State.playback.stts = 1;

                PgBar.tglIconPlayback(State.playback.stts);

                State.playback.intrvl = setInterval(frame, State.playback.intrvlTime);

                function frame() {
                    const bar = document.getElementById('pgbar');
                    let value = Number(bar.value);
                    let min = Number(bar.min);
                    let max = Number(bar.max);
                    let arrIdx = Helper.getIndexReversedSequence(value, max);

                    if (value >= max) {
                        clearInterval(State.playback.intrvl);
                        State.playback.stts = 4;
                        PgBar.tglIconPlayback(State.playback.stts);
                    } else {
                        ++value;
                        bar.value = value;
                        let indicator = Helper.getPercentRange(value, min, max);
                        bar.style.background = `linear-gradient(to right, var(--bs-blue) 0%, var(--bs-blue) ${indicator}%, #d3d3d3 0%)`;

                        let tr = Trucks.last_move[arrIdx];
                        Menu.createMarkerDetailPlotMovement(tr, {
                            nozoom: true
                        });
                    }

                    PgBar.syncToPlotTravelHistory(arrIdx);
                }
            },
            pause: function() {
                // not allowed
                if (State.playback.stts === 0 || State.playback.stts === 2 || State.playback.stts === 4) return false;
                State.playback.stts = 2;

                const bar = document.getElementById('pgbar');
                PgBar.tglIconPlayback(State.playback.stts);

                clearInterval(State.playback.intrvl);

                // just show markers with openPopup
                let value = Number(bar.value);
                let min = Number(bar.min);
                let max = Number(bar.max);
                let arrIdx = Helper.getIndexReversedSequence(value, max);
                let tr = Trucks.last_move[arrIdx];
                setTimeout(() => {
                    Menu.createMarkerDetailPlotMovement(tr, {
                        nozoom: true
                    });
                }, 1);
            },
            play1: function() {
                let indicator = 0; // percent: double
                const bar = document.getElementById('pgbar');
                let frameProgress = setInterval(frame, 10);

                function frame() {
                    if (indicator >= 100) {
                        clearInterval(frameProgress);
                    } else {
                        ++indicator;
                        bar.style.width = indicator + '%';
                    }
                }
            },
            tglMenuPlayback: function(show = true) {
                if (show) document.getElementById('menuPlayback').classList.remove('d-none');
                else document.getElementById('menuPlayback').classList.add('d-none');
            },
            tglIconPlayback: function(stts) {
                const iconPg = document.getElementById('icon-pg');
                if (stts === 0 || stts === 2 || stts === 4) {
                    iconPg.classList.remove('ion-pause');
                    iconPg.classList.add('ion-play');
                } else if (stts === 1 || stts === 3) {
                    iconPg.classList.remove('ion-play');
                    iconPg.classList.add('ion-pause');
                }
            },
            syncToPlotTravelHistory: function(arrIdx) {
                const listPlotTravelHistory = document.querySelectorAll('#infoMove-plots .plotMove-item')[arrIdx];
                listPlotTravelHistory.scrollIntoView();
                listPlotTravelHistory.querySelector('li').classList.add('hover');
                setTimeout(() => {
                    listPlotTravelHistory.querySelector('li').classList.remove('hover');
                }, 500);
            }
        }

        Wrapper.activate();
    </script>
@endsection
