|
1 | 1 | package com.guizmaii.distances.implementations.google.distanceapi
|
2 | 2 |
|
3 |
| -import com.google.maps.DistanceMatrixApi |
| 3 | +import cats._ |
| 4 | +import cats.data._ |
| 5 | +import cats.implicits._ |
| 6 | +import com.google.maps.DirectionsApi.RouteRestriction |
| 7 | +import com.google.maps.{DistanceMatrixApi, DistanceMatrixApiRequest} |
| 8 | +import com.google.maps.model.{TrafficModel, TransitMode, Unit => GoogleDistanceUnit} |
4 | 9 | import com.guizmaii.distances.Types._
|
5 | 10 | import com.guizmaii.distances.implementations.cache.GeoCache
|
6 | 11 | import com.guizmaii.distances.implementations.google.GoogleGeoApiContext
|
7 | 12 | import com.guizmaii.distances.{DistanceApi, Geocoder}
|
8 | 13 | import monix.eval.Task
|
9 | 14 | import monix.execution.CancelableFuture
|
10 | 15 |
|
11 |
| -import scala.collection.immutable.Seq |
12 |
| - |
13 | 16 | final class GoogleDistanceApi(
|
14 | 17 | geoApiContext: GoogleGeoApiContext,
|
15 |
| - override protected val alternativeCache: Option[GeoCache[SerializableDistance]] = None |
| 18 | + override protected val alternativeCache: Option[GeoCache[(TravelMode, SerializableDistance)]] = None |
16 | 19 | ) extends DistanceApi {
|
17 | 20 |
|
18 | 21 | import com.guizmaii.distances.utils.MonixSchedulers.AlwaysAsyncForkJoinScheduler._
|
19 | 22 | import com.guizmaii.distances.utils.RichImplicits._
|
20 | 23 |
|
21 |
| - private def toGoogleRepresentation(latLong: LatLong): String = s"${latLong.latitude},${latLong.longitude}" |
| 24 | +// |
| 25 | + //override def distanceFromPostalCodesT(geocoder: Geocoder)( |
| 26 | + // origin: PostalCode, |
| 27 | + // destination: PostalCode |
| 28 | + //): Task[Distance] = |
| 29 | + // if (origin == destination) Task.now(Distance.zero) |
| 30 | + // else Task.zip2(geocoder.geocodeT(origin), geocoder.geocodeT(destination)).flatMap((distanceT _).tupled) |
| 31 | +// |
| 32 | + //override def distance(origin: LatLong, destination: LatLong): CancelableFuture[Distance] = |
| 33 | + // distanceT(origin, destination).runAsync |
| 34 | +// |
| 35 | + //override def distanceFromPostalCodes(geocoder: Geocoder)( |
| 36 | + // origin: PostalCode, |
| 37 | + // destination: PostalCode |
| 38 | + //): CancelableFuture[Distance] = distanceFromPostalCodesT(geocoder)(origin, destination).runAsync |
| 39 | +// |
| 40 | + //override def distancesT(paths: Seq[DirectedPath]): Task[Seq[DirectedPathWithDistance]] = Task.sequence { |
| 41 | + // paths.map { |
| 42 | + // case (origin, destination) => |
| 43 | + // if (origin == destination) Task.now((origin, destination, Distance.zero)) |
| 44 | + // else distanceT(origin, destination).map(distance => (origin, destination, distance)) |
| 45 | + // } |
| 46 | + //} |
| 47 | +// |
| 48 | + //override def distances(paths: Seq[DirectedPath]): CancelableFuture[Seq[DirectedPathWithDistance]] = |
| 49 | + // distancesT(paths).runAsync |
| 50 | + |
| 51 | + import TravelMode._ |
22 | 52 |
|
23 |
| - override def distanceT(origin: LatLong, destination: LatLong): Task[Distance] = { |
24 |
| - def fetch: Task[SerializableDistance] = |
| 53 | + override def distanceT( |
| 54 | + origin: LatLong, |
| 55 | + destination: LatLong, |
| 56 | + travelModes: List[TravelMode] = List(TravelMode.Driving) |
| 57 | + ): Task[Map[TravelMode, Distance]] = { |
| 58 | + def fetch(mode: TravelMode): Task[(TravelMode, SerializableDistance)] = |
25 | 59 | DistanceMatrixApi
|
26 |
| - .getDistanceMatrix( |
27 |
| - geoApiContext.geoApiContext, |
28 |
| - Array(toGoogleRepresentation(origin)), |
29 |
| - Array(toGoogleRepresentation(destination)) |
30 |
| - ) |
| 60 | + .newRequest(geoApiContext.geoApiContext) |
| 61 | + .mode(mode.toGoogleTravelMode) |
| 62 | + .origins(origin.toGoogleLatLng) |
| 63 | + .destinations(destination.toGoogleLatLng) |
| 64 | + .units(GoogleDistanceUnit.METRIC) |
31 | 65 | .toTask
|
32 |
| - .map(_.rows.head.elements.head.asSerializableDistance) |
| 66 | + .map(res => mode -> res.rows.head.elements.head.asSerializableDistance) |
| 67 | + |
| 68 | + def fetchAndCache(mode: TravelMode): Task[(TravelMode, Distance)] = { |
| 69 | + val key = (mode, origin, destination) |
| 70 | + cache.getOrTask(key)(fetch(mode)).map { case (m, serializableDistance) => m -> Distance.apply(serializableDistance) } |
| 71 | + } |
33 | 72 |
|
34 |
| - val key = origin -> destination |
35 |
| - cache |
36 |
| - .getOrTask(key)(fetch) |
37 |
| - .map(Distance.apply) |
| 73 | + if (origin == destination) Task.now(travelModes.map(_ -> Distance.zero).toMap) |
| 74 | + else travelModes.map(fetchAndCache).sequence.map(_.toMap) |
38 | 75 | }
|
39 | 76 |
|
| 77 | + override def distance( |
| 78 | + origin: LatLong, |
| 79 | + destination: LatLong, |
| 80 | + travelModes: List[TravelMode] = List(TravelMode.Driving) |
| 81 | + ): CancelableFuture[Map[TravelMode, Distance]] = distanceT(origin, destination, travelModes).runAsync |
| 82 | + |
40 | 83 | override def distanceFromPostalCodesT(geocoder: Geocoder)(
|
41 | 84 | origin: PostalCode,
|
42 |
| - destination: PostalCode |
43 |
| - ): Task[Distance] = |
44 |
| - if (origin == destination) Task.now(Distance.zero) |
45 |
| - else Task.zip2(geocoder.geocodeT(origin), geocoder.geocodeT(destination)).flatMap((distanceT _).tupled) |
46 |
| - |
47 |
| - override def distance(origin: LatLong, destination: LatLong): CancelableFuture[Distance] = |
48 |
| - distanceT(origin, destination).runAsync |
| 85 | + destination: PostalCode, |
| 86 | + travelModes: List[TravelMode] = List(TravelMode.Driving) |
| 87 | + ): Task[Map[TravelMode, Distance]] = { |
| 88 | + if (origin == destination) Task.now(travelModes.map(_ -> Distance.zero).toMap) |
| 89 | + else |
| 90 | + Task |
| 91 | + .zip2(geocoder.geocodeT(origin), geocoder.geocodeT(destination)) |
| 92 | + .flatMap { case (o, d) => distanceT(o, d, travelModes) } |
| 93 | + } |
49 | 94 |
|
50 | 95 | override def distanceFromPostalCodes(geocoder: Geocoder)(
|
51 | 96 | origin: PostalCode,
|
52 |
| - destination: PostalCode |
53 |
| - ): CancelableFuture[Distance] = distanceFromPostalCodesT(geocoder)(origin, destination).runAsync |
54 |
| - |
55 |
| - override def distancesT(paths: Seq[DirectedPath]): Task[Seq[DirectedPathWithDistance]] = Task.sequence { |
56 |
| - paths.map { |
57 |
| - case (origin, destination) => |
58 |
| - if (origin == destination) Task.now((origin, destination, Distance.zero)) |
59 |
| - else distanceT(origin, destination).map(distance => (origin, destination, distance)) |
| 97 | + destination: PostalCode, |
| 98 | + travelModes: List[TravelMode] = List(TravelMode.Driving) |
| 99 | + ): CancelableFuture[Map[TravelMode, Distance]] = |
| 100 | + distanceFromPostalCodesT(geocoder)(origin, destination, travelModes).runAsync |
| 101 | + |
| 102 | + override def distancesT(paths: List[DirectedPath]): Task[Map[(TravelMode, LatLong, LatLong), Distance]] = { |
| 103 | + //def fetch(mode: TravelMode): Task[(TravelMode, SerializableDistance)] = |
| 104 | + // DistanceMatrixApi |
| 105 | + // .newRequest(geoApiContext.geoApiContext) |
| 106 | + // .mode(mode.toGoogleTravelMode) |
| 107 | + // .origins(origin.toGoogleLatLng) |
| 108 | + // .destinations(destination.toGoogleLatLng) |
| 109 | + // .units(GoogleDistanceUnit.METRIC) |
| 110 | + // .toTask |
| 111 | + // .map(res => mode -> res.rows.head.elements.head.asSerializableDistance) |
| 112 | + |
| 113 | + def fetchAndCache(mode: TravelMode): Task[(TravelMode, Distance)] = { |
| 114 | + val key = (mode, origin, destination) |
| 115 | + cache.getOrTask(key)(fetch(mode)).map { case (m, serializableDistance) => m -> Distance.apply(serializableDistance) } |
60 | 116 | }
|
| 117 | + |
| 118 | + paths |
| 119 | + .distinctBy { case (origin, destination, t) => DirectedPath(origin, destination, t) } |
| 120 | + .map { |
| 121 | + case DirectedPath(origin, destination, travelModes) => |
| 122 | + if (origin == destination) Task.now(travelModes.map(mode => (mode, origin, destination) -> Distance.zero).toMap) |
| 123 | + else {} |
| 124 | + } |
| 125 | + |
| 126 | + ??? |
| 127 | + |
61 | 128 | }
|
62 | 129 |
|
63 |
| - override def distances(paths: Seq[DirectedPath]): CancelableFuture[Seq[DirectedPathWithDistance]] = |
64 |
| - distancesT(paths).runAsync |
| 130 | + override def distances(paths: List[DirectedPath]): CancelableFuture[Map[(TravelMode, LatLong, LatLong), Distance]] = ??? |
65 | 131 |
|
66 | 132 | }
|
67 | 133 |
|
68 | 134 | object GoogleDistanceApi {
|
69 | 135 | def apply(geoApiContext: GoogleGeoApiContext): GoogleDistanceApi = new GoogleDistanceApi(geoApiContext)
|
70 | 136 |
|
71 |
| - def apply(geoApiContext: GoogleGeoApiContext, geoCache: GeoCache[SerializableDistance]): GoogleDistanceApi = |
| 137 | + def apply(geoApiContext: GoogleGeoApiContext, geoCache: GeoCache[(TravelMode, SerializableDistance)]): GoogleDistanceApi = |
72 | 138 | new GoogleDistanceApi(geoApiContext, Some(geoCache))
|
73 | 139 | }
|
0 commit comments