From b5cc580cf81c2ee294fcf1cd82209de90cd6d592 Mon Sep 17 00:00:00 2001
From: Piotr Dec <piotr_dec@msn.com>
Date: Fri, 25 Aug 2023 08:25:06 +0200
Subject: [PATCH] Data cache

---
 app/src/main/java/eu/ztsh/garmin/Garmin.kt    | 34 +++++-----
 .../main/java/eu/ztsh/garmin/MapboxToolbox.kt | 24 ++++++-
 .../java/eu/ztsh/garmin/data/DataCache.kt     | 66 ++++++++++++++++++
 .../eu/ztsh/garmin/data/ManeuverMapper.kt     | 26 ++++---
 .../main/java/eu/ztsh/garmin/data/Model.kt    | 68 +++++++++++++++----
 5 files changed, 178 insertions(+), 40 deletions(-)
 create mode 100644 app/src/main/java/eu/ztsh/garmin/data/DataCache.kt

diff --git a/app/src/main/java/eu/ztsh/garmin/Garmin.kt b/app/src/main/java/eu/ztsh/garmin/Garmin.kt
index d6b3113..e9836d5 100644
--- a/app/src/main/java/eu/ztsh/garmin/Garmin.kt
+++ b/app/src/main/java/eu/ztsh/garmin/Garmin.kt
@@ -6,17 +6,13 @@ import android.bluetooth.BluetoothDevice
 import android.bluetooth.BluetoothSocket
 import android.util.Log
 import com.mapbox.navigation.ui.maneuver.model.Maneuver
-import eu.ztsh.garmin.data.Direction
+import eu.ztsh.garmin.data.DataCache
 import eu.ztsh.garmin.data.GarminMapper
 import eu.ztsh.garmin.data.ManeuverMapper
-import eu.ztsh.garmin.data.OutAngle
-import eu.ztsh.garmin.data.OutType
-import eu.ztsh.garmin.data.State
 import java.io.IOException
 import java.util.*
 import java.util.concurrent.SynchronousQueue
 
-
 @SuppressLint("MissingPermission")
 class Garmin(
     val context: MainActivity,
@@ -26,7 +22,7 @@ class Garmin(
 
     private lateinit var connection: ConnectThread
     private lateinit var processing: ProcessingThread
-    private var stateCache: State = State()
+    private val cache = DataCache()
 
     fun start() {
         connection = ConnectThread()
@@ -46,22 +42,24 @@ class Garmin(
 
 
     private inner class ProcessingThread(val maneuver: Maneuver) : Thread() {
+
         override fun run() {
-            // TODO: check for equality before mapping!
-            send(ManeuverMapper.apply(maneuver))
+            if (cache.hasChanged(maneuver)) {
+                cache.update(maneuver)
+                send(ManeuverMapper.apply(maneuver))
+            }
         }
 
         fun send(incoming: eu.ztsh.garmin.data.State) {
-            if (stateCache.distance != incoming.distance) {
+            if (cache.hasChanged(incoming.distance)) {
                 setDistance(incoming)
             }
-            if (stateCache.direction != incoming.direction) {
-                setDirection(stateCache)
+            if (cache.hasChanged(incoming.direction)) {
+                setDirection(incoming)
             }
-            stateCache = incoming
+            cache.update(incoming)
         }
 
-
         private fun setLines(state: eu.ztsh.garmin.data.State) {
 
         }
@@ -94,10 +92,13 @@ class Garmin(
             sleep(3000)
             readAll()
             while (true) {
-                val newCurrent = Optional.ofNullable(queue.poll()).orElse(current)
-                current = newCurrent
+                val newCurrent = queue.poll()
+                if (newCurrent == null) {
+                    sleep(500)
+                } else {
+                    current = newCurrent
+                }
                 send(current)
-                sleep(900)
             }
         }
 
@@ -138,6 +139,7 @@ class Garmin(
     }
 
     companion object {
+
         fun prepareData(input: IntArray): IntArray {
             val n = input.size
             var crc = (0xeb + n + n).toUInt()
diff --git a/app/src/main/java/eu/ztsh/garmin/MapboxToolbox.kt b/app/src/main/java/eu/ztsh/garmin/MapboxToolbox.kt
index 7afeffe..8711206 100644
--- a/app/src/main/java/eu/ztsh/garmin/MapboxToolbox.kt
+++ b/app/src/main/java/eu/ztsh/garmin/MapboxToolbox.kt
@@ -1,6 +1,8 @@
 package eu.ztsh.garmin
 
 import android.annotation.SuppressLint
+import android.location.Location
+import android.util.Log
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
@@ -8,6 +10,8 @@ import com.mapbox.navigation.base.formatter.DistanceFormatterOptions
 import com.mapbox.navigation.base.options.NavigationOptions
 import com.mapbox.navigation.core.formatter.MapboxDistanceFormatter
 import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
+import com.mapbox.navigation.core.trip.session.LocationMatcherResult
+import com.mapbox.navigation.core.trip.session.LocationObserver
 import com.mapbox.navigation.core.trip.session.RouteProgressObserver
 import com.mapbox.navigation.ui.maneuver.api.MapboxManeuverApi
 
@@ -43,10 +47,13 @@ class MapboxToolbox(lifecycle: Lifecycle, private val context: MainActivity) {
 
     fun onStart() {
         MapboxNavigationApp.current()?.registerRouteProgressObserver(routeProgressObserver)
+        MapboxNavigationApp.current()?.registerLocationObserver(locationObserver)
+//        MapboxNavigationApp.current()?.registerNavigationSessionStateObserver()
     }
 
     fun onStop() {
         MapboxNavigationApp.current()?.unregisterRouteProgressObserver(routeProgressObserver)
+        MapboxNavigationApp.current()?.unregisterLocationObserver(locationObserver)
     }
 
     fun onDestroy() {
@@ -64,6 +71,21 @@ class MapboxToolbox(lifecycle: Lifecycle, private val context: MainActivity) {
     }
 
     private val routeProgressObserver =
-        RouteProgressObserver { routeProgress -> maneuverApi.getManeuvers(routeProgress).value?.apply { context.garmin.process(this[0]) } }
+        RouteProgressObserver { routeProgress ->
+            maneuverApi.getManeuvers(routeProgress).value?.apply {
+                context.garmin.process(
+                    this[0]
+                )
+            }
+        }
+
+    private val locationObserver = object : LocationObserver {
+        override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
+            Log.d("LOCATION", "")
+        }
+
+        override fun onNewRawLocation(rawLocation: Location) {
+        }
+    }
 
 }
\ No newline at end of file
diff --git a/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt b/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt
new file mode 100644
index 0000000..1b7eb16
--- /dev/null
+++ b/app/src/main/java/eu/ztsh/garmin/data/DataCache.kt
@@ -0,0 +1,66 @@
+package eu.ztsh.garmin.data
+
+import com.mapbox.navigation.ui.maneuver.model.Maneuver
+
+class DataCache {
+
+    private val stateCache: State = State()
+    private var maneuverCache: Maneuver? = null
+
+    // state
+    fun hasChanged(lanes: Lanes?): Boolean {
+        return stateCache.lineArrows == null || stateCache.lineArrows != lanes
+    }
+
+    fun hasChanged(outlines: Outlines?): Boolean {
+        return stateCache.lineOutlines == null || stateCache.lineOutlines != outlines
+    }
+
+    fun hasChanged(distance: Distance?): Boolean {
+        return stateCache.distance == null || stateCache.distance != distance
+    }
+
+    fun hasChanged(direction: Direction?): Boolean {
+        return stateCache.direction == null || stateCache.direction != direction
+    }
+
+    fun hasChanged(speed: Speed?): Boolean {
+        return stateCache.speed == null || stateCache.speed != speed
+    }
+
+    fun hasChanged(arrival: Arrival?): Boolean {
+        return stateCache.arrival == null || stateCache.arrival != arrival
+    }
+
+    // Merge states
+    fun update(state: State) {
+        if (state.lineArrows != null) {
+            stateCache.lineArrows = state.lineArrows
+        }
+        if (state.lineOutlines != null) {
+            state.lineOutlines = state.lineOutlines
+        }
+        if (state.direction != null) {
+            stateCache.direction = state.direction
+        }
+        if (state.distance != null) {
+            stateCache.distance = state.distance
+        }
+        if (state.speed != null) {
+            stateCache.speed = state.speed
+        }
+        if (state.arrival != null) {
+            stateCache.arrival = state.arrival
+        }
+    }
+
+    // maneuver
+    fun hasChanged(maneuver: Maneuver): Boolean {
+        return maneuverCache == null || maneuverCache!! != maneuver
+    }
+
+    fun update(maneuver: Maneuver) {
+        maneuverCache = maneuver
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/ztsh/garmin/data/ManeuverMapper.kt b/app/src/main/java/eu/ztsh/garmin/data/ManeuverMapper.kt
index 89f1996..fe75879 100644
--- a/app/src/main/java/eu/ztsh/garmin/data/ManeuverMapper.kt
+++ b/app/src/main/java/eu/ztsh/garmin/data/ManeuverMapper.kt
@@ -10,10 +10,12 @@ class ManeuverMapper {
             val state = State()
             maneuver.apply {
                 this.primary.apply {
+                    state.direction = Direction()
                     when (this.type) {
                         "roundabout" -> {
-                            state.direction.out = OutType.RightRoundabout
+                            state.direction!!.out = OutType.RightRoundabout
                         }
+
                         "arrive" -> {
                             state.flag = true
                         }
@@ -21,17 +23,18 @@ class ManeuverMapper {
                     when (this.modifier) {
                         "right" -> {
                             when (this.type) {
-                                "turn" -> state.direction.angle = OutAngle.Right
+                                "turn" -> state.direction!!.angle = OutAngle.Right
                                 "roundabout" -> {
                                     when (this.degrees) {
-                                        137.0 -> state.direction.angle = OutAngle.EasyRight
+                                        137.0 -> state.direction!!.angle = OutAngle.EasyRight
                                     }
                                 }
                             }
                         }
+
                         "left" -> {
                             when (this.type) {
-                                "turn" -> state.direction.angle = OutAngle.Left
+                                "turn" -> state.direction!!.angle = OutAngle.Left
                             }
                         }
                     }
@@ -39,13 +42,14 @@ class ManeuverMapper {
                 this.stepDistance.apply {
                     this.distanceRemaining?.apply {
                         distanceFormatter.formatDistance(distanceRemaining!!).split(" ").apply {
-                            state.distance = this[0].toInt()
-                            state.unit = when (this[1]) {
-                                "m" -> Unit.Metres
-                                "km" -> Unit.Kilometres
-                                else -> {
-                                    Unit.Any}
-                            }
+                            state.distance = Distance(
+                                this[0].toInt(),
+                                when (this[1]) {
+                                    "m" -> Unit.Metres
+                                    "km" -> Unit.Kilometres
+                                    else -> Unit.Any
+                                }
+                            )
 
                         }
                     }
diff --git a/app/src/main/java/eu/ztsh/garmin/data/Model.kt b/app/src/main/java/eu/ztsh/garmin/data/Model.kt
index 9092bbb..e4a8262 100644
--- a/app/src/main/java/eu/ztsh/garmin/data/Model.kt
+++ b/app/src/main/java/eu/ztsh/garmin/data/Model.kt
@@ -52,20 +52,64 @@ enum class Lane(val value: Int) {
 
 }
 
+open class Arrows(val lanes: List<Lane>) {
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as Arrows
+
+        return lanes == other.lanes
+    }
+
+    override fun hashCode(): Int {
+        return lanes.hashCode()
+    }
+}
+
+class Lanes(lanes: List<Lane>) : Arrows(lanes)
+
+class Outlines(lanes: List<Lane>) : Arrows(lanes)
+
+class Distance(val distance: Int, val unit: Unit) {
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as Distance
+
+        if (distance != other.distance) return false
+        if (unit != other.unit) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = distance
+        result = 31 * result + unit.hashCode()
+        return result
+    }
+
+}
+
+class Speed(val speed: Int, val limit: Int)
+
+class Arrival(val hours: Int, val minutes: Int)
+
 class State {
 
-    var lineArrows: List<Lane> = listOf()
-    var lineOutlines: List<Lane> = listOf()
-    var direction = Direction()
-    var distance: Int = 0
-    var unit: Unit = Unit.Any
-    var speed: Int = 0
-    var limit: Int = 0
-    var hours: Int = 0
-    var minutes: Int = 0
-    var traffic: Boolean = false
-    var flag: Boolean = false
-    var control: Boolean = false
+    var lineArrows: Lanes? = null
+    var lineOutlines: Outlines? = null
+    var direction : Direction? = null
+    var distance: Distance? = null
+    var speed: Speed? = null
+    var arrival: Arrival? = null
+    // TODO: support
+    var traffic: Boolean? = null
+    var flag: Boolean? = null
+    var control: Boolean? = null
 
 }