OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / go-kit / kit / examples / shipping / cargo / delivery.go
1 package cargo
2
3 import (
4         "time"
5
6         "github.com/go-kit/kit/examples/shipping/location"
7         "github.com/go-kit/kit/examples/shipping/voyage"
8 )
9
10 // Delivery is the actual transportation of the cargo, as opposed to the
11 // customer requirement (RouteSpecification) and the plan (Itinerary).
12 type Delivery struct {
13         Itinerary               Itinerary
14         RouteSpecification      RouteSpecification
15         RoutingStatus           RoutingStatus
16         TransportStatus         TransportStatus
17         NextExpectedActivity    HandlingActivity
18         LastEvent               HandlingEvent
19         LastKnownLocation       location.UNLocode
20         CurrentVoyage           voyage.Number
21         ETA                     time.Time
22         IsMisdirected           bool
23         IsUnloadedAtDestination bool
24 }
25
26 // UpdateOnRouting creates a new delivery snapshot to reflect changes in
27 // routing, i.e. when the route specification or the itinerary has changed but
28 // no additional handling of the cargo has been performed.
29 func (d Delivery) UpdateOnRouting(rs RouteSpecification, itinerary Itinerary) Delivery {
30         return newDelivery(d.LastEvent, itinerary, rs)
31 }
32
33 // IsOnTrack checks if the delivery is on track.
34 func (d Delivery) IsOnTrack() bool {
35         return d.RoutingStatus == Routed && !d.IsMisdirected
36 }
37
38 // DeriveDeliveryFrom creates a new delivery snapshot based on the complete
39 // handling history of a cargo, as well as its route specification and
40 // itinerary.
41 func DeriveDeliveryFrom(rs RouteSpecification, itinerary Itinerary, history HandlingHistory) Delivery {
42         lastEvent, _ := history.MostRecentlyCompletedEvent()
43         return newDelivery(lastEvent, itinerary, rs)
44 }
45
46 // newDelivery creates a up-to-date delivery based on an handling event,
47 // itinerary and a route specification.
48 func newDelivery(lastEvent HandlingEvent, itinerary Itinerary, rs RouteSpecification) Delivery {
49         var (
50                 routingStatus           = calculateRoutingStatus(itinerary, rs)
51                 transportStatus         = calculateTransportStatus(lastEvent)
52                 lastKnownLocation       = calculateLastKnownLocation(lastEvent)
53                 isMisdirected           = calculateMisdirectedStatus(lastEvent, itinerary)
54                 isUnloadedAtDestination = calculateUnloadedAtDestination(lastEvent, rs)
55                 currentVoyage           = calculateCurrentVoyage(transportStatus, lastEvent)
56         )
57
58         d := Delivery{
59                 LastEvent:               lastEvent,
60                 Itinerary:               itinerary,
61                 RouteSpecification:      rs,
62                 RoutingStatus:           routingStatus,
63                 TransportStatus:         transportStatus,
64                 LastKnownLocation:       lastKnownLocation,
65                 IsMisdirected:           isMisdirected,
66                 IsUnloadedAtDestination: isUnloadedAtDestination,
67                 CurrentVoyage:           currentVoyage,
68         }
69
70         d.NextExpectedActivity = calculateNextExpectedActivity(d)
71         d.ETA = calculateETA(d)
72
73         return d
74 }
75
76 // Below are internal functions used when creating a new delivery.
77
78 func calculateRoutingStatus(itinerary Itinerary, rs RouteSpecification) RoutingStatus {
79         if itinerary.Legs == nil {
80                 return NotRouted
81         }
82
83         if rs.IsSatisfiedBy(itinerary) {
84                 return Routed
85         }
86
87         return Misrouted
88 }
89
90 func calculateMisdirectedStatus(event HandlingEvent, itinerary Itinerary) bool {
91         if event.Activity.Type == NotHandled {
92                 return false
93         }
94
95         return !itinerary.IsExpected(event)
96 }
97
98 func calculateUnloadedAtDestination(event HandlingEvent, rs RouteSpecification) bool {
99         if event.Activity.Type == NotHandled {
100                 return false
101         }
102
103         return event.Activity.Type == Unload && rs.Destination == event.Activity.Location
104 }
105
106 func calculateTransportStatus(event HandlingEvent) TransportStatus {
107         switch event.Activity.Type {
108         case NotHandled:
109                 return NotReceived
110         case Load:
111                 return OnboardCarrier
112         case Unload:
113                 return InPort
114         case Receive:
115                 return InPort
116         case Customs:
117                 return InPort
118         case Claim:
119                 return Claimed
120         }
121         return Unknown
122 }
123
124 func calculateLastKnownLocation(event HandlingEvent) location.UNLocode {
125         return event.Activity.Location
126 }
127
128 func calculateNextExpectedActivity(d Delivery) HandlingActivity {
129         if !d.IsOnTrack() {
130                 return HandlingActivity{}
131         }
132
133         switch d.LastEvent.Activity.Type {
134         case NotHandled:
135                 return HandlingActivity{Type: Receive, Location: d.RouteSpecification.Origin}
136         case Receive:
137                 l := d.Itinerary.Legs[0]
138                 return HandlingActivity{Type: Load, Location: l.LoadLocation, VoyageNumber: l.VoyageNumber}
139         case Load:
140                 for _, l := range d.Itinerary.Legs {
141                         if l.LoadLocation == d.LastEvent.Activity.Location {
142                                 return HandlingActivity{Type: Unload, Location: l.UnloadLocation, VoyageNumber: l.VoyageNumber}
143                         }
144                 }
145         case Unload:
146                 for i, l := range d.Itinerary.Legs {
147                         if l.UnloadLocation == d.LastEvent.Activity.Location {
148                                 if i < len(d.Itinerary.Legs)-1 {
149                                         return HandlingActivity{Type: Load, Location: d.Itinerary.Legs[i+1].LoadLocation, VoyageNumber: d.Itinerary.Legs[i+1].VoyageNumber}
150                                 }
151
152                                 return HandlingActivity{Type: Claim, Location: l.UnloadLocation}
153                         }
154                 }
155         }
156
157         return HandlingActivity{}
158 }
159
160 func calculateCurrentVoyage(transportStatus TransportStatus, event HandlingEvent) voyage.Number {
161         if transportStatus == OnboardCarrier && event.Activity.Type != NotHandled {
162                 return event.Activity.VoyageNumber
163         }
164
165         return voyage.Number("")
166 }
167
168 func calculateETA(d Delivery) time.Time {
169         if !d.IsOnTrack() {
170                 return time.Time{}
171         }
172
173         return d.Itinerary.FinalArrivalTime()
174 }