207 lines
5.9 KiB
TypeScript
207 lines
5.9 KiB
TypeScript
import {
|
|
MatcherException,
|
|
MatcherExceptionCode,
|
|
} from '../../../exceptions/matcher.exception';
|
|
import { MarginDurations } from '../../types/margin-durations.type';
|
|
import { IRequestTime } from '../../interfaces/time-request.interface';
|
|
import { DAYS } from '../../types/days.const';
|
|
import { TimeSchedule } from '../../types/time-schedule.type';
|
|
import { Frequency } from '../../../../ad/domain/types/frequency.enum';
|
|
import { Day } from '../../types/day.type';
|
|
import { IConvertTime } from '../../interfaces/time-converter.interface';
|
|
|
|
export class Time {
|
|
private timeRequest: IRequestTime;
|
|
private defaultValidityDuration: number;
|
|
private timeConverter: IConvertTime;
|
|
frequency: Frequency;
|
|
fromDate: Date;
|
|
toDate: Date;
|
|
schedule: TimeSchedule;
|
|
marginDurations: MarginDurations;
|
|
|
|
constructor(
|
|
timeRequest: IRequestTime,
|
|
defaultMarginDuration: number,
|
|
defaultValidityDuration: number,
|
|
timeConverter: IConvertTime,
|
|
) {
|
|
this.timeRequest = timeRequest;
|
|
this.defaultValidityDuration = defaultValidityDuration;
|
|
this.timeConverter = timeConverter;
|
|
this.schedule = {};
|
|
this.marginDurations = {
|
|
mon: defaultMarginDuration,
|
|
tue: defaultMarginDuration,
|
|
wed: defaultMarginDuration,
|
|
thu: defaultMarginDuration,
|
|
fri: defaultMarginDuration,
|
|
sat: defaultMarginDuration,
|
|
sun: defaultMarginDuration,
|
|
};
|
|
}
|
|
|
|
init = (): void => {
|
|
this.validateBaseDate();
|
|
this.validatePunctualRequest();
|
|
this.validateRecurrentRequest();
|
|
this.setPunctualRequest();
|
|
this.setRecurrentRequest();
|
|
this.setMargindurations();
|
|
};
|
|
|
|
private validateBaseDate = (): void => {
|
|
if (!this.timeRequest.departure && !this.timeRequest.fromDate) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'departure or fromDate is required',
|
|
);
|
|
}
|
|
};
|
|
|
|
private validatePunctualRequest = (): void => {
|
|
if (this.timeRequest.departure) {
|
|
this.fromDate = this.toDate = new Date(this.timeRequest.departure);
|
|
if (!this.isDate(this.fromDate)) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'Wrong departure date',
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
private validateRecurrentRequest = (): void => {
|
|
if (this.timeRequest.fromDate) {
|
|
this.fromDate = new Date(this.timeRequest.fromDate);
|
|
if (!this.isDate(this.fromDate)) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'Wrong fromDate',
|
|
);
|
|
}
|
|
}
|
|
if (this.timeRequest.toDate) {
|
|
this.toDate = new Date(this.timeRequest.toDate);
|
|
if (!this.isDate(this.toDate)) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'Wrong toDate',
|
|
);
|
|
}
|
|
if (this.toDate < this.fromDate) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'toDate must be after fromDate',
|
|
);
|
|
}
|
|
}
|
|
if (this.timeRequest.fromDate) {
|
|
this.validateSchedule();
|
|
}
|
|
};
|
|
|
|
private validateSchedule = (): void => {
|
|
if (!this.timeRequest.schedule) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'Schedule is required',
|
|
);
|
|
}
|
|
if (
|
|
!Object.keys(this.timeRequest.schedule).some((elem) =>
|
|
DAYS.includes(elem),
|
|
)
|
|
) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'No valid day in the given schedule',
|
|
);
|
|
}
|
|
Object.keys(this.timeRequest.schedule).map((day) => {
|
|
const time = new Date('1970-01-01 ' + this.timeRequest.schedule[day]);
|
|
if (!this.isDate(time)) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
`Wrong time for ${day} in schedule`,
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
private setPunctualRequest = (): void => {
|
|
if (this.timeRequest.departure) {
|
|
this.frequency = Frequency.PUNCTUAL;
|
|
this.schedule[Day[this.fromDate.getDay()]] = this.timeConverter.toUtcDate(
|
|
this.fromDate,
|
|
this.timeRequest.timezone,
|
|
);
|
|
}
|
|
};
|
|
|
|
private setRecurrentRequest = (): void => {
|
|
if (this.timeRequest.fromDate) {
|
|
this.frequency = Frequency.RECURRENT;
|
|
if (!this.toDate) {
|
|
this.toDate = this.addDays(this.fromDate, this.defaultValidityDuration);
|
|
}
|
|
this.setSchedule();
|
|
}
|
|
};
|
|
|
|
private setSchedule = (): void => {
|
|
Object.keys(this.timeRequest.schedule).map((day) => {
|
|
this.schedule[day] = this.timeConverter.toUtcDate(
|
|
new Date(
|
|
`${this.fromDate.getFullYear()}-${this.fromDate.getMonth()}-${this.fromDate.getDate()} ${
|
|
this.timeRequest.schedule[day]
|
|
}`,
|
|
),
|
|
this.timeRequest.timezone,
|
|
);
|
|
});
|
|
};
|
|
|
|
private setMargindurations = (): void => {
|
|
if (this.timeRequest.marginDuration) {
|
|
const duration = Math.abs(this.timeRequest.marginDuration);
|
|
this.marginDurations = {
|
|
mon: duration,
|
|
tue: duration,
|
|
wed: duration,
|
|
thu: duration,
|
|
fri: duration,
|
|
sat: duration,
|
|
sun: duration,
|
|
};
|
|
}
|
|
if (this.timeRequest.marginDurations) {
|
|
if (
|
|
!Object.keys(this.timeRequest.marginDurations).some((elem) =>
|
|
DAYS.includes(elem),
|
|
)
|
|
) {
|
|
throw new MatcherException(
|
|
MatcherExceptionCode.INVALID_ARGUMENT,
|
|
'No valid day in the given margin durations',
|
|
);
|
|
}
|
|
Object.keys(this.timeRequest.marginDurations).map((day) => {
|
|
this.marginDurations[day] = Math.abs(
|
|
this.timeRequest.marginDurations[day],
|
|
);
|
|
});
|
|
}
|
|
};
|
|
|
|
private isDate = (date: Date): boolean => {
|
|
return date instanceof Date && isFinite(+date);
|
|
};
|
|
|
|
private addDays = (date: Date, days: number): Date => {
|
|
const result = new Date(date);
|
|
result.setDate(result.getDate() + days);
|
|
return result;
|
|
};
|
|
}
|