Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Nabil Belahouane authored Sep 23, 2019
1 parent e7f93f4 commit 734adc9
Show file tree
Hide file tree
Showing 58 changed files with 810 additions and 0 deletions.
Binary file added trafficmon/lib/hamcrest-all-1.3.jar
Binary file not shown.
Binary file added trafficmon/lib/jmock-2.8.1.jar
Binary file not shown.
Binary file added trafficmon/lib/jmock-junit4-2.8.1.jar
Binary file not shown.
Binary file added trafficmon/lib/junit-4.12.jar
Binary file not shown.
Binary file added trafficmon/lib/trafficmon-externals.jar
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
147 changes: 147 additions & 0 deletions trafficmon/src/com/trafficmon/CongestionChargeSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package com.trafficmon;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

public class CongestionChargeSystem {
//Variables
public static final long HOURS_TO_MILLI_SECONDS = 60*60*1000L;
private Map<VehicleInterface, List<ZoneBoundaryCrossing>> crossingsByVehicle;
private CustomerAccountsServiceInterface customerAccountService;
private OperationsServiceInterface operationsService;
//Variables*

//Package Private Constructor for testing
CongestionChargeSystem(Map<VehicleInterface, List<ZoneBoundaryCrossing>> crossingsByVehicle,CustomerAccountsServiceInterface customerAccountService,OperationsServiceInterface opsi){
this.crossingsByVehicle = crossingsByVehicle;
this.customerAccountService = customerAccountService;
this.operationsService = opsi;
}

public CongestionChargeSystem(){
this.operationsService = new OperationsService();
this.customerAccountService = new CustomerAccountsService();
this.crossingsByVehicle = new HashMap<VehicleInterface, List<ZoneBoundaryCrossing>>();
}

public void vehicleEnteringZone(VehicleInterface vehicle) {
if (!crossingsByVehicle.containsKey(vehicle)) {
crossingsByVehicle.put(vehicle, new ArrayList<ZoneBoundaryCrossing>());
}
crossingsByVehicle.get(vehicle).add(new EntryEvent(vehicle));
}

public void vehicleLeavingZone(VehicleInterface vehicle) {
//Make sure vehicle is registered
if ((!crossingsByVehicle.containsKey(vehicle))||(crossingsByVehicle.get(vehicle).size()<=0)) {
return;
}
crossingsByVehicle.get(vehicle).add(new ExitEvent(vehicle));
}

public void calculateCharges() {
//crossingsByVehicle.clear();//reset hashmap
//For each vehicle make sure the crossing are not illegal and then calculate the charges and deduct from account
for (Map.Entry<VehicleInterface, List<ZoneBoundaryCrossing>> vehicleCrossings : crossingsByVehicle.entrySet()) {
VehicleInterface vehicle = vehicleCrossings.getKey();
List<ZoneBoundaryCrossing> crossings = vehicleCrossings.getValue();
if (!checkOrderingOf(crossings)) {
operationsService.triggerInvestigationInto(vehicle);
} else {

BigDecimal charge = calculateChargeForTimeInZone(crossings);
try {
customerAccountService.deductChargeFrom(vehicle,charge);
} catch (InsufficientCreditException | AccountNotRegisteredException ex) {
operationsService.issuePenaltyNotice(vehicle, charge);
}
}
}

}

private double timeFromEpochToHourOfDay(long millis){
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
Date resultantDate = new Date(millis);
String[] timeOfDay = sdf.format(resultantDate).split(":");
return (Double.parseDouble(timeOfDay[0])+(Double.parseDouble(timeOfDay[1])/60.0));

}

private BigDecimal calculateChargeForTimeInZone(List<ZoneBoundaryCrossing> crossings){
BigDecimal charge;
ZoneBoundaryCrossing previousEvent = crossings.get(0);//stores the previous crossing
ZoneBoundaryCrossing previousEntryEventCharged = crossings.get(0);//stores the last entry event in which you were charged
long totalTimeInZone = 0;

if (timeFromEpochToHourOfDay(previousEntryEventCharged.timestamp()) < 14.0){
charge= new BigDecimal(6.0);//before 2 pm
}else{
charge= new BigDecimal(4.0);//2pm onwards will be 4 gbp
}

for (ZoneBoundaryCrossing crossing : crossings.subList(1, crossings.size())) {
if (crossing instanceof ExitEvent) {
totalTimeInZone += crossing.timestamp()-previousEvent.timestamp();
//For the case where you weren't charged when you entered but stayed past the 4 hour mark from the previous charge
if ( (crossing.timestamp()-previousEntryEventCharged.timestamp()) > (4*HOURS_TO_MILLI_SECONDS) ){
long tmp_crossing_time = previousEntryEventCharged.timestamp()+(4*HOURS_TO_MILLI_SECONDS);
if (timeFromEpochToHourOfDay(tmp_crossing_time) < 14.0){
charge = charge.add(new BigDecimal(6.0));
}else{
charge = charge.add(new BigDecimal(4.0));
}
previousEntryEventCharged = new EntryEvent(crossing.getVehicle(),tmp_crossing_time);//create a phantom crossing(entry event) to make the system work
}

}else{
//Add Charges if previous charge was more than 4 hours ago
if ( (crossing.timestamp()-previousEntryEventCharged.timestamp()) > (4*HOURS_TO_MILLI_SECONDS) ){
if (timeFromEpochToHourOfDay(crossing.timestamp()) < 14.0) {
charge = charge.add(new BigDecimal(6.0));
} else{
charge = charge.add(new BigDecimal(4.0));
}
previousEntryEventCharged = crossing;
}
}
previousEvent = crossing;
}

//if total time spent in the zone greater than 4 hours return 12 gbp
if (totalTimeInZone > (4* HOURS_TO_MILLI_SECONDS)){
return new BigDecimal(12);
}

return charge;
}

private boolean checkOrderingOf(List<ZoneBoundaryCrossing> crossings) {

ZoneBoundaryCrossing previousEvent = crossings.get(0);
//Even though the vehicleLeavingZone function does not allow for exit events to be registered as the first event, it is always a good idea to perform checks in multiple places
if (previousEvent instanceof ExitEvent){
return false;
}
//Make sure a vehicle always leaves after entering (the list size is even and every Entry is followed by and Exit)
if ((crossings.size() % 2) != 0){
return false;
}
for (ZoneBoundaryCrossing crossing : crossings.subList(1, crossings.size())) {
if (crossing.timestamp() < previousEvent.timestamp()) {
return false;
}
if (crossing instanceof EntryEvent && previousEvent instanceof EntryEvent) {
return false;
}
if (crossing instanceof ExitEvent && previousEvent instanceof ExitEvent) {
return false;
}
previousEvent = crossing;
}

return true;
}

}
16 changes: 16 additions & 0 deletions trafficmon/src/com/trafficmon/CustomerAccountsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.trafficmon;

import java.math.BigDecimal;

/**
* Created by Shoaib on 11/19/18.
*/

public class CustomerAccountsService implements CustomerAccountsServiceInterface {
private AccountsService registeredCustomerAccountsService = RegisteredCustomerAccountsService.getInstance();

@Override
public void deductChargeFrom(VehicleInterface vehicle, BigDecimal charge) throws InsufficientCreditException,AccountNotRegisteredException {
registeredCustomerAccountsService.accountFor((Vehicle) vehicle).deduct(charge);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.trafficmon;

import java.math.BigDecimal;

/**
* Created by Shoaib on 11/19/18.
*/

public interface CustomerAccountsServiceInterface {

void deductChargeFrom(VehicleInterface vehicle, BigDecimal charge) throws InsufficientCreditException,AccountNotRegisteredException ;
}
9 changes: 9 additions & 0 deletions trafficmon/src/com/trafficmon/EntryEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.trafficmon;

public class EntryEvent extends ZoneBoundaryCrossing{
public EntryEvent(VehicleInterface vehicleRegistration) {
super(vehicleRegistration);
}
// Package-Private Method For Testing
EntryEvent(VehicleInterface vehicleRegistration,long time) {super(vehicleRegistration, time);}
}
11 changes: 11 additions & 0 deletions trafficmon/src/com/trafficmon/ExitEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.trafficmon;

public class ExitEvent extends ZoneBoundaryCrossing {
public ExitEvent(VehicleInterface vehicle) {
super(vehicle);
}
// Package-Private Method For Testing
ExitEvent(VehicleInterface vehicle, long time) {
super(vehicle,time);
}
}
26 changes: 26 additions & 0 deletions trafficmon/src/com/trafficmon/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.trafficmon;

/**
* Created by Shoaib on 11/17/18.
*/

public class Main {
public static void main(String[] args) throws Exception {

CongestionChargeSystem congestionChargeSystem = new CongestionChargeSystem();
congestionChargeSystem.vehicleEnteringZone(Vehicle.withRegistration("A123 XYZ"));
//delaySeconds(15);
congestionChargeSystem.vehicleEnteringZone(Vehicle.withRegistration("J091 4PY"));
//delayMinutes(30);
//congestionChargeSystem.vehicleLeavingZone(Vehicle.withRegistration("A123 XYZ"));
//delayMinutes(10);
congestionChargeSystem.vehicleLeavingZone(Vehicle.withRegistration("J091 4PY"));
congestionChargeSystem.calculateCharges();
}
private static void delayMinutes(int mins) throws InterruptedException {
delaySeconds(mins * 60);
}
private static void delaySeconds(int secs) throws InterruptedException {
Thread.sleep(secs * 1000);
}
}
19 changes: 19 additions & 0 deletions trafficmon/src/com/trafficmon/OperationsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.trafficmon;

import java.math.BigDecimal;

public class OperationsService implements OperationsServiceInterface {
private PenaltiesService OpTeam = OperationsTeam.getInstance();

@Override
public void issuePenaltyNotice(VehicleInterface vehicle, BigDecimal charge) {
OpTeam.issuePenaltyNotice((Vehicle) vehicle,charge);
}

@Override
public void triggerInvestigationInto(VehicleInterface vehicle){
OpTeam.triggerInvestigationInto((Vehicle) vehicle);
}


}
8 changes: 8 additions & 0 deletions trafficmon/src/com/trafficmon/OperationsServiceInterface.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.trafficmon;

import java.math.BigDecimal;

public interface OperationsServiceInterface {
void issuePenaltyNotice(VehicleInterface vehicle, BigDecimal charge);
void triggerInvestigationInto(VehicleInterface vehicle);
}
39 changes: 39 additions & 0 deletions trafficmon/src/com/trafficmon/Vehicle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.trafficmon;

public class Vehicle implements VehicleInterface {

private final String registration;

private Vehicle(String registration) {
this.registration = registration;
}

static Vehicle withRegistration(String registration) {
return new Vehicle(registration);
}

@Override
public String toString() {
return "Vehicle [" + registration + "]";
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Vehicle vehicle = (Vehicle) o;

return (registration != null) ? registration.equals(vehicle.registration) : vehicle.registration == null;

/*if (registration != null){
return registration.equals(vehicle.registration);
}
return (vehicle.registration == null);*/
}

@Override
public int hashCode() {
return registration != null ? registration.hashCode() : 0;
}
}
17 changes: 17 additions & 0 deletions trafficmon/src/com/trafficmon/VehicleInterface.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.trafficmon;

/**
* Created by Shoaib on 11/17/18.
*/

interface VehicleInterface {

@Override
String toString();

@Override
boolean equals(Object o);

@Override
int hashCode();
}
25 changes: 25 additions & 0 deletions trafficmon/src/com/trafficmon/ZoneBoundaryCrossing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.trafficmon;

public abstract class ZoneBoundaryCrossing {

private final VehicleInterface vehicle;
private final long time;

public ZoneBoundaryCrossing(VehicleInterface vehicle) {
this.vehicle = vehicle;
this.time = System.currentTimeMillis();
}
//Package private constructor for testing purposes
ZoneBoundaryCrossing(VehicleInterface vehicle, long time) {
this.vehicle = vehicle;
this.time = time;
}

public VehicleInterface getVehicle() {
return vehicle;
}

public long timestamp() {
return time;
}
}
Loading

0 comments on commit 734adc9

Please sign in to comment.