|
package paysim; |
|
|
|
import java.util.ArrayList; |
|
|
|
import sim.engine.SimState; |
|
import sim.engine.Steppable; |
|
|
|
public class Client extends SuperClient implements Steppable { |
|
|
|
private String name = ""; |
|
private boolean willRepeat = false; |
|
boolean failed = false; |
|
private double[] probabilityArr; |
|
private ArrayList<ActionProbability> probList; |
|
private ArrayList<Long> stepsToRepeat = new ArrayList<Long>(); |
|
private long nrOfStepsToRepeat = 0; |
|
private ArrayList<String> paramFile = new ArrayList<String>(); |
|
String currType = ""; |
|
private CurrentStepHandler stepHandler = null; |
|
private double x; |
|
private double y; |
|
private double balanceFlag = 0; |
|
private int countFlag = 0; |
|
|
|
public double getDiff(Client c) { |
|
double xFactor = c.getX() - this.x; |
|
xFactor = xFactor * xFactor; |
|
double yFactor = c.getY() - this.y; |
|
yFactor = yFactor * yFactor; |
|
|
|
double result = xFactor + yFactor; |
|
result = Math.sqrt(result); |
|
return result; |
|
} |
|
|
|
public void move(PaySim paysim) { |
|
int randNrX = 0; |
|
int randNrY = 0; |
|
|
|
do { |
|
randNrX = paysim.random.nextInt() % 5; |
|
} while (randNrX == 0); |
|
|
|
do { |
|
randNrY = paysim.random.nextInt() % 5; |
|
} while (randNrY == 0); |
|
|
|
System.out.println("RandedX:\t" + randNrX + "\tRandedY:\t" + randNrY |
|
+ "\n"); |
|
|
|
this.x += randNrX; |
|
this.y += randNrY; |
|
|
|
if (this.x > 1000) { |
|
this.x = 1000; |
|
} else if (this.x < 0) { |
|
this.x = 0; |
|
} |
|
|
|
if (this.y > 1000) { |
|
this.y = 1000; |
|
} else if (this.y < 0) { |
|
this.y = 0; |
|
} |
|
|
|
System.out.println("X:\t" + this.x + "\tY:\t" + this.y + "\n"); |
|
|
|
} |
|
|
|
@Override |
|
public void step(SimState state) { |
|
|
|
handleAction(state); |
|
|
|
|
|
if (this.cont != null) { |
|
handleRepetition(state); |
|
} |
|
|
|
|
|
} |
|
|
|
public long getNrOfStepsToRepeat() { |
|
return nrOfStepsToRepeat; |
|
} |
|
|
|
public void setNrOfStepsToRepeat(long nrOfStepsToRepeat) { |
|
this.nrOfStepsToRepeat = nrOfStepsToRepeat; |
|
} |
|
|
|
public void handleAction(SimState state) { |
|
PaySim paysim = (PaySim) state; |
|
|
|
int action = 0; |
|
|
|
|
|
do { |
|
action = this.chooseAction(paysim, this.probabilityArr); |
|
if (action == -1) { |
|
if (this.probabilityArr.length == 0) { |
|
return; |
|
} |
|
} |
|
} while (action == -1); |
|
|
|
ActionProbability prob; |
|
switch (action) { |
|
|
|
|
|
case 1: |
|
|
|
|
|
|
|
handleCashIn(paysim, paysim.getRandomClient()); |
|
break; |
|
|
|
|
|
case 2: |
|
prob = getProb("CASH_OUT", paysim); |
|
if (prob != null) |
|
handleCashOut(paysim, paysim.getRandomClient(), |
|
this.getAmount(prob, paysim)); |
|
break; |
|
|
|
|
|
case 3: |
|
handleDebit(paysim); |
|
break; |
|
|
|
|
|
case 4: |
|
handlePayment(paysim); |
|
break; |
|
|
|
|
|
case 5: |
|
prob = getProb("TRANSFER", paysim); |
|
|
|
if (prob != null) { |
|
double amount = this.getAmount(prob, paysim); |
|
double reducedAmount = amount; |
|
int loops = (int) Math.ceil(amount / paysim.transferLimit); |
|
Client c = paysim.getRandomClient(); |
|
for (int i = 0; i < loops; i++) { |
|
if (reducedAmount > paysim.transferLimit) { |
|
handleTransfer(paysim, c, |
|
paysim.transferLimit); |
|
reducedAmount -= paysim.transferLimit; |
|
} else { |
|
handleTransfer(paysim, c, |
|
reducedAmount); |
|
} |
|
} |
|
} |
|
break; |
|
|
|
} |
|
} |
|
|
|
public void handleRepetition(SimState state) { |
|
PaySim paysim = (PaySim) state; |
|
|
|
|
|
for (int i = 0; i < this.stepsToRepeat.size(); i++) { |
|
|
|
long currentStep = this.stepsToRepeat.get(i); |
|
this.currDay = (int) (currentStep / 24) + 1; |
|
this.currHour = (int) (currentStep - ((this.currDay - 1) * 24)); |
|
|
|
switch (this.cont.getType()) { |
|
|
|
case "CASH_IN": |
|
this.currType = "CASH_IN"; |
|
handleCashInRepetition(paysim); |
|
break; |
|
|
|
|
|
case "CASH_OUT": |
|
this.currType = "CASH_OUT"; |
|
handleCashOutRepetition(paysim); |
|
break; |
|
|
|
|
|
case "DEBIT": |
|
this.currType = "DEBIT"; |
|
handleDebitRepetition(paysim); |
|
break; |
|
|
|
|
|
case "DEPOSIT": |
|
this.currType = "DEPOSIT"; |
|
handleDepositRepetition(paysim); |
|
break; |
|
|
|
|
|
case "PAYMENT": |
|
this.currType = "PAYMENT"; |
|
handlePaymentRepetition(paysim); |
|
break; |
|
|
|
|
|
case "TRANSFER": |
|
this.currType = "TRANSFER"; |
|
handleTrasferRepetition(paysim); |
|
break; |
|
|
|
} |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void setClient(Client c) { |
|
this.balance = c.getBalance(); |
|
this.currency = c.getCurrency(); |
|
this.currStep = c.getCurrStep(); |
|
this.name = c.getName(); |
|
this.numDeposits = c.getNumDeposits(); |
|
this.numTransfers = c.getNumTransfers(); |
|
this.numWithdraws = c.getNumWithdraws(); |
|
} |
|
|
|
public double[] getProbabilityArr() { |
|
return probabilityArr; |
|
} |
|
|
|
public void setProbabilityArr(double[] probabilityArr) { |
|
this.probabilityArr = probabilityArr; |
|
} |
|
|
|
public void setName(String name) { |
|
|
|
} |
|
|
|
public String getName() { |
|
return this.toString(); |
|
} |
|
|
|
public String toString() { |
|
return "C" + Integer.toString(this.hashCode()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void handleCashIn(PaySim paysim, SuperClient clientTo) { |
|
|
|
ActionProbability prob = getProb("CASH_IN", paysim); |
|
|
|
|
|
|
|
if (prob != null) { |
|
double amount = this.getAmount(prob, paysim); |
|
Client clientToTransferAfter = (Client) clientTo; |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
clientToTransferAfter.withdraw(amount); |
|
this.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 1, amount, "CashIn"); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
|
|
|
|
|
|
} else { |
|
Manager.nrFailed++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
printActionProbability(); |
|
} |
|
|
|
} |
|
|
|
public void handleCashOut(PaySim paysim, Client clientTo, double amount) { |
|
|
|
Client clientToTransferAfter = clientTo; |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
clientToTransferAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), before, |
|
this, (short) 2, amount, "CashOut"); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
|
|
t2.setFraud(this.isFraud()); |
|
paysim.getTrans().add(t2); |
|
|
|
} |
|
|
|
public void handleDeposit(PaySim paysim) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
ActionProbability prob = getProb("DEPOSIT", paysim); |
|
|
|
if (prob != null) { |
|
|
|
|
|
double amount = this.getAmount(prob, paysim); |
|
|
|
|
|
|
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
clientToTransferAfter.withdraw(amount); |
|
this.deposit(amount); |
|
this.numDeposits++; |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 4, amount, "Deposit"); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
printActionProbability(); |
|
} |
|
|
|
} |
|
|
|
public void handlePayment(PaySim paysim) { |
|
|
|
Merchant mAfter = paysim.getRandomMerchant(); |
|
Merchant merchantToTransferBefore = new Merchant(); |
|
merchantToTransferBefore.setMerchant(mAfter); |
|
ActionProbability prob = getProb("PAYMENT", paysim); |
|
|
|
if (prob != null) { |
|
double amount = this.getAmount(prob, paysim); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
mAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 5, amount, "Payment"); |
|
t2.setMerchantAfter(mAfter); |
|
t2.setMerchantBefore(merchantToTransferBefore); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
printActionProbability(); |
|
} |
|
|
|
} |
|
|
|
public void handleTransfer(PaySim paysim, Client clientTo, double amount) { |
|
|
|
if (!this.checkBalanceDropping(paysim.transferLimit, amount)) { |
|
Client clientToTransferAfter = clientTo; |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
clientToTransferAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 6, amount, "Transfer"); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
|
|
t2.setFraud(this.isFraud()); |
|
paysim.getTrans().add(t2); |
|
} else { |
|
Client clientToTransferAfter = clientTo; |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
|
|
|
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 6, amount, "Transfer"); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setFlaggedFraud(true); |
|
t2.setFraud(this.isFraud()); |
|
paysim.getTrans().add(t2); |
|
} |
|
} |
|
|
|
public boolean checkBalanceDropping(double transLimit, double amount) { |
|
boolean flag = false; |
|
if (this.countFlag >= 3) { |
|
if (this.balanceFlag - this.balance - amount > transLimit * 2.5) { |
|
flag = true; |
|
} |
|
} else { |
|
this.countFlag++; |
|
if (this.balanceFlag == 0) { |
|
this.balanceFlag = this.balance; |
|
} |
|
if (this.balanceFlag < this.balance) { |
|
this.balanceFlag = this.balance; |
|
} |
|
} |
|
return flag; |
|
} |
|
|
|
public void handleDebit(PaySim paysim) { |
|
|
|
ActionProbability prob = getProb("DEBIT", paysim); |
|
|
|
|
|
|
|
if (prob != null) { |
|
double amount = this.getAmount(prob, paysim); |
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
clientToTransferAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 3, amount, "Debit"); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
printActionProbability(); |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void handleCashInRepetition(PaySim paysim) { |
|
double amount = this.getAmountRepetition(this.currType, this.currDay, |
|
this.currHour, paysim); |
|
if (amount == -1) { |
|
return; |
|
} |
|
|
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
clientToTransferAfter.withdraw(amount); |
|
this.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), before, |
|
this, (short) 1, amount, "CashIn"); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
|
|
} |
|
|
|
public void handleCashOutRepetition(PaySim paysim) { |
|
double amount = this.getAmountRepetition(this.currType, this.currDay, |
|
this.currHour, paysim); |
|
if (amount == -1) { |
|
return; |
|
} |
|
|
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
clientToTransferAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), before, |
|
this, (short) 2, amount, "CashOut"); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
paysim.getTrans().add(t2); |
|
} |
|
|
|
public void handleDebitRepetition(PaySim paysim) { |
|
double amount = this.getAmountRepetition(this.currType, this.currDay, |
|
this.currHour, paysim); |
|
if (amount == -1) { |
|
return; |
|
} |
|
|
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
clientToTransferAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), before, |
|
this, (short) 3, amount, "Debit"); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
} |
|
|
|
public void handleDepositRepetition(PaySim paysim) { |
|
double amount = this.getAmountRepetition(this.currType, this.currDay, |
|
this.currHour, paysim); |
|
if (amount == -1) { |
|
return; |
|
} |
|
|
|
|
|
|
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
clientToTransferAfter.withdraw(amount); |
|
this.deposit(amount); |
|
this.numDeposits++; |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), before, |
|
this, (short) 4, amount, "Deposit"); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
} |
|
|
|
public void handlePaymentRepetition(PaySim paysim) { |
|
|
|
Merchant mAfter = paysim.getRandomMerchant(); |
|
Merchant merchantToTransferBefore = new Merchant(); |
|
merchantToTransferBefore.setMerchant(mAfter); |
|
|
|
double amount = this.getAmountRepetition(this.currType, this.currDay, |
|
this.currHour, paysim); |
|
if (amount == -1) { |
|
return; |
|
} |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
mAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), before, |
|
this, (short) 5, amount, "Payment"); |
|
t2.setMerchantAfter(mAfter); |
|
t2.setMerchantBefore(merchantToTransferBefore); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
paysim.getTrans().add(t2); |
|
} |
|
|
|
public void handleTrasferRepetition(PaySim paysim) { |
|
double amount = this.getAmountRepetition(this.currType, this.currDay, |
|
this.currHour, paysim); |
|
if (amount == -1) { |
|
return; |
|
} |
|
try { |
|
Client clientToTransferAfter = getRandomClient(amount, paysim); |
|
Client clientToTransferBefore = new Client(); |
|
clientToTransferBefore.setClient(clientToTransferAfter); |
|
|
|
Client before = new Client(); |
|
before.setClient(this); |
|
this.withdraw(amount); |
|
clientToTransferAfter.deposit(amount); |
|
|
|
Transaction t2 = new Transaction(paysim.schedule.getSteps(), |
|
before, this, (short) 6, amount, "Transfer"); |
|
t2.setDay(this.currDay); |
|
t2.setHour(this.currHour); |
|
t2.setClientDestAfter(clientToTransferAfter); |
|
t2.setClientDestBefore(clientToTransferBefore); |
|
paysim.getTrans().add(t2); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
|
|
return; |
|
} |
|
|
|
} |
|
|
|
public ArrayList<ActionProbability> getProbList() { |
|
return probList; |
|
} |
|
|
|
public boolean isWillRepeat() { |
|
return willRepeat; |
|
} |
|
|
|
public Client getRandomClient(double amount, PaySim paysim) { |
|
Client clientToTransfer = new Client(); |
|
int counter = 0; |
|
do { |
|
clientToTransfer = paysim.getClients().get( |
|
paysim.random.nextInt(paysim.getClients().size())); |
|
counter++; |
|
if (counter > 50000) { |
|
break; |
|
} |
|
} while (clientToTransfer.getBalance() < amount); |
|
|
|
return clientToTransfer; |
|
} |
|
|
|
public void setWillRepeat(boolean willRepeat) { |
|
this.willRepeat = willRepeat; |
|
} |
|
|
|
public void setProbList(ArrayList<ActionProbability> probList) { |
|
this.probList = probList; |
|
} |
|
|
|
private double getAmount(ActionProbability prob, PaySim paysim) { |
|
double amount = 0; |
|
|
|
do { |
|
amount = paysim.random.nextGaussian() * prob.getStd() |
|
+ prob.getAverage(); |
|
} while (amount <= 0); |
|
|
|
return amount; |
|
} |
|
|
|
private double getAmountRepetition(String type, int day, int hour, |
|
PaySim paysim) { |
|
AggregateTransactionRecord transRecord = this.stepHandler.getRecord( |
|
type, day, hour); |
|
if (transRecord == null) { |
|
return -1; |
|
} |
|
double amount = 0; |
|
do { |
|
amount = paysim.random.nextGaussian() |
|
* Double.parseDouble(transRecord.gettStd()) |
|
+ Double.parseDouble(transRecord.gettAvg()); |
|
} while (amount <= 0); |
|
|
|
return amount; |
|
} |
|
|
|
public ArrayList<Long> getStepsToRepeat() { |
|
return stepsToRepeat; |
|
} |
|
|
|
public void setStepsToRepeat(ArrayList<Long> stepsToRepeat) { |
|
this.stepsToRepeat = stepsToRepeat; |
|
} |
|
|
|
private ActionProbability getProb(String probToGet, PaySim p) { |
|
|
|
for (ActionProbability temp : this.probList) { |
|
if (temp.getType().equals(probToGet)) { |
|
return temp; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
private void printActionProbability() { |
|
System.out.println("Printing prob\n"); |
|
for (ActionProbability p : this.probList) { |
|
System.out.println(p.getType() + "\n" + p.getNrOfTransactions() |
|
+ "\n"); |
|
} |
|
System.out.println("\n\n"); |
|
} |
|
|
|
public ArrayList<String> getParamFile() { |
|
return paramFile; |
|
} |
|
|
|
public void setParamFile(ArrayList<String> paramFile) { |
|
this.paramFile = paramFile; |
|
} |
|
|
|
public CurrentStepHandler getStepHandler() { |
|
return stepHandler; |
|
} |
|
|
|
public void setStepHandler(CurrentStepHandler stepHandler) { |
|
this.stepHandler = stepHandler; |
|
} |
|
|
|
public double getX() { |
|
return x; |
|
} |
|
|
|
public void setX(double x) { |
|
this.x = x; |
|
} |
|
|
|
public double getY() { |
|
return y; |
|
} |
|
|
|
public void setY(double y) { |
|
this.y = y; |
|
} |
|
|
|
} |
|
|