package com.capgemini.reports.periodicity;

import com.capgemini.reports.database.javabean.enumeration.SchedulingEnum;
import com.capgemini.reports.database.manager.MngSchedulingCriteriaVal.SchedulingCriteriaValue;

import java.util.List;

/**
 * Object representing various scheduling periodicities and their parameters.<br>
 * These periodicities are also ablo to presnt themselves as a {@link List} of database entries ({@link SchedulingCriteriaValue}s) using {@link SchedulingPeriod#asCriteriaValues()}.
 */
public interface SchedulingPeriod {

    /**
     * Returns the instance of {@link SchedulingEnum} that represents the overall periodicity of this SchedulingPeriod.
     *
     * @return the instance of {@link SchedulingEnum}
     */
    SchedulingEnum getPeriodicity();

    /**
     * Returns a {@link List} of database entries ({@link SchedulingCriteriaValue}s) that represent this period object.<br>
     * Example: period=weekly, weekly=3
     *
     * @return a List of two SchedulingCriteriaValue
     */
    List<SchedulingCriteriaValue> asCriteriaValues();

    /**
     * This object accepts a {@link PeriodVisitor}.<br>
     * It will invoke one of its visit method and pass itself as a parameter. <br>
     * This way, the visitor knows exactly which sub-class of {@link SchedulingPeriod} is used.
     *
     * @param <T>     any desired return type
     * @param visitor the visitor
     * @return any kind of interesting output
     */
    <T> T accept(final PeriodVisitor<T> visitor);

    /**
     * Visitor of {@link SchedulingPeriod}.<br>
     * By implementing this interface, you will be able to invoke {@link SchedulingPeriod#accept(PeriodVisitor)} on any SchedulingPeriod instance<br>
     * The SchedulingPeriod will in turn invoke the visitor's visit methods with itself as a strongly-typed argument.
     *
     * @param <T> any kind of desired output
     */
    interface PeriodVisitor<T> {

        /**
         * Behaviour to be had when visiting a {@link DayInMonth}.
         *
         * @param dayInMonth the day of the month
         * @return any kind of desired output
         */
        T visit(final DayInMonth dayInMonth);

        /**
         * Behaviour to be had when visiting a {@link SpecificDay}.
         *
         * @param specificDay the day
         * @return any kind of desired output
         */
        T visit(final SpecificDay specificDay);

        /**
         * Behaviour to be had when visiting a {@link WeekendPeriod}.
         *
         * @param weekend the weekend
         * @return any kind of desired output
         */
        T visit(final WeekendPeriod weekend);

        /**
         * Behaviour to be had when visiting a {@link WeeklyPeriod}.
         *
         * @param dayInWeek the day of the week
         * @return any kind of desired output
         */
        T visit(final WeeklyPeriod dayInWeek);

        /**
         * Behaviour to be had when visiting a {@link DailyPeriod}.
         *
         * @param uselessParam this parameter is useless, because a DailPeriod happens every day, by definition.
         * @return any kind of desired output
         */
        T visit(final DailyPeriod uselessParam);
    }

}
