package mx.trackermap.TrackerMap.android.details.reports import android.util.Log import androidx.lifecycle.* import kotlinx.coroutines.DelicateCoroutinesApi import java.text.SimpleDateFormat import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import mx.trackermap.TrackerMap.client.apis.ReportsApi import mx.trackermap.TrackerMap.client.models.* import mx.trackermap.TrackerMap.controllers.GeofencesController import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.util.* import java.util.Calendar @DelicateCoroutinesApi class UnitReportsViewModel( private val reportsApi: ReportsApi, savedStateHandle: SavedStateHandle ) : ViewModel(), KoinComponent { sealed class Report { class PositionsReport(val positions: Array) : Report() class EventsReport(val events: Array) : Report() class StopsReport(val stops: Array) : Report() object LoadingReport: Report() } enum class ReportType { POSITIONS, EVENTS, STOPS } enum class ReportPeriod { DAY, WEEK, MONTH } private val geofenceController: GeofencesController by inject() private var _deviceId = savedStateHandle.getLiveData("deviceId", 0) private val _reportType: MutableLiveData = savedStateHandle.getLiveData("reportType", null) private val _reportPeriod: MutableLiveData = savedStateHandle.getLiveData("reportPeriod", null) private val _report: MutableLiveData = MutableLiveData() private val _reportFile: MutableLiveData = MutableLiveData() private val _geofences: MutableLiveData> = MutableLiveData() val deviceId: LiveData get() = _deviceId val reportType: LiveData get() = _reportType val reportPeriod: LiveData get() = _reportPeriod val report: LiveData get() = _report val reportFile: LiveData get() = _reportFile val geofences: LiveData> get() = _geofences private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()) init { viewModelScope.launch { setupTypeObserver() } viewModelScope.launch { setupPeriodObserver() } viewModelScope.launch { setupGeofenceObserver() } } private suspend fun setupTypeObserver() { _reportType.asFlow().collect { fetchReport() } } private suspend fun setupPeriodObserver() { _reportPeriod.asFlow().collect { fetchReport() } } private suspend fun setupGeofenceObserver() { geofenceController.geofencesFlow.collect { _geofences.postValue(it) } } fun setDeviceId (id: Int) { _deviceId.value = id } fun setReportType(reportType: ReportType) { _reportType.value = reportType } fun setReportPeriod(reportPeriod: ReportPeriod) { _reportPeriod.value = reportPeriod } fun getGeofence(id: Int): Geofence? = _geofences.value?.get(id) private fun getDates(): Pair { val calendar = Calendar.getInstance() val currentDate = calendar.time calendar.add( Calendar.DATE, when (_reportPeriod.value!!) { ReportPeriod.DAY -> -1 ReportPeriod.WEEK -> -7 ReportPeriod.MONTH -> -30 } ) val previousDate = calendar.time return Pair(currentDate, previousDate) } fun fetchReportXlsx() { fetchReport(true) } private fun fetchReport(xlsx: Boolean = false) { if (_reportType.value == null || _reportPeriod.value == null) { return } val (currentDate, previousDate) = getDates() Log.d("UnitReportsVM", "Current report type: ${_reportType.value.toString()}") Log.d("UnitReportsVM", "Current report period: ${_reportPeriod.value.toString()}") Log.d("UnitReportsVM", "Current date:${dateFormat.format(currentDate)}") Log.d("UnitReportsVM", "Previous date:${dateFormat.format(previousDate)}") if (!xlsx) { _report.postValue(Report.LoadingReport) } viewModelScope.launch { when (_reportType.value!!) { ReportType.POSITIONS -> fetchPositions(previousDate, currentDate, xlsx) ReportType.EVENTS -> fetchEvents(previousDate, currentDate, xlsx) ReportType.STOPS -> fetchStops(previousDate, currentDate, xlsx) } } } private suspend fun fetchPositions(from: Date, to: Date, xlsx: Boolean) { Log.d("UnitReportsVM", "Fetching positions") if (!xlsx) { val result = reportsApi.reportsRouteGet( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) Log.d("UnitReportsVM", "Positions report: $result") _report.postValue(Report.PositionsReport(result)) } else { val result = reportsApi.reportsRouteGetXlsx( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) Log.d("UnitReportsVM", "Positions report: $result") _reportFile.postValue(result) } } private suspend fun fetchEvents(from: Date, to: Date, xlsx: Boolean) { Log.d("UnitReportsVM", "Fetching events") if (!xlsx) { val positionsResult = reportsApi.reportsRouteGet( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) val eventsResult = reportsApi.reportsEventsGet( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) val result = mutableListOf() eventsResult.forEach { event -> result.add(EventInformation( event = event, position = positionsResult.find { it.id == event.positionId } )) } Log.d("UnitReportsVM", "Events report: $result") _report.postValue(Report.EventsReport(result.toTypedArray())) } else { val result = reportsApi.reportsEventsGetXlsx( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) Log.d("UnitReportsVM", "Events report: $result") _reportFile.postValue(result) } } private suspend fun fetchStops(from: Date, to: Date, xlsx: Boolean) { Log.d("UnitReportsVM", "Fetching stops") if (!xlsx) { val result = reportsApi.reportsStopsGet( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) Log.d("UnitReportsVM", "Stops report: $result") _report.postValue(Report.StopsReport(result)) } else { val result = reportsApi.reportsStopsGetXlsx( dateFormat.format(from), dateFormat.format(to), _deviceId.value!! ) Log.d("UnitReportsVM", "Stops report: $result") _reportFile.postValue(result) } } }