<?php
/** 
 * @package     VikRestaurants
 * @subpackage  core
 * @author      E4J s.r.l.
 * @copyright   Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 * @link        https://vikwp.com
 */

namespace E4J\VikRestaurants\Recurrence;

// No direct access
defined('ABSPATH') or die('No script kiddies please!');

/**
 * Recurrence interface adapter for common methods implementation.
 * 
 * @since 1.10
 */
abstract class RecurrenceAware implements Recurrence
{
    /** @var \DateTime */
    protected $start;

    /** @var \DateTime */
    protected $end;

    /** @var \DateTime|null */
    protected $stop;

    /**
     * Class constructor.
     * 
     * @param  \DateTime       $start  The period start date.
     * @param  \DateTime       $end    The period ending date.
     * @param  \DateTime|null  $stop   An optional stop threshold.
     */
    public function __construct(\DateTime $start, \DateTime $end, ?\DateTime $stop = null)
    {
        $this->start = $start;
        $this->end = $end;
        $this->stop = $stop;
    }

    /**
     * @inheritDoc
     */
    public function match(\DateTime $date)
    {
        if ($this->start > $date)
        {
            // the closure is not yet started
            return false;
        }

        // clone the start and end dates to allow their modification
        // without altering the internally registered dates
        $start = clone $this->start;
        $end = clone $this->end;
        
        if (!$this->isMatchingDate($date, $start, $end))
        {
            // the provided date does not match the recurrence preferences
            return false;
        }

        if ($this->stop && $this->stop < $end)
        {
            // the resulting ending date exceeded the stop threshold
            return false;
        }

        // matching dates
        return true;
    }

    /**
     * Checks whether the specified date time is between the given period.
     * 
     * @param   \DateTime  $date   The date to check.
     * @param   \DateTime  $start  The period start date.
     * @param   \DateTime  $end    The period end date.
     * 
     * @return  bool       True if in between, false otherwise.
     */
    abstract protected function isMatchingDate(\DateTime $date, \DateTime $start, \DateTime $end);
}
