001package org.matsim.contrib.carsharing.manager;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.matsim.api.core.v01.Id;
007import org.matsim.api.core.v01.network.Link;
008import org.matsim.api.core.v01.network.Network;
009import org.matsim.api.core.v01.population.Activity;
010import org.matsim.api.core.v01.population.Leg;
011import org.matsim.api.core.v01.population.Person;
012import org.matsim.api.core.v01.population.Plan;
013import org.matsim.api.core.v01.population.PlanElement;
014import org.matsim.contrib.carsharing.events.NoVehicleCarSharingEvent;
015import org.matsim.contrib.carsharing.events.StartRentalEvent;
016import org.matsim.contrib.carsharing.manager.demand.CurrentTotalDemand;
017import org.matsim.contrib.carsharing.manager.demand.VehicleChoiceAgent;
018import org.matsim.contrib.carsharing.manager.routers.RouterProvider;
019import org.matsim.contrib.carsharing.manager.supply.CarsharingSupplyInterface;
020import org.matsim.contrib.carsharing.manager.supply.CompanyAgent;
021import org.matsim.contrib.carsharing.manager.supply.CompanyContainer;
022import org.matsim.contrib.carsharing.manager.supply.OneWayContainer;
023import org.matsim.contrib.carsharing.manager.supply.TwoWayContainer;
024import org.matsim.contrib.carsharing.manager.supply.VehiclesContainer;
025import org.matsim.contrib.carsharing.models.ChooseTheCompany;
026import org.matsim.contrib.carsharing.models.ChooseVehicleType;
027import org.matsim.contrib.carsharing.models.KeepingTheCarModel;
028import org.matsim.contrib.carsharing.router.CarsharingRoute;
029import org.matsim.contrib.carsharing.stations.CarsharingStation;
030import org.matsim.contrib.carsharing.vehicles.CSVehicle;
031import org.matsim.contrib.carsharing.vehicles.StationBasedVehicle;
032import org.matsim.core.api.experimental.events.EventsManager;
033import org.matsim.core.controler.events.IterationStartsEvent;
034import org.matsim.core.controler.listener.IterationStartsListener;
035
036import com.google.inject.Inject;
037import com.google.inject.name.Named;
038
039/**
040 * Class containing all the information about carsharing supply and demand.
041 * 
042 * @author balac
043 */
044public class CarsharingManagerNew implements CarsharingManagerInterface, IterationStartsListener {
045
046        @Inject
047        @Named("carnetwork")
048        private Network network;
049        @Inject
050        private CurrentTotalDemand currentDemand;
051        @Inject
052        private KeepingTheCarModel keepTheCarModel;
053        @Inject
054        private ChooseTheCompany chooseCompany;
055        @Inject
056        private ChooseVehicleType chooseVehicleType;
057        @Inject
058        private CarsharingSupplyInterface carsharingSupplyContainer;
059        @Inject
060        private EventsManager eventsManager;
061        @Inject
062        private RouterProvider routerProvider;
063        @Inject
064        private VehicleChoiceAgent vehicleChoiceAgent;
065
066        @Override
067        public List<PlanElement> reserveAndrouteCarsharingTrip(final Plan plan, String carsharingType, Leg legToBeRouted, Double time) {
068                Person person = plan.getPerson();
069                Link startLink = network.getLinks().get(legToBeRouted.getRoute().getStartLinkId());
070                Link destinationLink = network.getLinks().get(legToBeRouted.getRoute().getEndLinkId());
071
072                // === get the vehicle for the trip if the agent has it already ===
073                CSVehicle vehicle = getVehicleAtLocation(startLink, plan.getPerson(), carsharingType);
074
075                boolean willHaveATripFromLocation = willUseTheVehicleLaterFromLocation(destinationLink.getId(), plan,
076                                legToBeRouted);
077                double durationOfNextActivity = getDurationOfNextActivity(plan, legToBeRouted, time);
078                boolean keepTheCar;
079                if (((CarsharingRoute) legToBeRouted.getRoute()).isOldRoute())
080                        keepTheCar = ((CarsharingRoute) legToBeRouted.getRoute()).isKeepthecar();
081                else
082                        keepTheCar = keepTheCarModel.keepTheCarDuringNextActivity(durationOfNextActivity, plan.getPerson(),
083                                        carsharingType);
084                // TODO: create a method for getting the search distance
085                double searchDistance = 1000.0;
086                if (vehicle != null) {
087
088                        if ((willHaveATripFromLocation && keepTheCar)
089                                        || (willHaveATripFromLocation && carsharingType.equals("twoway"))) {
090                                ((CarsharingRoute) legToBeRouted.getRoute()).setKeepthecar(true);
091                                return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType, vehicle,
092                                                startLink, destinationLink, true, true);
093                        } else {
094
095                                if (carsharingType.equals("oneway")) {
096
097                                        CompanyContainer companyContainer = this.carsharingSupplyContainer
098                                                        .getCompany(vehicle.getCompanyId());
099                                        VehiclesContainer vehiclesContainer = companyContainer.getVehicleContainer(carsharingType);
100                                        Link parkingLocation = vehiclesContainer.findClosestAvailableParkingLocation(destinationLink,
101                                                        searchDistance);
102
103                                        if (parkingLocation == null)
104                                                return null;
105                                        destinationLink = parkingLocation;
106                                        vehiclesContainer.reserveParking(destinationLink);
107
108                                } else if (carsharingType.equals("twoway")) {
109                                        CarsharingStation parkingStation = ((TwoWayContainer) this.carsharingSupplyContainer
110                                                        .getCompany(vehicle.getCompanyId()).getVehicleContainer(carsharingType))
111                                                                        .getTwowaycarsharingstationsMap()
112                                                                        .get(((StationBasedVehicle) vehicle).getStationId());
113                                        destinationLink = parkingStation.getLink();
114                                }
115
116                                return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType, vehicle,
117                                                startLink, destinationLink, false, true);
118                        }
119                } else {
120
121                        // === agent does not hold the vehicle, therefore must find a one
122                        // from the supply side===
123                        // === here he chooses the company, type of vehicle and in the end
124                        // vehicle ===
125                        // === possibly this could be moved to one method which decides
126                        // based on the supply which vehicle to take
127                        String typeOfVehicle = chooseVehicleType.getPreferredVehicleType(plan, legToBeRouted);
128                        // CompanyAgent companyAgent =
129                        // this.carsharingSupplyContainer.getCompanyAgents().
130                        // get(((CarsharingRoute)legToBeRouted.getRoute()).getCompany());
131                        List<CSVehicle> offeredVehicles = new ArrayList<>();
132                        for (CompanyAgent companyAgent : this.carsharingSupplyContainer.getCompanyAgents().values()) {
133
134                                CSVehicle offeredVehicle = companyAgent.vehicleRequest(person.getId(), startLink, destinationLink,
135                                                carsharingType, typeOfVehicle);
136
137                                if (offeredVehicle != null)
138                                        offeredVehicles.add(offeredVehicle);
139                        }
140
141                        if (offeredVehicles.size() == 0) {
142                                eventsManager.processEvent(
143                                                new NoVehicleCarSharingEvent(time, carsharingType, "", startLink, destinationLink));
144
145                                return null;
146                        }
147
148                        // TODO: offer the possible cars to the agent, from which the agent
149                        // can choose
150                        CSVehicle chosenVehicle = vehicleChoiceAgent.chooseVehicle(offeredVehicles, startLink, legToBeRouted, time,
151                                        plan.getPerson());
152
153                        if (chosenVehicle == null) {
154                                eventsManager.processEvent(
155                                                new NoVehicleCarSharingEvent(time, carsharingType, "", startLink, destinationLink));
156
157                                return null;
158                        } else {
159
160                                CompanyContainer companyContainer = this.carsharingSupplyContainer
161                                                .getCompany(chosenVehicle.getCompanyId());
162                                VehiclesContainer vehiclesContainer = companyContainer.getVehicleContainer(carsharingType);
163                                Link stationLink = vehiclesContainer.getVehicleLocation(chosenVehicle);
164
165                                if (false == companyContainer.reserveVehicle(chosenVehicle)) {
166                                        eventsManager.processEvent(new NoVehicleCarSharingEvent(time, carsharingType,
167                                                        chosenVehicle.getCompanyId(), startLink, destinationLink));
168
169                                        return null;
170                                }
171
172                                eventsManager.processEvent(new StartRentalEvent(time, carsharingType, chosenVehicle.getCompanyId(),
173                                                startLink, stationLink, destinationLink, person.getId(), chosenVehicle.getVehicleId()));
174
175                                if ((willHaveATripFromLocation && keepTheCar)
176                                                || (willHaveATripFromLocation && carsharingType.equals("twoway"))) {
177                                        ((CarsharingRoute) legToBeRouted.getRoute()).setKeepthecar(true);
178
179                                        return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType,
180                                                        chosenVehicle, stationLink, destinationLink, true, false);
181                                } else {
182                                        if ((carsharingType.equals("oneway")) || (carsharingType.equals("freefloating"))) {
183                                                Link parkingStationLink = this.carsharingSupplyContainer.findClosestAvailableParkingSpace(
184                                                                destinationLink, carsharingType, chosenVehicle.getCompanyId(), searchDistance);
185                                                if (parkingStationLink == null)
186                                                        return null;
187
188                                                vehiclesContainer.reserveParking(parkingStationLink);
189
190                                                destinationLink = parkingStationLink;
191                                        }
192
193                                        return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType,
194                                                        chosenVehicle, stationLink, destinationLink, false, false);
195                                }
196
197                        }
198
199                }
200        }
201
202        private double getDurationOfNextActivity(Plan plan, Leg legToBeRouted, double time) {
203
204                int index = plan.getPlanElements().indexOf(legToBeRouted);
205
206                Activity a = (Activity) plan.getPlanElements().get(index + 1);
207
208                //return a.getEndTime() - time > 0.0 ? a.getEndTime() - time : 0.0;
209                return a.getEndTime().isUndefined() ? 0 : a.getEndTime().seconds() - time;
210        }
211
212        private boolean willUseTheVehicleLaterFromLocation(Id<Link> linkId, Plan plan, Leg currentLeg) {
213                boolean willUseVehicle = false;
214
215                String mode = currentLeg.getMode();
216                List<PlanElement> planElements = plan.getPlanElements();
217
218                int index = planElements.indexOf(currentLeg) + 1;
219
220                for (int i = index; i < planElements.size(); i++) {
221
222                        if (planElements.get(i) instanceof Leg) {
223
224                                if (((Leg) planElements.get(i)).getMode().equals(mode)) {
225
226                                        if (((Leg) planElements.get(i)).getRoute().getStartLinkId().toString().equals(linkId.toString())) {
227
228                                                willUseVehicle = true;
229                                        }
230                                }
231                        }
232                }
233                return willUseVehicle;
234        }
235
236        private CSVehicle getVehicleAtLocation(Link currentLink, Person person, String carsharingType) {
237
238                return this.currentDemand.getVehicleOnLink(person.getId(), currentLink, carsharingType);
239
240        }
241
242        @Override
243        public void freeParkingSpot(String vehicleId, Id<Link> linkId) {
244
245                CSVehicle vehicle = this.carsharingSupplyContainer.getVehicleWithId(vehicleId);
246                CompanyContainer companyContainer = this.carsharingSupplyContainer.getCompany(vehicle.getCompanyId());
247                VehiclesContainer vehiclesContainer = companyContainer.getVehicleContainer(vehicle.getCsType());
248
249                ((OneWayContainer) vehiclesContainer).freeParkingSpot(vehicle);
250        }
251
252        @Override
253        public boolean parkVehicle(String vehicleId, Id<Link> linkId) {
254                CSVehicle vehicle = this.carsharingSupplyContainer.getVehicleWithId(vehicleId);
255                Link link = network.getLinks().get(linkId);
256                this.carsharingSupplyContainer.getCompany(vehicle.getCompanyId()).parkVehicle(vehicle, link);
257                return false;
258        }
259
260        @Override
261        public void notifyIterationStarts(IterationStartsEvent event) {
262                this.carsharingSupplyContainer.populateSupply();
263                this.currentDemand.reset();
264        }
265}