1 /*
2 * Copyright (C) 2020-2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
3 */
4 package de.powerstat.validation.values;
5
6
7 import java.util.Objects;
8
9 import de.powerstat.validation.interfaces.IValueObject;
10
11
12 /**
13 * Day.
14 *
15 * Not DSGVO relevant.
16 *
17 * TODO Constructor with day, month
18 * TODO Constructor with day, month, year
19 * TODO Listener
20 * TODO hoursWithin = 24
21 * TODO min, max
22 */
23 public final class Day implements Comparable<Day>, IValueObject
24 {
25 /**
26 * Overflow constant.
27 */
28 private static final String OVERFLOW = "Overflow"; //$NON-NLS-1$
29
30 /**
31 * Underflow constant.
32 */
33 private static final String UNDERFLOW = "Underflow"; //$NON-NLS-1$
34
35 /* *
36 * Cache for singletons.
37 */
38 // private static final Map<Integer, Day> CACHE = new WeakHashMap<>();
39
40 /**
41 * Day.
42 */
43 private final int day;
44
45
46 /**
47 * Constructor.
48 *
49 * @param day Day 1-31
50 * @throws IndexOutOfBoundsException When the day is less than 1 or greater than 31
51 */
52 private Day(final int day)
53 {
54 super();
55 if ((day < 1) || (day > 31))
56 {
57 throw new IndexOutOfBoundsException("Day number out of range (1-31)!"); //$NON-NLS-1$
58 }
59 this.day = day;
60 }
61
62
63 /**
64 * Day factory.
65 *
66 * @param day Day 1-31
67 * @return Day object
68 */
69 public static Day of(final int day)
70 {
71 /*
72 synchronized (Day.class)
73 {
74 Day obj = Day.CACHE.get(day);
75 if (obj != null)
76 {
77 return obj;
78 }
79 obj = new Day(day);
80 Day.CACHE.put(Integer.valueOf(day), obj);
81 return obj;
82 }
83 */
84 return new Day(day);
85 }
86
87
88 /**
89 * Day factory.
90 *
91 * @param value String value
92 * @return Day object
93 */
94 public static Day of(final String value)
95 {
96 return of(Integer.parseInt(value));
97 }
98
99
100 /**
101 * Returns the value of this Day as an int.
102 *
103 * @return The numeric value represented by this object after conversion to type int.
104 */
105 public int intValue()
106 {
107 return this.day;
108 }
109
110
111 /**
112 * Returns the value of this Day as an String.
113 *
114 * @return The numeric value represented by this object after conversion to type String.
115 */
116 @Override
117 public String stringValue()
118 {
119 return String.valueOf(this.day);
120 }
121
122
123 /**
124 * Calculate hash code.
125 *
126 * @return Hash
127 * @see java.lang.Object#hashCode()
128 */
129 @Override
130 public int hashCode()
131 {
132 return Integer.hashCode(this.day);
133 }
134
135
136 /**
137 * Is equal with another object.
138 *
139 * @param obj Object
140 * @return true when equal, false otherwise
141 * @see java.lang.Object#equals(java.lang.Object)
142 */
143 @Override
144 public boolean equals(final Object obj)
145 {
146 if (this == obj)
147 {
148 return true;
149 }
150 if (!(obj instanceof Day))
151 {
152 return false;
153 }
154 final Day other = (Day)obj;
155 return this.day == other.day;
156 }
157
158
159 /**
160 * Returns the string representation of this Day.
161 *
162 * The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
163 *
164 * "Day[day=1]"
165 *
166 * @return String representation of this Day
167 * @see java.lang.Object#toString()
168 */
169 @Override
170 public String toString()
171 {
172 final var builder = new StringBuilder();
173 builder.append("Day[day=").append(this.day).append(']'); //$NON-NLS-1$
174 return builder.toString();
175 }
176
177
178 /**
179 * Compare with another object.
180 *
181 * @param obj Object to compare with
182 * @return 0: equal; 1: greater; -1: smaller
183 * @see java.lang.Comparable#compareTo(java.lang.Object)
184 */
185 @Override
186 public int compareTo(final Day obj)
187 {
188 Objects.requireNonNull(obj, "obj"); //$NON-NLS-1$
189 return Integer.compare(this.day, obj.day);
190 }
191
192
193 /**
194 * Add days to this day.
195 *
196 * @param days Days to add to this day
197 * @return New day after adding the days to this day
198 * @throws ArithmeticException In case of an overflow
199 */
200 public Day add(final Days days)
201 {
202 final int newDay = Math.toIntExact(Math.addExact(this.day, days.longValue()));
203 if (newDay > 31) // TODO depends on month and year
204 {
205 // TODO Listener
206 throw new ArithmeticException(Day.OVERFLOW);
207 }
208 return Day.of(newDay);
209 }
210
211
212 /**
213 * Subtract days from this day.
214 *
215 * @param days Days to subtract from this day
216 * @return New day after subtracting days from this day
217 * @throws ArithmeticException In case of an underflow
218 */
219 public Day subtract(final Days days)
220 {
221 final int newDay = Math.toIntExact(Math.subtractExact(this.day, days.longValue()));
222 if (newDay <= 0)
223 {
224 // TODO Listener
225 throw new ArithmeticException(Day.UNDERFLOW);
226 }
227 return Day.of(newDay);
228 }
229
230
231 /**
232 * Increment this day.
233 *
234 * @return New day after incrementing this day
235 * @throws ArithmeticException In case of an overflow
236 */
237 public Day increment()
238 {
239 final int newDay = Math.incrementExact(this.day);
240 if (newDay == 32) // TODO depends on month and year
241 {
242 // TODO Listener
243 throw new ArithmeticException(Day.OVERFLOW);
244 }
245 return Day.of(newDay);
246 }
247
248
249 /**
250 * Decrement this day.
251 *
252 * @return New day after decrement this day
253 * @throws ArithmeticException In case of an overflow
254 */
255 public Day decrement()
256 {
257 final int newDay = Math.decrementExact(this.day);
258 if (newDay == 0)
259 {
260 // TODO Listener
261 throw new ArithmeticException(Day.UNDERFLOW);
262 }
263 return Day.of(newDay);
264 }
265
266 }