<?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\Cron;

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

/**
 * Interface used to define the methods of an executable cron job.
 * 
 * @since 1.10
 */
abstract class CronJob implements Runnable, Configurable
{
    /**
     * The unique identifier of the cron job.
     * 
     * @var int
     */
    private $id;

    /**
     * Class constructor.
     */
    public function __construct(?int $id = null)
    {
        $this->id = $id;
    }

    /**
     * Returns the unique identifier of the cron job.
     * 
     * @return  int|null
     */
    final public function getId()
    {
        return $this->id;
    }

    /**
     * @inheritDoc
     * 
     * @see Runnable
     */
    public function isSupported()
    {
        // always supported by default
        return true;
    }

    /**
     * @inheritDoc
     * 
     * @see Runnable
     */
    final public function run(array $args = [])
    {
        // wrap in a registry for a better ease of use
        $args = new \JRegistry($args);

        // preserve the current language tag
        $langTag = \JFactory::getLanguage()->getTag();

        // initialize the response status
        $status = new Status;

        try
        {
            // execute the 
            $this->execute($args, $status);
        }
        catch (\Throwable $error)
        {
            // uncaught error, register message and send notification
            $status->setStatus(false)->appendContent($error->getMessage())->setNotify(true);
        }

        // reload the language according to the tag previously set
        \VikRestaurants::loadLanguage($langTag, JPATH_SITE);

        return $status;
    }

    /**
     * Concrete implementation of the cron execution.
     * 
     * @param   \JRegistry  $args    The cron configuration.
     * @param   Status      $status  The execution status.
     * 
     * @return  void
     * 
     * @throws  \Exception
     */
    abstract protected function execute(\JRegistry $args, Status $status);

    /**
     * @inheritDoc
     * 
     * Define the following language key to support a description for the cron: "VRE_CRON_{CLASSNAME}_TITLE".
     * 
     * @see Configurable
     */
    public function getTitle()
    {
        $id = $this->getDriver();
        $key = 'VRE_CRON_' . strtoupper($id) . '_TITLE';

        // try to translate the given language definition
        $title = \JText::translate($key);

        if ($title === $key)
        {
            // translation not found, return plain ID
            return $id;
        }

        return $title;
    }

    /**
     * @inheritDoc
     * 
     * Define the following language key to support a description for the cron: "VRE_CRON_{CLASSNAME}_DESC".
     * 
     * @see Configurable
     */
    public function getDescription()
    {
        $id = $this->getDriver();
        $key = 'VRE_CRON_' . strtoupper($id) . '_DESC';

        // try to translate the given language definition
        $description = \JText::translate($key);

        if ($description === $key)
        {
            // translation not found, do not use a description
            return '';
        }

        return $description;
    }

    /**
     * Returns the cron driver identifier.
     *
     * @return  string
     */
    public function getDriver()
    {
        // obtain class and get rid of the default namespace
        $class = preg_replace("/^E4J\\\\VikRestaurants\\\\Cron\\\\Jobs\\\\/", '', get_class($this));

        // split all the namespace components and take the class separately
        $namespace = preg_split("/\\\\/", $class);
        $class = array_pop($namespace);

        // separate camel-case intersections and join it to the namespace again
        $namespace[] = preg_replace("/([a-z0-9])([A-Z])/", addslashes('$1_$2'), $class);

        // create ID from class name
        return strtolower(implode('_', $namespace));
    }
}
