#pragma once
#include <config.h>
#include <cassert>
#include <string>
#include <vector>
#include "EffortCalculator.h"
#include "FareToken.h"
#include "FareZones.h"
class ZoneCounter {
public:
explicit ZoneCounter(unsigned int ct) :
myCount(ct) {
}
inline void addZone(int zoneNumber) {
zoneNumber = getOverlayZone(zoneNumber);
if (zoneNumber == 0) {
return;
}
long long int repNum = fareZoneToRep[zoneNumber];
if (bitcount(repNum) == 0) {
return;
}
myCount = myCount | repNum;
}
int numZones() const {
return bitcount(myCount);
}
private:
inline int bitcount(long long int intVal) const {
int count = 0;
long long int counter = intVal;
while (counter != 0) {
counter = counter & (counter - 1);
++count;
}
return count;
}
private:
long long int myCount;
};
struct FareState {
friend class FareModul;
public:
explicit FareState():
myFareToken(FareToken::None),
myCounter(std::numeric_limits<int>::max()),
myTravelledDistance(std::numeric_limits<double>::max()),
myVisistedStops(std::numeric_limits<int>::max()),
myPriceDiff(0) {
};
explicit FareState(FareToken token):
myFareToken(token),
myCounter(0),
myTravelledDistance(0),
myVisistedStops(0),
myPriceDiff(0) {}
~FareState() = default;
bool isValid() const {
return !(myFareToken == FareToken::None);
}
private:
FareToken myFareToken;
ZoneCounter myCounter;
double myTravelledDistance;
int myVisistedStops;
double myPriceDiff;
};
struct Prices {
std::vector<double> zonePrices = std::vector<double> {1.9, 3.4, 4.9, 6.2, 7.7, 9.2};
double halle = 2.3;
double leipzig = 2.7;
double t1 = 1.5;
double t2 = 1.6;
double t3 = 1.6;
double shortTrip = 1.6;
double shortTripLeipzig = 1.9;
double shortTripHalle = 1.7;
double maxPrice = 10.6;
};
class FareModul : public EffortCalculator {
public:
FareModul() :
myFareStates()
{};
void init(const std::vector<std::string>& edges) override {
myEdges = edges;
myFareStates.resize(edges.size());
}
void addStop(const int stopEdge, const Parameterised& params) override {
myStopFareZone[stopEdge] = StringUtils::toInt(params.getParameter("fareZone"));
myStopFareToken[stopEdge] = FareUtil::stringToToken(params.getParameter("fareToken"));
myStopStartToken[stopEdge] = FareUtil::stringToToken(params.getParameter("startToken"));
}
double getEffort(const int numericalID) const override {
double effort = 0;
FareState const& state = myFareStates.at(numericalID);
if (state.isValid()) {
effort = state.myPriceDiff;
} else {
effort = std::numeric_limits<double>::max();
}
return effort;
}
void update(const int edge, const int prev, const double length) override {
std::string const& edgeType = myEdges[edge];
FareState& state = myFareStates.at(prev);
double oldPr;
if (state.myFareToken == FareToken::START) {
oldPr = 0;
} else {
oldPr = computePrice(state);
}
if (edgeType.c_str()[0] != '!') {
updateFareStatePublic(state, edge, length);
} else if (edgeType == "!stop") {
updateFareStateStop(state, edge);
} else if (edgeType == "!ped") {
updateFareStatePedestrian(state, edge);
} else if (edgeType == "!access") {
updateFareStateAccess(state, edge, prev);
} else {
updateFareState(state, edge);
}
FareState& stateAtE = myFareStates[edge];
double newPr = computePrice(stateAtE);
stateAtE.myPriceDiff = newPr - oldPr;
assert(stateAtE.myPriceDiff >= 0);
}
void setInitialState(const int edge) override {
myFareStates[edge] = FareState(FareToken::START);
}
private:
std::vector<FareState> myFareStates;
std::vector<std::string> myEdges;
std::map<int, int> myStopFareZone;
std::map<int, FareToken> myStopFareToken;
std::map<int, FareToken> myStopStartToken;
Prices prices;
double computePrice(FareState const& fareState) const {
switch (fareState.myFareToken) {
case FareToken ::H:
return prices.halle;
case FareToken ::L:
return prices.leipzig;
case FareToken ::T1:
return prices.t1;
case FareToken ::T2:
return prices.t2;
case FareToken ::T3:
return prices.t3;
case FareToken::U:
return prices.zonePrices[0];
case FareToken ::Z:
return prices.zonePrices[fareState.myCounter.numZones() - 1];
case FareToken ::M:
return prices.maxPrice;
case FareToken ::K:
return prices.shortTrip;
case FareToken ::KL:
case FareToken ::KLZ:
case FareToken ::KLU:
return prices.shortTripLeipzig;
case FareToken ::KH:
case FareToken ::KHU:
case FareToken ::KHZ:
return prices.shortTripHalle;
case FareToken::Free:
return 1.4;
case FareToken ::START:
return 0;
case FareToken::ZU:
case FareToken::None:
assert(false);
}
return std::numeric_limits<double>::max();
}
std::string output(const int edge) const override {
FareState const& my = myFareStates[edge];
std::stringstream msg;
msg << FareUtil::tokenToTicket(my.myFareToken) << " ";
if (my.myFareToken == FareToken::Z) {
msg << my.myCounter.numZones() << " ";
if (my.myCounter.numZones() == 1) {
msg << "Zone";
} else {
msg << "Zonen";
}
} else if (my.myFareToken == FareToken::U) {
msg << my.myCounter.numZones() << "1 Zone";
}
msg << ":" << computePrice(my);
return msg.str();
}
void updateFareStateStop(FareState const& currentFareState, const int stopEdge) {
FareToken collectedToken = myStopFareToken[stopEdge];
if (collectedToken == FareToken::None) {
std::cout << "Propagating fare state for stop w/o a price!" << std::endl;
return;
}
FareToken const& token = currentFareState.myFareToken;
FareState& stateAtE = myFareStates[stopEdge];
stateAtE = currentFareState;
stateAtE.myCounter.addZone(myStopFareZone[stopEdge]);
stateAtE.myVisistedStops++;
switch (token) {
case FareToken ::Free:
stateAtE.myFareToken = myStopStartToken[stopEdge];
break;
case FareToken::M :
break;
case FareToken::Z :
if (stateAtE.myCounter.numZones() > 6) {
stateAtE.myFareToken = FareToken::M;
}
break;
case FareToken::T1 :
case FareToken::T2 :
case FareToken::T3 :
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = stateAtE.myTravelledDistance <= 4000 ? FareToken::K : FareToken::Z;
}
break;
case FareToken::U :
if (collectedToken == FareToken::H) {
stateAtE.myFareToken = FareToken::H;
}
if (collectedToken == FareToken::L) {
stateAtE.myFareToken = FareToken::L;
}
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken::Z;
}
break;
case FareToken::H:
case FareToken::L:
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken::Z;
}
break;
case FareToken::KH:
if (stateAtE.myVisistedStops <= 4) {
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken::KHU;
}
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken::KHZ;
}
} else {
if (collectedToken == FareToken::H) {
stateAtE.myFareToken = FareToken ::H;
}
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken ::Z;
}
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken ::U;
}
}
break;
case FareToken::KL:
if (stateAtE.myVisistedStops <= 4) {
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken::KLU;
}
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken::KLZ;
}
} else {
if (collectedToken == FareToken::L) {
stateAtE.myFareToken = FareToken ::L;
}
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken ::Z;
}
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken ::U;
}
}
break;
case FareToken::K:
if (stateAtE.myTravelledDistance > 4000) {
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken ::U;
}
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken ::Z;
}
}
break;
case FareToken::KHU :
case FareToken::KLU :
if (stateAtE.myVisistedStops > 4) {
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken::U;
}
}
break;
case FareToken::KLZ:
case FareToken::KHZ:
if (stateAtE.myVisistedStops > 4) {
if (collectedToken == FareToken::Z) {
stateAtE.myFareToken = FareToken::Z;
}
}
break;
case FareToken::ZU :
assert(false);
if (collectedToken == FareToken::U) {
stateAtE.myFareToken = FareToken::U;
} else {
stateAtE.myFareToken = FareToken::Z;
}
break;
default:
std::cout << "Reached invalid position in fareToken selection!" << std::endl;
assert(false);
break;
}
}
void updateFareStatePedestrian(FareState const& currentFareState, const int pedestrianEdge) {
FareState& stateAtE = myFareStates[pedestrianEdge];
stateAtE = currentFareState;
if (currentFareState.myFareToken == FareToken::START) {
stateAtE.myFareToken = FareToken::Free;
}
}
void updateFareStatePublic(FareState const& currentFareState, const int publicTransportEdge, const double length) {
if (currentFareState.myFareToken == FareToken::None) {
return;
}
FareState& stateAtE = myFareStates[publicTransportEdge];
stateAtE = currentFareState;
stateAtE.myTravelledDistance += length;
}
void updateFareState(FareState const& currentFareState, const int intermodalEdge) {
if (currentFareState.myFareToken == FareToken::None) {
return;
}
FareState& stateAtE = myFareStates[intermodalEdge];
stateAtE = currentFareState;
if (currentFareState.myFareToken == FareToken::START) {
stateAtE.myFareToken = FareToken::Free;
}
}
void updateFareStateAccess(FareState const& currentFareState, const int accessEdge, const int prev) {
FareToken const& token = currentFareState.myFareToken;
FareState& stateAtE = myFareStates[accessEdge];
stateAtE = currentFareState;
if (currentFareState.myFareToken == FareToken::START) {
stateAtE.myFareToken = FareToken::Free;
}
if (myEdges[prev] == "!ped") {
switch (token) {
case FareToken::Free :
break;
case FareToken::K :
if (currentFareState.myCounter.numZones() == 0) {
stateAtE.myFareToken = FareToken::U;
} else {
stateAtE.myFareToken = FareToken::Z;
}
break;
case FareToken::KH :
stateAtE.myFareToken = FareToken::H;
break;
case FareToken::KL :
stateAtE.myFareToken = FareToken::L;
break;
case FareToken::KLU :
stateAtE.myFareToken = FareToken::L;
break;
case FareToken::KHU:
stateAtE.myFareToken = FareToken::H;
break;
case FareToken::KLZ :
stateAtE.myFareToken = FareToken::Z;
break;
case FareToken::KHZ:
stateAtE.myFareToken = FareToken::Z;
break;
default:
return;
}
}
}
};