B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Activity
Version=9.9
@EndOfDesignText@
#Region  Activity Attributes 
    #FullScreen: False
    #IncludeTitle: True
    #IgnoreWarnings: 9, 10, 15, 32
#End Region

Sub Process_Globals
	Private prevIntent As Intent
    Private LastTapTime As Long = 0
End Sub

Sub Globals
    ' Login UI
    Private pnlLogin As Panel
    Private txtPhone As EditText
    Private txtPass As EditText
    Private btnLogin As Button
    
    ' Tracking UI
    Private pnlTracking As Panel
    Private lblStatus As Label
    Private lblDriverInfo As Label
    Private btnToggle As Button
    Private btnLogout As Button
    Private btnAttendance As Button
    
    ' Attendance UI
    Private pnlAttendance As Panel
    Private clvStudents As ScrollView ' Using ScrollView for custom layout
    Private btnBackToTracking As Button
    Private StudentList As List
    Private rp As RuntimePermissions
    Private nfc As NFC
    Private RegistrationTargetID As Int = 0 ' 0 means normal attendance mode
    
    ' Tag Scanning Modal
    Private pnlTagScan As Panel
    Private lblScanStatus As Label
    Private btnCancelScan As Button
    
    ' Route Selection UI
    Private pnlRouteSelection As Panel
    Private lvRoutes As ListView
    Private lblRouteTitle As Label
    Private btnRefreshRoutes As Button
    Private ActiveRouteID As Int = 0
    Private ActiveRouteName As String = ""
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.Title = "BusTrack Driver"
    Activity.Color = Colors.White
    
    ' Initialize UI
    InitializeLoginUI
    InitializeRouteSelectionUI
    InitializeTrackingUI
    InitializeAttendanceUI
    InitializeScanUI
    
    ' Initialize NFC (Managed via Foreground Dispatch in Resume/Pause)
    Log("NFC Ready")
    
    CheckLoginState
End Sub

Sub InitializeLoginUI
    ' Login Panel
    pnlLogin.Initialize("")
    Activity.AddView(pnlLogin, 0, 0, 100%x, 100%y)
    pnlLogin.Color = Colors.RGB(240, 240, 240)
    
    ' Title
    Dim lblTitle As Label
    lblTitle.Initialize("")
    lblTitle.Text = "Driver Login"
    lblTitle.TextSize = 28
    lblTitle.TextColor = Colors.RGB(33, 150, 243)
    lblTitle.Gravity = Gravity.CENTER
    pnlLogin.AddView(lblTitle, 10%x, 15%y, 80%x, 60dip)
    
    ' Phone Input
    Dim lblPhone As Label
    lblPhone.Initialize("")
    lblPhone.Text = "Phone Number"
    lblPhone.TextSize = 14
    lblPhone.TextColor = Colors.DarkGray
    pnlLogin.AddView(lblPhone, 10%x, 30%y, 80%x, 30dip)
    
    txtPhone.Initialize("txtPhone")
    txtPhone.Hint = "Enter phone number"
    txtPhone.InputType = txtPhone.INPUT_TYPE_PHONE
    txtPhone.TextSize = 16
    pnlLogin.AddView(txtPhone, 10%x, 35%y, 80%x, 50dip)
    
    ' Password Input
    Dim lblPass As Label
    lblPass.Initialize("")
    lblPass.Text = "Password"
    lblPass.TextSize = 14
    lblPass.TextColor = Colors.DarkGray
    pnlLogin.AddView(lblPass, 10%x, 45%y, 80%x, 30dip)
    
    txtPass.Initialize("txtPass")
    txtPass.Hint = "Enter password"
    txtPass.PasswordMode = True
    txtPass.TextSize = 16
    pnlLogin.AddView(txtPass, 10%x, 50%y, 80%x, 50dip)
    
    ' Login Button
    btnLogin.Initialize("btnLogin")
    btnLogin.Text = "LOGIN"
    btnLogin.TextSize = 18
    btnLogin.Color = Colors.RGB(33, 150, 243)
    btnLogin.TextColor = Colors.White
    pnlLogin.AddView(btnLogin, 10%x, 65%y, 80%x, 55dip)
End Sub

Sub InitializeTrackingUI
    ' Tracking Panel
    pnlTracking.Initialize("")
    Activity.AddView(pnlTracking, 0, 0, 100%x, 100%y)
    pnlTracking.Color = Colors.White
    pnlTracking.Visible = False
    
    ' Driver Info
    lblDriverInfo.Initialize("")
    lblDriverInfo.Text = "Driver Dashboard"
    lblDriverInfo.TextSize = 22
    lblDriverInfo.TextColor = Colors.RGB(33, 150, 243)
    lblDriverInfo.Gravity = Gravity.CENTER
    pnlTracking.AddView(lblDriverInfo, 10%x, 10%y, 80%x, 60dip)
    
    ' Status Label
    lblStatus.Initialize("")
    lblStatus.Text = "Status: IDLE"
    lblStatus.TextSize = 24
    lblStatus.TextColor = Colors.Red
    lblStatus.Gravity = Gravity.CENTER
    pnlTracking.AddView(lblStatus, 10%x, 25%y, 80%x, 80dip)
    
    ' Toggle Button
    btnToggle.Initialize("btnToggle")
    btnToggle.Text = "START TRACKING"
    btnToggle.TextSize = 20
    btnToggle.Color = Colors.RGB(76, 175, 80)
    btnToggle.TextColor = Colors.White
    pnlTracking.AddView(btnToggle, 10%x, 45%y, 80%x, 70dip)
    
    ' Logout Button
    btnLogout.Initialize("btnLogout")
    btnLogout.Text = "LOGOUT"
    btnLogout.TextSize = 16
    btnLogout.Color = Colors.RGB(244, 67, 54)
    btnLogout.TextColor = Colors.White
    pnlTracking.AddView(btnLogout, 10%x, 75%y, 80%x, 50dip)
    
    ' Attendance Button
    btnAttendance.Initialize("btnAttendance")
    btnAttendance.Text = "MARK ATTENDANCE 📋"
    btnAttendance.TextSize = 18
    btnAttendance.Color = Colors.RGB(33, 150, 243)
    btnAttendance.TextColor = Colors.White
    pnlTracking.AddView(btnAttendance, 10%x, 63%y, 80%x, 60dip)
End Sub

Sub InitializeAttendanceUI
    pnlAttendance.Initialize("")
    Activity.AddView(pnlAttendance, 0, 0, 100%x, 100%y)
    pnlAttendance.Color = Colors.White
    pnlAttendance.Visible = False
    
    Dim lblTitle As Label
    lblTitle.Initialize("")
    lblTitle.Text = "Student Attendance"
    lblTitle.TextSize = 22
    lblTitle.TextColor = Colors.RGB(33, 150, 243)
    lblTitle.Gravity = Gravity.CENTER
    pnlAttendance.AddView(lblTitle, 5%x, 5%y, 70%x, 50dip)
    
    btnBackToTracking.Initialize("btnBackToTracking")
    btnBackToTracking.Text = "BACK"
    btnBackToTracking.Color = Colors.DarkGray
    btnBackToTracking.TextColor = Colors.White
    pnlAttendance.AddView(btnBackToTracking, 75%x, 5%y, 20%x, 50dip)
    
    clvStudents.Initialize(0)
    pnlAttendance.AddView(clvStudents, 0, 15%y, 100%x, 85%y)
End Sub

Sub InitializeScanUI
    pnlTagScan.Initialize("")
    Activity.AddView(pnlTagScan, 0, 0, 100%x, 100%y)
    pnlTagScan.Color = Colors.ARGB(200, 0, 0, 0) ' Semi-transparent black
    pnlTagScan.Visible = False
    
    ' Scan Status Card
    Dim pnlCard As Panel
    pnlCard.Initialize("")
    pnlCard.Color = Colors.White
    pnlTagScan.AddView(pnlCard, 10%x, 35%y, 80%x, 30%y)
    
    lblScanStatus.Initialize("")
    lblScanStatus.Text = "Tap NFC Tag..."
    lblScanStatus.TextSize = 20
    lblScanStatus.TextColor = Colors.RGB(33, 150, 243)
    lblScanStatus.Gravity = Gravity.CENTER
    pnlCard.AddView(lblScanStatus, 5%x, 20%y, 90%x, 40%y)
    
    btnCancelScan.Initialize("btnCancelScan")
    btnCancelScan.Text = "CANCEL"
    btnCancelScan.Color = Colors.RGB(244, 67, 54)
    btnCancelScan.TextColor = Colors.White
    pnlCard.AddView(btnCancelScan, 25%x, 70%y, 50%x, 50dip)
End Sub

Sub InitializeRouteSelectionUI
    pnlRouteSelection.Initialize("")
    Activity.AddView(pnlRouteSelection, 0, 0, 100%x, 100%y)
    pnlRouteSelection.Color = Colors.RGB(240, 240, 240)
    pnlRouteSelection.Visible = False
    
    ' Title
    lblRouteTitle.Initialize("")
    lblRouteTitle.Text = "Select Your Route"
    lblRouteTitle.TextSize = 24
    lblRouteTitle.TextColor = Colors.RGB(33, 150, 243)
    lblRouteTitle.Gravity = Gravity.CENTER
    pnlRouteSelection.AddView(lblRouteTitle, 10%x, 10%y, 80%x, 60dip)
    
    ' Routes ListView
    lvRoutes.Initialize("lvRoutes")
    lvRoutes.TwoLinesAndBitmap.ItemHeight = 80dip
    lvRoutes.TwoLinesAndBitmap.SecondLabel.TextSize = 14
    lvRoutes.TwoLinesAndBitmap.SecondLabel.TextColor = Colors.DarkGray
    pnlRouteSelection.AddView(lvRoutes, 5%x, 20%y, 90%x, 60%y)
    
    ' Refresh Button
    btnRefreshRoutes.Initialize("btnRefreshRoutes")
    btnRefreshRoutes.Text = "REFRESH ROUTES"
    btnRefreshRoutes.TextSize = 16
    btnRefreshRoutes.Color = Colors.RGB(76, 175, 80)
    btnRefreshRoutes.TextColor = Colors.White
    pnlRouteSelection.AddView(btnRefreshRoutes, 10%x, 85%y, 80%x, 50dip)
End Sub

Sub btnCancelScan_Click
    RegistrationTargetID = 0
    pnlTagScan.Visible = False
End Sub

Sub Activity_Resume
	' Only update UI if we're on the tracking screen
	If pnlTracking.IsInitialized And pnlTracking.Visible Then
		UpdateUI
	End If
	
	' 1. Enable NFC listening while app is visible
    Try
	    nfc.EnableForegroundDispatch
    Catch
        Log("NFC Dispatch Error: " & LastException)
    End Try
    
    ' 2. Process intentional scan
    ProcessIntent(Activity.GetStartingIntent)
End Sub

Sub Activity_NewIntent (StartingIntent As Intent)
    Log("New Intent Received")
    ' We process the new intent in Activity_Resume or here
    ProcessIntent(StartingIntent)
End Sub

' Helper to extract Tag ID and handle logic
Sub ProcessIntent(si As Intent)
    If si.IsInitialized = False Then Return
    
    Log("Checking Intent: " & si.Action)
    
    If si.Action.EndsWith("TECH_DISCOVERED") OR si.Action.EndsWith("TAG_DISCOVERED") OR si.Action.EndsWith("NDEF_DISCOVERED") Then
        ProcessNFCTag(si)
        ' Intent is processed, no need to clear it manually with SetStartingIntent
    End If
End Sub

' Helper to extract Tag ID and handle logic
Sub ProcessNFCTag(si As Intent)
    Try
        Dim jo As JavaObject = si
        Dim tag As JavaObject = jo.RunMethod("getParcelableExtra", Array("android.nfc.extra.TAG"))
        
        If tag.IsInitialized Then
            Dim bc As ByteConverter
            Dim rawId() As Byte = tag.RunMethod("getId", Null)
            Dim nfcId As String = bc.HexFromBytes(rawId)
            
            Log("NFC ID Detected: " & nfcId)
            
            ' Update UI if modal is visible
            If pnlTagScan.Visible Then
                lblScanStatus.Text = "DETECTED: " & nfcId & CRLF & "Saving to database..."
                lblScanStatus.TextColor = Colors.Green
            Else
                ToastMessageShow("NFC Tag: " & nfcId, False)
            End If
            
            ' Audio feedback
            Dim p As PhoneVibrate
            p.Vibrate(150)
            
            ' Handle Registration or Attendance
            SendTagToServer(nfcId)
        End If
    Catch
        Log("NFC Extract Error: " & LastException)
    End Try
End Sub

Sub SendTagToServer(nfcId As String)
    Log("NFC: Sending to server...")
    Dim payload As Map
    payload.Initialize
    payload.Put("nfc_id", nfcId)
    
	If RegistrationTargetID > 0 Then
        payload.Put("student_id", RegistrationTargetID)
		Dim gen As JSONGenerator
		gen.Initialize(payload)
		Dim job As HttpJob
		job.Initialize("register_tag", Me)
		job.PostString(APIModule.ServerURL & "/register_nfc_tag.php", gen.ToString)
		APIModule.SetAuthHeader(job, APIModule.GetToken)
		RegistrationTargetID = 0 
	Else
		Dim gen As JSONGenerator
		gen.Initialize(payload)
		Dim job As HttpJob
		job.Initialize("mark_attendance_nfc", Me)
		job.PostString(APIModule.ServerURL & "/mark_attendance_nfc.php", gen.ToString)
		APIModule.SetAuthHeader(job, APIModule.GetToken)
	End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    ' Disable NFC dispatch to avoid battery drain when app is in background
    nfc.DisableForegroundDispatch
End Sub

Sub CheckLoginState
    If APIModule.GetToken = "" Then
        ShowLogin
    Else
        ' Check if route is already selected
        If ActiveRouteID = 0 Then
            ShowRouteSelection
        Else
            ShowTracking
        End If
    End If
End Sub

Sub ShowLogin
    pnlLogin.Visible = True
    pnlRouteSelection.Visible = False
    pnlTracking.Visible = False
    pnlAttendance.Visible = False
End Sub

Sub ShowRouteSelection
    pnlLogin.Visible = False
    pnlRouteSelection.Visible = True
    pnlTracking.Visible = False
    pnlAttendance.Visible = False
    LoadRoutes
End Sub

Sub ShowTracking
    pnlLogin.Visible = False
    pnlRouteSelection.Visible = False
    pnlTracking.Visible = True
    pnlAttendance.Visible = False
    
    ' Update driver info with route
    If ActiveRouteName <> "" Then
        lblDriverInfo.Text = "Route: " & ActiveRouteName
    End If
    UpdateUI
End Sub

Sub btnLogin_Click
    Dim phone As String = txtPhone.Text.Trim
    Dim password As String = txtPass.Text.Trim
    
    If phone = "" Or password = "" Then
        ToastMessageShow("Please enter phone and password", True)
        Return
    End If
    
    btnLogin.Enabled = False
    btnLogin.Text = "Logging in..."
    
    Dim data As Map
    data.Initialize
    data.Put("phone", phone)
    data.Put("password", password)
    
    Dim json As JSONGenerator
    json.Initialize(data)
    
    Dim job As HttpJob
    job.Initialize("login", Me)
    job.PostString(APIModule.ServerURL & "/login.php", json.ToString)
    job.GetRequest.SetHeader("Content-Type", "application/json")
End Sub

Sub btnToggle_Click
    If TrackingService.IsTracking Then
        CallSub(TrackingService, "StopTracking")
        UpdateUI
    Else
        rp.CheckAndRequest(rp.PERMISSION_ACCESS_FINE_LOCATION)
        Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
        If Result Then
            ' Small sleep ensures activity state is stabilized before service start
            Sleep(200) 
            Try
                StartService(TrackingService)
                CallSubDelayed(TrackingService, "StartTracking")
                ' Wait slightly for service logic to kick in before updating UI
                Sleep(200)
                UpdateUI
            Catch
                Log("Error starting service: " & LastException)
                ToastMessageShow("Could not start tracking service", True)
            End Try
        Else
            ToastMessageShow("Location permission required for tracking", True)
        End If
    End If
End Sub

Sub btnLogout_Click
    APIModule.ClearToken
    CallSub(TrackingService, "StopTracking")
    txtPhone.Text = ""
    txtPass.Text = ""
    CheckLoginState
End Sub

Sub btnAttendance_Click
    ShowAttendance
End Sub

Sub btnBackToTracking_Click
    ShowTracking
End Sub

Sub ShowAttendance
    pnlLogin.Visible = False
    pnlTracking.Visible = False
    pnlAttendance.Visible = True
    FetchStudents
End Sub

Sub FetchStudents
    Dim job As HttpJob
    job.Initialize("fetch_students", Me)
    job.Download(APIModule.ServerURL & "/get_students_by_driver.php")
    APIModule.SetAuthHeader(job, APIModule.GetToken)
End Sub

Sub UpdateStudentList(students As List)
    StudentList = students
    clvStudents.Panel.RemoveAllViews
    
    Dim itemHeight As Int = 110dip
    clvStudents.Panel.Height = students.Size * itemHeight
    
    For i = 0 To students.Size - 1
        Dim s As Map = students.Get(i)
        Dim p As Panel
        p.Initialize("")
        clvStudents.Panel.AddView(p, 0, i * itemHeight, 100%x, itemHeight)
        
        Dim lblName As Label
        lblName.Initialize("")
        lblName.Text = (i+1) & ". " & s.Get("name") & " (" & s.Get("grade") & ")"
        lblName.TextSize = 16
        lblName.Typeface = Typeface.DEFAULT_BOLD
        p.AddView(lblName, 10dip, 10dip, 90%x, 30dip)
        
        Dim lblStop As Label
        lblStop.Initialize("")
        lblStop.Text = "📍 " & s.Get("stop_name")
        lblStop.TextSize = 14
        lblStop.TextColor = Colors.DarkGray
        p.AddView(lblStop, 10dip, 40dip, 90%x, 30dip)
        
        Dim status As String = s.GetDefault("current_status", "")
        
        Dim btnPickup As Button
        btnPickup.Initialize("btnAction")
        btnPickup.Tag = CreateMap("id": s.Get("id"), "action": "pickup")
        btnPickup.Text = "PICKUP"
        btnPickup.TextSize = 12
        If status = "pickup" Then 
            btnPickup.Color = Colors.Green 
            btnPickup.Enabled = False
        Else
            btnPickup.Color = Colors.RGB(76, 175, 80)
        End If
        p.AddView(btnPickup, 10dip, 70dip, 40%x, 35dip)
        
        Dim btnDrop As Button
        btnDrop.Initialize("btnAction")
        btnDrop.Tag = CreateMap("id": s.Get("id"), "action": "drop")
        btnDrop.Text = "DROP"
        btnDrop.TextSize = 12
        If status = "drop" Then 
            btnDrop.Color = Colors.Red 
            btnDrop.Enabled = False
        Else
            btnDrop.Color = Colors.RGB(244, 67, 54)
        End If
        p.AddView(btnDrop, 50%x, 70dip, 20%x, 35dip)
        
        ' Only show registration button if student doesn't have a tag
        Dim hasNfc As Boolean = False
        If s.ContainsKey("nfc_id") Then
            Dim nId As String = s.Get("nfc_id")
            If nId <> "" AND nId <> "null" Then hasNfc = True
        End If
        
        If hasNfc = False Then
            Dim btnReg As Button
            btnReg.Initialize("btnRegTag")
            btnReg.Tag = s.Get("id")
            btnReg.Text = "🆔"
            btnReg.TextSize = 14
            btnReg.Color = Colors.DarkGray
            p.AddView(btnReg, 75%x, 70dip, 20%x, 35dip)
        End If
        
        Dim line As Panel
        line.Initialize("")
        line.Color = Colors.LightGray
        p.AddView(line, 0, itemHeight - 1dip, 100%x, 1dip)
    Next
End Sub

Sub btnAction_Click
    Dim btn As Button = Sender
    Dim data As Map = btn.Tag
    Dim studentId As Int = data.Get("id")
    Dim action As String = data.Get("action")
    
    Dim payload As Map
    payload.Initialize
    payload.Put("student_id", studentId)
    payload.Put("action", action)
    
    Dim json As JSONGenerator
    json.Initialize(payload)
    
    Dim job As HttpJob
    job.Initialize("mark_attendance", Me)
    job.PostString(APIModule.ServerURL & "/mark_attendance.php", json.ToString)
    APIModule.SetAuthHeader(job, APIModule.GetToken)
    
    btn.Enabled = False
    btn.Text = "..."
End Sub

Sub btnRegTag_Click
	Dim btn As Button = Sender
	RegistrationTargetID = btn.Tag
	
    ' Reset and Show Modal
    lblScanStatus.Text = "Please tap the card against the back of your phone..."
    lblScanStatus.TextColor = Colors.LightGray
    pnlTagScan.Visible = True
End Sub

Sub UpdateUI
    If TrackingService.IsTracking Then
        btnToggle.Text = "STOP TRACKING"
        btnToggle.Color = Colors.RGB(244, 67, 54)
        lblStatus.Text = "Status: TRACKING"
        lblStatus.TextColor = Colors.RGB(76, 175, 80)
    Else
        btnToggle.Text = "START TRACKING"
        btnToggle.Color = Colors.RGB(76, 175, 80)
        lblStatus.Text = "Status: IDLE"
        lblStatus.TextColor = Colors.Red
    End If
End Sub

Sub nfc_TagDiscovered (TagId() As Byte, Intent As Intent)
    ' This may still fire on some devices, so we route it to the same logic
    ProcessNFCTag(Intent)
End Sub
Sub JobDone(Job As HttpJob)
    ' Existing JobDone logic...
    If Job.Success Then
        If Job.JobName = "mark_attendance_nfc" Then
            Try
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                If root.Get("success") = True Then
                    Dim sName As String = root.Get("student_name")
                    Dim action As String = root.Get("action")
                    ToastMessageShow("TAP SUCCESS: " & sName & " " & action, True)
                    
                    ' If attendance panel is open, refresh it
                    If pnlAttendance.Visible Then FetchStudents
                Else
                    ToastMessageShow("TAP ERROR: " & root.Get("error"), True)
                End If
            Catch
                Log("NFC Parse Error: " & LastException)
            End Try
        Else If Job.JobName = "register_tag" Then
            Try
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                If root.Get("success") = True Then
                    ToastMessageShow("SUCCESS: Tag Assigned!", True)
                    pnlTagScan.Visible = False ' Close modal on success
                    FetchStudents
                Else
                    ToastMessageShow("REG ERROR: " & root.Get("error"), True)
                    ' Keep modal open but show error
                    lblScanStatus.Text = "ERROR: " & root.Get("error")
                    lblScanStatus.TextColor = Colors.Red
                End If
            Catch
                Log("Reg Parse Error: " & LastException)
                Log("Server raw response: " & Job.GetString)
            End Try
        Else If Job.JobName = "login" Then
            ' ... (moved login logic to helper or just kept here if few)
            Try
                Log("Login response: " & Job.GetString)
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                
                If root.ContainsKey("success") And True = root.Get("success") Then
                    If root.ContainsKey("api_key") Then
                        Dim apiKey As String = root.Get("api_key")
                        APIModule.SaveToken(apiKey)
                    End If
                    
                    If root.ContainsKey("driver") Then
                        Dim driver As Map = root.Get("driver")
                        If driver.ContainsKey("name") Then
                            Dim driverName As String = driver.Get("name")
                            lblDriverInfo.Text = "Welcome, " & driverName
                        End If
                    End If
                    
                    ToastMessageShow("Login successful", False)
                    ShowTracking
                Else
                    Dim errorMsg As String = "Login failed"
                    If root.ContainsKey("error") Then
                        errorMsg = root.Get("error")
                    End If
                    ToastMessageShow("Error: " & errorMsg, True)
                    btnLogin.Enabled = True
                    btnLogin.Text = "LOGIN"
                End If
            Catch
                Log("Login error: " & LastException)
                ToastMessageShow("Login failed: Invalid response", True)
                btnLogin.Enabled = True
                btnLogin.Text = "LOGIN"
            End Try
        Else if Job.JobName = "fetch_students" Then
            Try
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                If root.Get("success") = True Then
                    UpdateStudentList(root.Get("students"))
                End If
            Catch
                Log("Fetch error: " & LastException)
            End Try
        Else if Job.JobName = "mark_attendance" Then
             Try
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                If root.Get("success") = True Then
                    ToastMessageShow("Success: Student " & root.Get("action"), False)
                    FetchStudents ' Refresh list
                Else
                    ToastMessageShow("Failed to update status", True)
                    FetchStudents ' Reset UI
                End If
            Catch
                Log("Mark error: " & LastException)
            End Try
        Else if Job.JobName = "get_routes" Then
            If Job.Success Then
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                
                If root.Get("success") = True Then
                    lvRoutes.Clear
                    Dim routes As List = root.Get("routes")
                    
                    For Each colRoute As Map In routes
                        Dim routeName As String = colRoute.Get("route_name")
                        Dim shift As String = colRoute.Get("shift")
                        Dim studentCount As Int = colRoute.Get("student_count")
                        
                        Dim secondLine As String = shift.ToUpperCase & " • " & studentCount & " students"
                        lvRoutes.AddTwoLines2(routeName, secondLine, colRoute)
                    Next
                    
                    If routes.Size = 0 Then
                        ToastMessageShow("No routes available", False)
                    End If
                Else
                    ToastMessageShow("Error loading routes", False)
                End If
            End If
        Else if Job.JobName = "set_active_route" Then
            If Job.Success Then
                Dim parser As JSONParser
                parser.Initialize(Job.GetString)
                Dim root As Map = parser.NextObject
                
                If root.Get("success") = True Then
                    ToastMessageShow("Route selected: " & ActiveRouteName, True)
                    ShowTracking
                    FetchStudents ' Reload students for this route
                Else
                    ToastMessageShow("Error setting route", False)
                End If
            End If
        End If
    Else
        ToastMessageShow("Network error: " & Job.ErrorMessage, True)
        btnLogin.Enabled = True
        btnLogin.Text = "LOGIN"
    End If
    Job.Release
End Sub

' ============================================
' ROUTE SELECTION FUNCTIONS
' ============================================

Sub LoadRoutes
    ' Fetch available routes from server
    Dim job As HttpJob
    job.Initialize("get_routes", Me)
    job.Download(APIModule.ServerURL & "/get_routes.php")
    APIModule.SetAuthHeader(job, APIModule.GetToken)
End Sub

Sub btnRefreshRoutes_Click
    LoadRoutes
End Sub

Sub lvRoutes_ItemClick (Position As Int, Value As Object)
    ' Get selected route
    Dim routeData As Map = Value
    Dim routeId As Int = routeData.Get("id")
    Dim routeName As String = routeData.Get("route_name")
    
    ' Set active route on server
    SetActiveRoute(routeId, routeName)
End Sub

Sub SetActiveRoute(routeId As Int, routeName As String)
    ' Send to server
    Dim payload As Map
    payload.Initialize
    payload.Put("route_id", routeId)
    
    Dim gen As JSONGenerator
    gen.Initialize(payload)
    
    Dim job As HttpJob
    job.Initialize("set_active_route", Me)
    job.PostString(APIModule.ServerURL & "/set_active_route.php", gen.ToString)
    APIModule.SetAuthHeader(job, APIModule.GetToken)
    
    ' Store locally
    ActiveRouteID = routeId
    ActiveRouteName = routeName
End Sub

