forked from emilybache/Theatrical-Players-Refactoring-Kata
/
TheatricalPlayers.java
159 lines (133 loc) · 5.2 KB
/
TheatricalPlayers.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class TheatricalPlayers {
private final Printer printer = new PlainTextPrinter();
private final Printer htmlPrinter = (data) -> "<html>" + data.customer + "</html>";
public String print(Invoice invoice, Map<String, Play> plays) {
final InvoiceData invoiceData = getInvoiceData(invoice, plays);
return printer.printer(invoiceData);
}
public InvoiceData getInvoiceData(Invoice invoice, Map<String, Play> plays) {
int totalAmount = getTotalAmount(invoice, plays);
int volumeCredits = getVolumeCredits(invoice, plays);
List<LineData> lines = getLineData(invoice, plays);
return new InvoiceData(invoice.customer, lines, totalAmount / 100, volumeCredits);
}
public List<LineData> getLineData(Invoice invoice, Map<String, Play> plays) {
List<LineData> lines = new ArrayList<>();
for (var perf : invoice.performances) {
lines.add(new LineData(plays.get(perf.playID).name, amount(plays, perf), perf.audience));
}
return lines;
}
public int amount(Map<String, Play> plays, Performance perf) {
return getThisAmount(perf, plays.get(perf.playID)) / 100;
}
public int getVolumeCredits(Invoice invoice, Map<String, Play> plays) {
var volumeCredits = 0;
for (var perf : invoice.performances) {
volumeCredits += getThisCredits(perf, plays.get(perf.playID));
}
return volumeCredits;
}
public int getTotalAmount(Invoice invoice, Map<String, Play> plays) {
var totalAmount = 0;
for (var perf : invoice.performances) {
totalAmount += getThisAmount(perf, plays.get(perf.playID));
}
return totalAmount;
}
public int getThisCredits(Performance perf, Play play) {
// add volume credits
var thisCredits = Math.max(perf.audience - 30, 0);
// add extra credit for every ten comedy attendees
if ("comedy".equals(play.type)) thisCredits += Math.floor((double) perf.audience / 5);
return thisCredits;
}
public int getThisAmount(Performance perf, Play play) {
var thisAmount = 0;
switch (play.type) {
case "tragedy":
thisAmount = 40000;
if (perf.audience > 30) {
thisAmount += 1000 * (perf.audience - 30);
}
break;
case "comedy":
thisAmount = 30000;
if (perf.audience > 20) {
thisAmount += 10000 + 500 * (perf.audience - 20);
}
thisAmount += 300 * perf.audience;
break;
default:
throw new Error("unknown type: ${play.type}");
}
return thisAmount;
}
private static class LineData {
private final String playName;
private final int amount;
private final int audience;
private LineData(String playName, int amount, int audience) {
this.playName = playName;
this.amount = amount;
this.audience = audience;
}
public String getPlayName() {
return playName;
}
public int getAmount() {
return amount;
}
public int getAudience() {
return audience;
}
}
public static class InvoiceData {
private final String customer;
private final List<LineData> lines;
private final int totalAmount;
private final int volumeCredits;
private InvoiceData(String customer, List<LineData> lines, int totalAmount, int volumeCredits) {
this.customer = customer;
this.lines = lines;
this.totalAmount = totalAmount;
this.volumeCredits = volumeCredits;
}
public String getCustomer() {
return customer;
}
public List<LineData> getLines() {
return lines;
}
public int getTotalAmount() {
return totalAmount;
}
public int getVolumeCredits() {
return volumeCredits;
}
}
public static class PlainTextPrinter implements Printer {
private NumberFormat format;
public PlainTextPrinter() {
this.format = NumberFormat.getCurrencyInstance(Locale.US);
}
@Override
public String printer(InvoiceData invoiceData) {
StringBuilder result = new StringBuilder(String.format("Statement for %s\n", invoiceData.getCustomer()));
for (LineData lineData : invoiceData.getLines()) {
result.append(printLine(lineData));
}
result.append(String.format("Amount owed is %s\n", format.format(invoiceData.getTotalAmount())));
result.append(String.format("You earned %s credits\n", invoiceData.getVolumeCredits()));
return result.toString();
}
public String printLine(LineData lineData) {
return String.format(" %s: %s (%s seats)\n", lineData.getPlayName(), format.format(lineData.getAmount()), lineData.getAudience());
}
}
}