[BP-841] Add validators for cyclic reporting

Signed-off-by: Christopher Keim <keim@develop-group.de>
diff --git a/src/app/cyclic-reporting/validators/cyclic-report.validators.spec.ts b/src/app/cyclic-reporting/validators/cyclic-report.validators.spec.ts
new file mode 100644
index 0000000..d2a83d0
--- /dev/null
+++ b/src/app/cyclic-reporting/validators/cyclic-report.validators.spec.ts
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Copyright © 2020 Basys GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+import {FormControl, ValidationErrors, ValidatorFn} from '@angular/forms';
+import {CyclicReportObject} from '@shared/model/CyclicReportObject';
+import {CyclicReportValidators} from './cyclic-report.validators';
+
+function getValidationErrors<T>(...validators: ValidatorFn[]): (data: T) => ValidationErrors {
+  return (data: T) => new FormControl(data, validators).errors;
+}
+
+describe('CyclicReportValidators', () => {
+
+  it('validationDate should check if the validation date is correctly set', () => {
+    const errors = { invalidDate: true };
+    const getValidationDateError = getValidationErrors<Partial<CyclicReportObject>>(CyclicReportValidators.validationDate);
+
+    expect(getValidationDateError(null)).toBe(null);
+    expect(getValidationDateError({})).toBe(null);
+
+    expect(getValidationDateError({
+      validToDayOffset: 1, validToHour: 12, validToMinute: 30,
+      validFromDayOffset: 0, validFromHour: 12, validFromMinute: 30
+    })).toEqual(null);
+
+    expect(getValidationDateError({
+      validToDayOffset: 1, validToHour: 12, validToMinute: 30,
+      validFromDayOffset: 1, validFromHour: 0, validFromMinute: 30
+    })).toEqual(null);
+
+    expect(getValidationDateError({
+      validToDayOffset: 1, validToHour: 12, validToMinute: 30,
+      validFromDayOffset: 1, validFromHour: 12, validFromMinute: 0
+    })).toEqual(null);
+
+    expect(getValidationDateError({
+      validToDayOffset: 1, validToHour: 12, validToMinute: 30,
+      validFromDayOffset: 1, validFromHour: 12, validFromMinute: 30
+    })).toEqual(errors);
+
+    expect(getValidationDateError({
+      validToDayOffset: 1, validToHour: 12, validToMinute: 30,
+      validFromDayOffset: 1, validFromHour: 14, validFromMinute: 0
+    })).toEqual(errors);
+
+    expect(getValidationDateError({
+      validToDayOffset: 1, validToHour: 12, validToMinute: 30,
+      validFromDayOffset: 12, validFromHour: 10, validFromMinute: 0
+    })).toEqual(errors);
+
+  });
+
+});
diff --git a/src/app/cyclic-reporting/validators/cyclic-report.validators.ts b/src/app/cyclic-reporting/validators/cyclic-report.validators.ts
new file mode 100644
index 0000000..7d0a79f
--- /dev/null
+++ b/src/app/cyclic-reporting/validators/cyclic-report.validators.ts
@@ -0,0 +1,51 @@
+/********************************************************************************
+ * Copyright © 2020 Basys GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms';
+import {CyclicReportObject} from '@shared/model/CyclicReportObject';
+
+export class CyclicReportValidators {
+
+  public static validationDate: ValidatorFn = (control: AbstractControl): ValidationErrors => {
+    const error = { invalidDate: true };
+
+    if (control.value == null) {
+      return;
+    }
+
+    const value: CyclicReportObject = control.value;
+    const { validFromDayOffset, validFromHour, validFromMinute, validToDayOffset, validToHour, validToMinute} = value;
+
+    if ( ![validFromDayOffset, validFromHour, validFromMinute, validToDayOffset, validToHour, validToMinute].every(Number.isInteger) ) {
+      return;
+    }
+
+    const isLargerZero = (arg: number) => arg === 0 ? null : arg > 0;
+
+    const isDayOffsetValid = isLargerZero(validToDayOffset - validFromDayOffset);
+    const isHourValid = isLargerZero(validToHour - validFromHour);
+    const isMinuteValid = isLargerZero(validToMinute - validFromMinute);
+
+    if (isDayOffsetValid) {
+      return;
+    }
+
+    if (isDayOffsetValid == null && isHourValid) {
+      return;
+    }
+
+    if (isDayOffsetValid == null && isHourValid == null && isMinuteValid) {
+      return;
+    }
+
+    return error;
+  }
+
+}