package at.procon.eventhub.config;

import at.procon.eventhub.esperpoc.dto.EsperActivityMergeMode;
import at.procon.eventhub.esperpoc.dto.EsperOperatingPeriodEngineMode;
import at.procon.eventhub.esperpoc.dto.EsperUnknownTreatmentMode;
import at.procon.eventhub.esperpoc.dto.EsperShiftResolutionMode;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

import at.procon.eventhub.dto.AcquisitionStrategy;
import at.procon.eventhub.dto.EventFamily;
import at.procon.eventhub.dto.EventSourceDto;
import at.procon.eventhub.dto.ImportMode;
import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.dto.SchedulerTriggerMode;
import at.procon.eventhub.dto.SourceGroupRefDto;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "eventhub")
public class EventHubProperties {

    public enum JdbcExtractionIngestMode {
        SYNC_DIRECT,
        CAMEL_ROUTE
    }

    private final Batch batch = new Batch();
    private final Tachograph tachograph = new Tachograph();
    private final TachographFileSession tachographFileSession = new TachographFileSession();
    private final EsperPoc esperPoc = new EsperPoc();
    private final YellowFox yellowFox = new YellowFox();

    public Batch getBatch() {
        return batch;
    }

    public Tachograph getTachograph() {
        return tachograph;
    }

    public TachographFileSession getTachographFileSession() {
        return tachographFileSession;
    }

    public EsperPoc getEsperPoc() {
        return esperPoc;
    }

    public YellowFox getYellowFox() {
        return yellowFox;
    }

    public static class EsperPoc {
        private EsperActivityMergeMode activityMergeMode = EsperActivityMergeMode.JAVA;
        private EsperShiftResolutionMode shiftResolutionMode = EsperShiftResolutionMode.JAVA;
        private final OperatingPeriodEvaluation operatingPeriodEvaluation = new OperatingPeriodEvaluation();

        public EsperActivityMergeMode getActivityMergeMode() {
            return activityMergeMode;
        }

        public void setActivityMergeMode(EsperActivityMergeMode activityMergeMode) {
            this.activityMergeMode = activityMergeMode == null ? EsperActivityMergeMode.JAVA : activityMergeMode;
        }

        public EsperShiftResolutionMode getShiftResolutionMode() {
            return shiftResolutionMode;
        }

        public void setShiftResolutionMode(EsperShiftResolutionMode shiftResolutionMode) {
            this.shiftResolutionMode = shiftResolutionMode == null ? EsperShiftResolutionMode.JAVA : shiftResolutionMode;
        }

        public OperatingPeriodEvaluation getOperatingPeriodEvaluation() {
            return operatingPeriodEvaluation;
        }
    }

    public static class OperatingPeriodEvaluation {
        private int operatingSplitIdleHours = 7;
        private int significantDrivingMinutes = 3;
        private int mergeGapSeconds = 0;
        private int gapDetectionToleranceSeconds = 0;
        private EsperUnknownTreatmentMode unknownTreatmentMode = EsperUnknownTreatmentMode.AS_BREAK_REST;
        private EsperOperatingPeriodEngineMode engineMode = EsperOperatingPeriodEngineMode.STREAM_COLLECTOR;

        public int getOperatingSplitIdleHours() {
            return operatingSplitIdleHours;
        }

        public void setOperatingSplitIdleHours(int operatingSplitIdleHours) {
            this.operatingSplitIdleHours = Math.max(1, operatingSplitIdleHours);
        }

        public int getSignificantDrivingMinutes() {
            return significantDrivingMinutes;
        }

        public void setSignificantDrivingMinutes(int significantDrivingMinutes) {
            this.significantDrivingMinutes = Math.max(1, significantDrivingMinutes);
        }

        public int getMergeGapSeconds() {
            return mergeGapSeconds;
        }

        public void setMergeGapSeconds(int mergeGapSeconds) {
            this.mergeGapSeconds = Math.max(0, mergeGapSeconds);
        }

        public int getGapDetectionToleranceSeconds() {
            return gapDetectionToleranceSeconds;
        }

        public void setGapDetectionToleranceSeconds(int gapDetectionToleranceSeconds) {
            this.gapDetectionToleranceSeconds = Math.max(0, gapDetectionToleranceSeconds);
        }

        public EsperUnknownTreatmentMode getUnknownTreatmentMode() {
            return unknownTreatmentMode;
        }

        public void setUnknownTreatmentMode(EsperUnknownTreatmentMode unknownTreatmentMode) {
            this.unknownTreatmentMode = unknownTreatmentMode == null
                    ? EsperUnknownTreatmentMode.AS_BREAK_REST
                    : unknownTreatmentMode;
        }

        public EsperOperatingPeriodEngineMode getEngineMode() {
            return engineMode;
        }

        public void setEngineMode(EsperOperatingPeriodEngineMode engineMode) {
            this.engineMode = engineMode == null
                    ? EsperOperatingPeriodEngineMode.STREAM_COLLECTOR
                    : engineMode;
        }
    }

    public static class Batch {
        /** Number of events collected before a package is persisted. */
        private int completionSize = 5000;

        /** Maximum time to wait for more events belonging to the same package key. */
        private Duration completionTimeout = Duration.ofSeconds(5);

        /** Maximum number of normalized events buffered before producers apply backpressure. */
        private int queueSize = 10000;

        /** Number of parallel consumers draining the normalized-event queue. */
        private int concurrentConsumers = 4;

        /** Whether producers should wait for queue capacity instead of failing immediately. */
        private boolean blockWhenFull = true;

        /** Maximum time a producer waits for queue capacity before failing the import. */
        private Duration queueOfferTimeout = Duration.ofMinutes(5);

        public int getCompletionSize() {
            return completionSize;
        }

        public void setCompletionSize(int completionSize) {
            this.completionSize = completionSize;
        }

        public Duration getCompletionTimeout() {
            return completionTimeout;
        }

        public void setCompletionTimeout(Duration completionTimeout) {
            this.completionTimeout = completionTimeout;
        }

        public int getQueueSize() {
            return queueSize;
        }

        public void setQueueSize(int queueSize) {
            this.queueSize = Math.max(1, queueSize);
        }

        public int getConcurrentConsumers() {
            return concurrentConsumers;
        }

        public void setConcurrentConsumers(int concurrentConsumers) {
            this.concurrentConsumers = Math.max(1, concurrentConsumers);
        }

        public boolean isBlockWhenFull() {
            return blockWhenFull;
        }

        public void setBlockWhenFull(boolean blockWhenFull) {
            this.blockWhenFull = blockWhenFull;
        }

        public Duration getQueueOfferTimeout() {
            return queueOfferTimeout;
        }

        public void setQueueOfferTimeout(Duration queueOfferTimeout) {
            if (queueOfferTimeout != null && !queueOfferTimeout.isNegative()) {
                this.queueOfferTimeout = queueOfferTimeout;
            }
        }
    }

    public static class Tachograph {
        /** Default chunk size for initial/backfill occurred-time imports. */
        private int defaultChunkDays = 1;

        /** Overlap used by occurred-at fallback incremental imports. */
        private Duration occurredAtOverlap = Duration.ofDays(7);

        /** Regular scheduler scan interval; each configured plan still uses its own cron. */
        private Duration schedulerPollInterval = Duration.ofMinutes(1);

        /** Whether scheduled tachograph imports are enabled. */
        private boolean schedulerEnabled = false;

        private SchedulerTriggerMode schedulerTriggerMode = SchedulerTriggerMode.PLAN_ONLY;

        /** How JDBC extraction batches are handed over to the ingest pipeline. */
        private JdbcExtractionIngestMode jdbcExtractionIngestMode = JdbcExtractionIngestMode.SYNC_DIRECT;

        /** Whether master-data refresh reconciles vehicle registrations and assignments. */
        private boolean syncVehicleRegistrationsOnMasterDataUpdate = true;

        /** Configured tenant/source import plans. */
        private List<ConfiguredImportPlan> importPlans = new ArrayList<>();

        /** Optional external tachograph DB datasource. If absent, the no-op extractor is used. */
        private TachographDataSource datasource = new TachographDataSource();

        public int getDefaultChunkDays() {
            return defaultChunkDays;
        }

        public void setDefaultChunkDays(int defaultChunkDays) {
            this.defaultChunkDays = Math.max(1, defaultChunkDays);
        }

        public Duration getOccurredAtOverlap() {
            return occurredAtOverlap;
        }

        public void setOccurredAtOverlap(Duration occurredAtOverlap) {
            this.occurredAtOverlap = occurredAtOverlap;
        }

        public Duration getSchedulerPollInterval() {
            return schedulerPollInterval;
        }

        public void setSchedulerPollInterval(Duration schedulerPollInterval) {
            this.schedulerPollInterval = schedulerPollInterval;
        }

        public boolean isSchedulerEnabled() {
            return schedulerEnabled;
        }

        public void setSchedulerEnabled(boolean schedulerEnabled) {
            this.schedulerEnabled = schedulerEnabled;
        }

        public SchedulerTriggerMode getSchedulerTriggerMode() {
            return schedulerTriggerMode;
        }

        public void setSchedulerTriggerMode(SchedulerTriggerMode schedulerTriggerMode) {
            this.schedulerTriggerMode = schedulerTriggerMode == null ? SchedulerTriggerMode.PLAN_ONLY : schedulerTriggerMode;
        }

        public JdbcExtractionIngestMode getJdbcExtractionIngestMode() {
            return jdbcExtractionIngestMode;
        }

        public void setJdbcExtractionIngestMode(JdbcExtractionIngestMode jdbcExtractionIngestMode) {
            this.jdbcExtractionIngestMode = jdbcExtractionIngestMode == null
                    ? JdbcExtractionIngestMode.SYNC_DIRECT
                    : jdbcExtractionIngestMode;
        }

        public boolean isSyncVehicleRegistrationsOnMasterDataUpdate() {
            return syncVehicleRegistrationsOnMasterDataUpdate;
        }

        public void setSyncVehicleRegistrationsOnMasterDataUpdate(boolean syncVehicleRegistrationsOnMasterDataUpdate) {
            this.syncVehicleRegistrationsOnMasterDataUpdate = syncVehicleRegistrationsOnMasterDataUpdate;
        }

        public List<ConfiguredImportPlan> getImportPlans() {
            return importPlans;
        }

        public void setImportPlans(List<ConfiguredImportPlan> importPlans) {
            this.importPlans = importPlans == null ? new ArrayList<>() : importPlans;
        }

        public TachographDataSource getDatasource() {
            return datasource;
        }

        public void setDatasource(TachographDataSource datasource) {
            this.datasource = datasource == null ? new TachographDataSource() : datasource;
        }
    }

    public static class TachographFileSession {
        private Duration ttl = Duration.ofHours(4);
        private int maxSessions = 100;
        private long maxFileSizeBytes = 20L * 1024L * 1024L;
        private final LegalRequirements legalRequirements = new LegalRequirements();
        private final Processing processing = new Processing();

        public Duration getTtl() {
            return ttl;
        }

        public void setTtl(Duration ttl) {
            if (ttl != null && !ttl.isNegative() && !ttl.isZero()) {
                this.ttl = ttl;
            }
        }

        public int getMaxSessions() {
            return maxSessions;
        }

        public void setMaxSessions(int maxSessions) {
            this.maxSessions = Math.max(1, maxSessions);
        }

        public long getMaxFileSizeBytes() {
            return maxFileSizeBytes;
        }

        public void setMaxFileSizeBytes(long maxFileSizeBytes) {
            this.maxFileSizeBytes = Math.max(1024L, maxFileSizeBytes);
        }

        public LegalRequirements getLegalRequirements() {
            return legalRequirements;
        }

        public Processing getProcessing() {
            return processing;
        }
    }

    public static class Processing {
        private int operatingSplitIdleHours = 7;
        private int significantDrivingMinutes = 3;
        private int mergeGapSeconds = 0;
        private int gapDetectionToleranceSeconds = 0;

        public int getOperatingSplitIdleHours() {
            return operatingSplitIdleHours;
        }

        public void setOperatingSplitIdleHours(int operatingSplitIdleHours) {
            this.operatingSplitIdleHours = Math.max(1, operatingSplitIdleHours);
        }

        public int getSignificantDrivingMinutes() {
            return significantDrivingMinutes;
        }

        public void setSignificantDrivingMinutes(int significantDrivingMinutes) {
            this.significantDrivingMinutes = Math.max(1, significantDrivingMinutes);
        }

        public int getMergeGapSeconds() {
            return mergeGapSeconds;
        }

        public void setMergeGapSeconds(int mergeGapSeconds) {
            this.mergeGapSeconds = Math.max(0, mergeGapSeconds);
        }

        public int getGapDetectionToleranceSeconds() {
            return gapDetectionToleranceSeconds;
        }

        public void setGapDetectionToleranceSeconds(int gapDetectionToleranceSeconds) {
            this.gapDetectionToleranceSeconds = Math.max(0, gapDetectionToleranceSeconds);
        }
    }

    public static class LegalRequirements {
        private static final String DEFAULT_BASE_URL = "https://legalrequirements.services.bytebar.eu/ODataV4/LR";

        private String baseUrl = DEFAULT_BASE_URL;
        private String username;
        private String password;
        private Duration connectTimeout = Duration.ofSeconds(20);
        private Duration readTimeout = Duration.ofMinutes(2);
        private boolean resetSessionAfterUse = false;

        public String getBaseUrl() {
            return baseUrl;
        }

        public void setBaseUrl(String baseUrl) {
            this.baseUrl = normalizeBaseUrl(baseUrl);
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public Duration getConnectTimeout() {
            return connectTimeout;
        }

        public void setConnectTimeout(Duration connectTimeout) {
            if (connectTimeout != null && !connectTimeout.isNegative() && !connectTimeout.isZero()) {
                this.connectTimeout = connectTimeout;
            }
        }

        public Duration getReadTimeout() {
            return readTimeout;
        }

        public void setReadTimeout(Duration readTimeout) {
            if (readTimeout != null && !readTimeout.isNegative() && !readTimeout.isZero()) {
                this.readTimeout = readTimeout;
            }
        }

        public boolean isResetSessionAfterUse() {
            return resetSessionAfterUse;
        }

        public void setResetSessionAfterUse(boolean resetSessionAfterUse) {
            this.resetSessionAfterUse = resetSessionAfterUse;
        }

        private String normalizeBaseUrl(String baseUrl) {
            if (baseUrl == null || baseUrl.isBlank()) {
                return DEFAULT_BASE_URL;
            }

            String normalized = baseUrl.trim();
            while (normalized.startsWith(":")) {
                normalized = normalized.substring(1).trim();
            }
            while (normalized.endsWith("/")) {
                normalized = normalized.substring(0, normalized.length() - 1).trim();
            }

            return normalized.isBlank() ? DEFAULT_BASE_URL : normalized;
        }
    }

    public static class TachographDataSource {
        private String jdbcUrl;
        private String username;
        private String password;
        private String driverClassName;

        public String getJdbcUrl() {
            return jdbcUrl;
        }

        public void setJdbcUrl(String jdbcUrl) {
            this.jdbcUrl = jdbcUrl;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getDriverClassName() {
            return driverClassName;
        }

        public void setDriverClassName(String driverClassName) {
            this.driverClassName = driverClassName;
        }
    }

    public static class YellowFox {
        /** Default chunk size for initial/backfill D8 booking imports. */
        private int defaultChunkDays = 1;

        /** Overlap used by incremental utc/eventid cursor imports to catch late rows and ignition transitions. */
        private Duration occurredAtOverlap = Duration.ofHours(2);

        /** How JDBC extraction batches are handed over to the ingest pipeline. */
        private JdbcExtractionIngestMode jdbcExtractionIngestMode = JdbcExtractionIngestMode.SYNC_DIRECT;

        /** Regular scheduler scan interval; each configured plan still uses its own cron. */
        private Duration schedulerPollInterval = Duration.ofMinutes(1);

        /** Whether scheduled YellowFox imports are enabled. */
        private boolean schedulerEnabled = false;

        private SchedulerTriggerMode schedulerTriggerMode = SchedulerTriggerMode.PLAN_ONLY;

        /** Emit a first ignition snapshot per vehicle if no previous D8 ignition state exists in the imported window. */
        private boolean emitInitialIgnitionSnapshot = false;

        /** Whether master-data refresh reconciles vehicle registrations and assignments. */
        private boolean syncVehicleRegistrationsOnMasterDataUpdate = true;

        /** Configured tenant/source import plans. */
        private List<ConfiguredImportPlan> importPlans = new ArrayList<>();

        /** Optional external YellowFox mirror datasource. If absent, the no-op extractor is used. */
        private YellowFoxDataSource datasource = new YellowFoxDataSource();

        public int getDefaultChunkDays() {
            return defaultChunkDays;
        }

        public void setDefaultChunkDays(int defaultChunkDays) {
            this.defaultChunkDays = Math.max(1, defaultChunkDays);
        }

        public Duration getOccurredAtOverlap() {
            return occurredAtOverlap;
        }

        public void setOccurredAtOverlap(Duration occurredAtOverlap) {
            if (occurredAtOverlap != null && !occurredAtOverlap.isNegative()) {
                this.occurredAtOverlap = occurredAtOverlap;
            }
        }

        public JdbcExtractionIngestMode getJdbcExtractionIngestMode() {
            return jdbcExtractionIngestMode;
        }

        public void setJdbcExtractionIngestMode(JdbcExtractionIngestMode jdbcExtractionIngestMode) {
            this.jdbcExtractionIngestMode = jdbcExtractionIngestMode == null
                    ? JdbcExtractionIngestMode.SYNC_DIRECT
                    : jdbcExtractionIngestMode;
        }

        public Duration getSchedulerPollInterval() {
            return schedulerPollInterval;
        }

        public void setSchedulerPollInterval(Duration schedulerPollInterval) {
            if (schedulerPollInterval != null && !schedulerPollInterval.isNegative()) {
                this.schedulerPollInterval = schedulerPollInterval;
            }
        }

        public boolean isSchedulerEnabled() {
            return schedulerEnabled;
        }

        public void setSchedulerEnabled(boolean schedulerEnabled) {
            this.schedulerEnabled = schedulerEnabled;
        }

        public SchedulerTriggerMode getSchedulerTriggerMode() {
            return schedulerTriggerMode;
        }

        public void setSchedulerTriggerMode(SchedulerTriggerMode schedulerTriggerMode) {
            this.schedulerTriggerMode = schedulerTriggerMode == null ? SchedulerTriggerMode.PLAN_ONLY : schedulerTriggerMode;
        }

        public boolean isEmitInitialIgnitionSnapshot() {
            return emitInitialIgnitionSnapshot;
        }

        public void setEmitInitialIgnitionSnapshot(boolean emitInitialIgnitionSnapshot) {
            this.emitInitialIgnitionSnapshot = emitInitialIgnitionSnapshot;
        }

        public boolean isSyncVehicleRegistrationsOnMasterDataUpdate() {
            return syncVehicleRegistrationsOnMasterDataUpdate;
        }

        public void setSyncVehicleRegistrationsOnMasterDataUpdate(boolean syncVehicleRegistrationsOnMasterDataUpdate) {
            this.syncVehicleRegistrationsOnMasterDataUpdate = syncVehicleRegistrationsOnMasterDataUpdate;
        }

        public List<ConfiguredImportPlan> getImportPlans() {
            return importPlans;
        }

        public void setImportPlans(List<ConfiguredImportPlan> importPlans) {
            this.importPlans = importPlans == null ? new ArrayList<>() : importPlans;
        }

        public YellowFoxDataSource getDatasource() {
            return datasource;
        }

        public void setDatasource(YellowFoxDataSource datasource) {
            this.datasource = datasource == null ? new YellowFoxDataSource() : datasource;
        }
    }

    public static class YellowFoxDataSource {
        private String jdbcUrl;
        private String username;
        private String password;
        private String driverClassName;

        public String getJdbcUrl() {
            return jdbcUrl;
        }

        public void setJdbcUrl(String jdbcUrl) {
            this.jdbcUrl = jdbcUrl;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getDriverClassName() {
            return driverClassName;
        }

        public void setDriverClassName(String driverClassName) {
            this.driverClassName = driverClassName;
        }
    }

    public static class ConfiguredImportPlan {
        private String planKey;
        private boolean enabled = true;
        private String cron;
        private String tenantKey;
        private EventSourceDto eventSource;
        private SourceGroupRefDto sourceGroup;
        private ImportScopeDto importScope;
        private Set<EventFamily> eventFamilies = EnumSet.allOf(EventFamily.class);
        private ImportMode initialMode = ImportMode.INITIAL_BACKFILL;
        private ImportMode scheduledMode = ImportMode.INCREMENTAL_UPDATE;
        private AcquisitionStrategy initialStrategy = AcquisitionStrategy.OCCURRED_AT_WINDOW_WITH_OVERLAP;
        private AcquisitionStrategy scheduledStrategy = AcquisitionStrategy.SOURCE_PACKAGE_WATERMARK;
        private boolean refreshMasterDataFirst = true;
        private OffsetDateTime initialOccurredFrom;
        private OffsetDateTime initialOccurredTo;
        private boolean runInitialOnStartup = false;

        public String getPlanKey() {
            return planKey;
        }

        public void setPlanKey(String planKey) {
            this.planKey = planKey;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public String getCron() {
            return cron;
        }

        public void setCron(String cron) {
            this.cron = cron;
        }

        public String getTenantKey() {
            return tenantKey;
        }

        public void setTenantKey(String tenantKey) {
            this.tenantKey = tenantKey;
        }

        public EventSourceDto getEventSource() {
            return eventSource;
        }

        public void setEventSource(EventSourceDto eventSource) {
            this.eventSource = eventSource;
        }

        public SourceGroupRefDto getSourceGroup() {
            return sourceGroup;
        }

        public void setSourceGroup(SourceGroupRefDto sourceGroup) {
            this.sourceGroup = sourceGroup;
        }

        public ImportScopeDto getImportScope() {
            return importScope;
        }

        public void setImportScope(ImportScopeDto importScope) {
            this.importScope = importScope;
        }

        public Set<EventFamily> getEventFamilies() {
            return eventFamilies;
        }

        public void setEventFamilies(Set<EventFamily> eventFamilies) {
            this.eventFamilies = eventFamilies == null || eventFamilies.isEmpty()
                    ? EnumSet.allOf(EventFamily.class)
                    : EnumSet.copyOf(eventFamilies);
        }

        public ImportMode getInitialMode() {
            return initialMode;
        }

        public void setInitialMode(ImportMode initialMode) {
            this.initialMode = initialMode;
        }

        public ImportMode getScheduledMode() {
            return scheduledMode;
        }

        public void setScheduledMode(ImportMode scheduledMode) {
            this.scheduledMode = scheduledMode;
        }

        public AcquisitionStrategy getInitialStrategy() {
            return initialStrategy;
        }

        public void setInitialStrategy(AcquisitionStrategy initialStrategy) {
            this.initialStrategy = initialStrategy;
        }

        public AcquisitionStrategy getScheduledStrategy() {
            return scheduledStrategy;
        }

        public void setScheduledStrategy(AcquisitionStrategy scheduledStrategy) {
            this.scheduledStrategy = scheduledStrategy;
        }

        public boolean isRefreshMasterDataFirst() {
            return refreshMasterDataFirst;
        }

        public void setRefreshMasterDataFirst(boolean refreshMasterDataFirst) {
            this.refreshMasterDataFirst = refreshMasterDataFirst;
        }

        public OffsetDateTime getInitialOccurredFrom() {
            return initialOccurredFrom;
        }

        public void setInitialOccurredFrom(OffsetDateTime initialOccurredFrom) {
            this.initialOccurredFrom = initialOccurredFrom;
        }

        public OffsetDateTime getInitialOccurredTo() {
            return initialOccurredTo;
        }

        public void setInitialOccurredTo(OffsetDateTime initialOccurredTo) {
            this.initialOccurredTo = initialOccurredTo;
        }

        public boolean isRunInitialOnStartup() {
            return runInitialOnStartup;
        }

        public void setRunInitialOnStartup(boolean runInitialOnStartup) {
            this.runInitialOnStartup = runInitialOnStartup;
        }
    }
}
