package com.github.kazuki43zoo.domain.model.timecard;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
@lombok.AllArgsConstructor
@lombok.NoArgsConstructor
@lombok.Data
public class WorkPlace implements Serializable {
private static final long serialVersionUID = 1L;
private static final LocalDate BASE_DATE = new LocalDate(0);
public static final String MAIN_OFFICE_UUID = "00000000-0000-0000-0000-000000000000";
private String workPlaceUuid;
private String workPlaceName;
private String workPlaceNameJa;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
private LocalTime baseBeginTime;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
private LocalTime baseFinishTime;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "H:mm")
private LocalTime unitTime;
private List<BreakTime> breakTimes;
@lombok.Setter(lombok.AccessLevel.NONE)
private transient int baseWorkTimeMinute;
@lombok.Setter(lombok.AccessLevel.NONE)
@lombok.Getter(lombok.AccessLevel.NONE)
private transient Interval baseWorkTimeInterval;
@lombok.Setter(lombok.AccessLevel.NONE)
@lombok.Getter(lombok.AccessLevel.NONE)
private transient List<Interval> breakTimeIntervals;
public void initialize() {
final List<Interval> breakTimeIntervals = new ArrayList<>();
if (getBreakTimes() != null) {
for (BreakTime breakTime : getBreakTimes()) {
breakTimeIntervals.addAll(breakTime.toBreakTimeIntervals());
}
Collections.sort(breakTimeIntervals, new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
return o1.getStart().compareTo(o2.getStart());
}
});
}
this.breakTimeIntervals = breakTimeIntervals;
this.baseWorkTimeInterval = new Interval(BASE_DATE.toDateTime(baseBeginTime),
BASE_DATE.toDateTime(baseFinishTime));
this.baseWorkTimeMinute = (int) toMinute(baseWorkTimeInterval)
- calculateContainsBreakTimeMinute(baseWorkTimeInterval);
}
int calculateWorkingMinute(final Interval workTimeInterval, final WorkPlace mainOffice) {
int workingMinute = (int) toMinute(workTimeInterval) - calculateContainsBreakTimeMinute(workTimeInterval);
return truncateWithTimeUnit(workingMinute, mainOffice);
}
int truncateWithTimeUnit(final int minute) {
return truncateWithTimeUnit(minute, this);
}
int truncateWithTimeUnit(final int minute, final WorkPlace mainOffice) {
int determinedMinute = 0;
int undeterminedMinute = minute;
int baseWorkTimeMinute = this.baseWorkTimeMinute;
if (baseWorkTimeMinute < mainOffice.getBaseWorkTimeMinute()
&& mainOffice.getBaseWorkTimeMinute() <= minute) {
baseWorkTimeMinute = mainOffice.getBaseWorkTimeMinute();
}
if (baseWorkTimeMinute <= minute) {
determinedMinute = baseWorkTimeMinute;
undeterminedMinute = minute - baseWorkTimeMinute;
}
final int unitTimeMinute = (getUnitTime().getHourOfDay() * 60)
+ getUnitTime().getMinuteOfHour();
return determinedMinute + undeterminedMinute - (undeterminedMinute % unitTimeMinute);
}
boolean isTardyOrEarlyLeaving(final DateTime beginTime, final DateTime finishTime) {
if (beginTime != null && beginTime.isAfter(baseWorkTimeInterval.getStart())) {
return true;
}
if (finishTime != null && finishTime.isBefore(baseWorkTimeInterval.getEnd())) {
return true;
}
return false;
}
int calculateContainsBreakTimeMinute(final Interval workTimeInterval) {
if (getBreakTimes() == null) {
return 0;
}
long minute = 0;
for (final Interval breakTimeInterval : breakTimeIntervals) {
if (workTimeInterval.overlaps(breakTimeInterval)) {
minute += toMinute(workTimeInterval.overlap(breakTimeInterval));
}
}
return (int) minute;
}
private long toMinute(final Interval interval) {
return TimeUnit.MILLISECONDS.toMinutes(interval.toDuration().getMillis());
}
}