<?php

/**
 * @author          Tassos Marinos <info@tassos.gr>
 * @link            http://www.tassos.gr
 * @copyright       Copyright © 2021 Tassos Marinos All Rights Reserved
 * @license         GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
 */

namespace NRFramework\Widgets\Helper;

defined('_JEXEC') or die('Restricted access');

/**
 * Countdown Helper class mainly used by the Countdown field
 */
class Countdown
{
    // Pattern used to find tags
    public static $pattern = '/{(.*?)}/';

    /**
     * Creates the countdown
     * 
     * @param   string  $date
     * @param   string  $format
     * 
	 * @return	mixed   string with countdown or false if countdown is finished
     */
    public static function getCountdown($date, $format)
    {
        // Get the date data
        $data = self::calculateDate($date, $format);

        if ($data == false)
        {
            return false;
        }

        // Search and replace the format given to the data from above
        $result = preg_replace_callback(self::$pattern, function ($preg) use ($data) { return isset($data[$preg[1]]) ? $data[$preg[1]] : $preg[0]; }, $format);

        return $result;
    }

	/**
	 * Calculate days, hours, minutes and seconds
     * between the provided date and now.
	 *
	 * @param	string	$date
	 * @param	string	$format
	 *
	 * @return	mixed   array if calculated the date or false if countdown is finished
	 */
	public static function calculateDate($date, $format)
	{
        $tz = new \DateTimeZone(\JFactory::getApplication()->getCfg('offset', 'UTC'));

        // Convert dates into timestamps
        $then = new \DateTime($date, $tz);
        $now = new \DateTime('now', $tz);

        // Calculate the difference
        $sinceThen = $now->diff($then);
        
        if ($sinceThen->invert)
        {
            return false;
        }

        $data = self::getCorrectData($then, $now, $format);

        return $data;
    }

    /**
     * Gets the correct data based on the format given
     * It may be the case that the user needs to display:
     * - {days} {hours} and {minutes} - Highest tag: days
     * - {minutes} and {seconds} - Highest tag: minutes
     * - {seconds}
     * Before we would generate all data(year,months,days),
     * but now we generate till the highest tag given.
     * 
     * @param   object  $then
     * @param   object  $now
     * @param   string  $format
     * 
     * @return  array
     */
    public static function getCorrectData($then, $now, $format)
    {
        // In some cases we may need to use these instead
        $_then = $then->format('r');
        $_now = $now->format('r');
        $diff = strtotime($_then)-strtotime($_now);

        // Calculate the difference
        $sinceThen = $now->diff($then);

        // Find which tags we have in our format
        $tags = self::findTagsInFormat($format);

        // Get the correct data to return
        $data = self::calculateCorrectData($tags, $sinceThen, $diff);
        
        return $data;
    }

    /**
     * Calculates the correct data that we need to display
     * 
     * @param   array   $tags
     * @param   object  $sinceThen
     * @param   int     $diff
     * 
     * @return  array
     */
    public static function calculateCorrectData($tags, $sinceThen, $diff)
    {
        $data = [
            'years'   => '',
            'months'  => '',
            'days'    => '',
            'hours'   => '',
            'minutes' => '',
            'seconds' => ''
        ];

        if ($tags['years'] == 1 &&
            $tags['months'] == 1 &&
            $tags['days'] == 1 &&
            $tags['hours'] == 1 &&
            $tags['minutes'] == 1 &&
            $tags['seconds'] == 1)
        {
            $data['years'] = $sinceThen->y;
            $data['months'] = $sinceThen->m;
            $data['days'] = $sinceThen->d;
            $data['hours'] = $sinceThen->h;
            $data['minutes'] = $sinceThen->i;
            $data['seconds'] = $sinceThen->s;
        }
        else if ($tags['months'] == 1 &&
            $tags['days'] == 1 &&
            $tags['hours'] == 1 &&
            $tags['minutes'] == 1 &&
            $tags['seconds'] == 1)
        {
            $data['months'] = ($sinceThen->format('%y') * 12) + $sinceThen->format('%m');
            $data['days'] = $sinceThen->d;
            $data['hours'] = $sinceThen->h;
            $data['minutes'] = $sinceThen->i;
            $data['seconds'] = $sinceThen->s;
        }
        else if ($tags['days'] == 1 &&
            $tags['hours'] == 1 &&
            $tags['minutes'] == 1 &&
            $tags['seconds'] == 1)
        {
            $data['days'] = $sinceThen->days;
            $data['hours'] = $sinceThen->h;
            $data['minutes'] = $sinceThen->i;
            $data['seconds'] = $sinceThen->s;
        }
        else if ($tags['hours'] == 1 &&
            $tags['minutes'] == 1 &&
            $tags['seconds'] == 1)
        {
            $hours = $sinceThen->h;
            $hours = $hours + ($sinceThen->days*24);
            $data['hours'] = $hours;
            $data['minutes'] = $sinceThen->i;
            $data['seconds'] = $sinceThen->s;
        }
        else if ($tags['hours'] == 1 &&
            $tags['minutes'] == 1)
        {
            $hours = $sinceThen->h;
            $hours = $hours + ($sinceThen->days*24);
            $data['hours'] = $hours;
            $data['minutes'] = $sinceThen->i;
        }
        else if ($tags['minutes'] == 1 &&
            $tags['seconds'] == 1)
        {
            $minutes = $sinceThen->d * 24 * 60;
            $minutes += $sinceThen->h * 60;
            $minutes += $sinceThen->i;
            $data['minutes'] = $minutes;
            $data['seconds'] = $sinceThen->s;
        }
        else if ($tags['seconds'] == 1)
        {
            $data['seconds'] = $diff;
        }
        
        return $data;
    }

    /**
     * Find all the tags within the format
     * 
	 * @param	string	$format
     * 
     * @return  string
     */
    public static function findTagsInFormat($format)
    {
        $tags = [
            'years' => 0,
            'months' => 0,
            'days' => 0,
            'hours' => 0,
            'minutes' => 0,
            'seconds' => 0
        ];

        preg_match_all(self::$pattern, $format, $matches);

        foreach ($tags as $key => $value)
        {
            if (!in_array($key, $matches[1]))
            {
                continue;
            }
            
            $tags[$key]++;
        }

        return $tags;
    }
    
    /**
     * Prepare the format by adding <span> between the provided tags
     * 
	 * @param	string	$format
     * 
     * @return  string
     */
    public static function livePrepareFormat($format)
    {
        return preg_replace(self::$pattern, '<span class="$1">{$1}</span>', $format);
    }

}