<?php
namespace ShortPixel\Helper;

if ( ! defined( 'ABSPATH' ) ) {
 exit; // Exit if accessed directly.
}

use ShortPixel\Model\Image\ImageModel as ImageModel;
use ShortPixel\Controller\ApiKeyController as ApiKeyController;
use ShortPixel\Controller\QuotaController as QuotaController;
use ShortPixel\Controller\QueueController as QueueController;
use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;


use ShortPixel\Model\AccessModel as AccessModel;
use ShortPixel\Model\AiDataModel;

class UiHelper
{

	private static $outputMode = 'admin';

	private static $knowledge_url = 'https://shortpixel.com/knowledge-base/article/common-shortpixel-bulk-processing-errors/'; // the URL of all knowledge.

	public static function setOutputHandler($name)
	{
		 	self::$outputMode = $name;
	}

  public static function renderBurgerList($actions, $imageObj)
  {
    $output = "";
    $id = $imageObj->get('id');
    $primary = isset($actions['optimizethumbs']) ? 'button-primary' : '';

    $output .= "<div class='sp-column-actions '>
                    <div class='sp-dropdown'>
                        <button onclick='ShortPixel.openImageMenu(event);' class='sp-dropbtn button dashicons dashicons-menu $primary' title='ShortPixel Actions'></button>";
    $output .= "<div id='sp-dd-$id' class='sp-dropdown-content'>";

    foreach($actions as $actionName => $actionData)
    {
        $link = ($actionData['type'] == 'js') ? 'javascript:' . $actionData['function'] : $actionData['function'];
        $output .= "<a href='" . $link . "' class='" . esc_attr($actionName) . "' >" . esc_html($actionData['text']) . "</a>";
    }

    $output .= "</div> <!--sp-dropdown-content--> </div> <!--sp-dropdown--> </div> <!--sp-column-actions--> ";
    return $output;
  }

  public static function renderSuccessText($imageObj)
  {
    $output = '';
    //$percent = $imageObj->getMeta('improvement');
    $percent = $imageObj->getImprovement(); 

    if (false === $percent || $percent < 5)
    {
      $improvements = $imageObj->getImprovements();
      if (isset($improvements['totalpercentage']))
      {
        $percent = $improvements['totalpercentage'];
      }
      else
        $percent = 999; // dunno what is this, but bail out
    }

    if($percent == 999) 
    {
       return ;
    }

    $output .= '<p>';
    if ($percent && intval($percent) >= 5)
    {
      $output .= __('Reduced by','shortpixel-image-optimiser') . ' <strong>' . self::formatNumber($percent,2) . '%</strong>';
    }
    else if (intval($percent) < 5)
      $output .= __('Bonus processing','shortpixel-image-optimiser');

    $type = $imageObj->getMeta('compressionType');
    $output .= ' ('. self::compressionTypeToText($type) .')';

    $output .= '<!-- eofsngline --></p> ';

    $thumbs = $imageObj->get('thumbnails');
    $thumbsDone = $retinasDone = 0;
    $thumbsTotal = ($thumbs) ? count($thumbs) : 0;

    $retinas = $imageObj->get('retinas');

    $webpsTotal = $imageObj->count('webps');
    $avifsTotal = $imageObj->count('avifs');

    if($retinas)
    {
      foreach($retinas as $retinaObj)
      {
         if ($retinaObj->isOptimized())
         {
           $retinasDone++;
         }
      }
    }

    $improvements = $imageObj->getImprovements();
    $thumbTotal = $thumbsDone = 0;
    if ($imageObj->get('thumbnails'))
    {
      $thumbsTotal = count($imageObj->get('thumbnails'));  //
      //$thumbsDone =  (isset($improvements['thumbnails'])) ? count($improvements['thumbnails']) : 0;
      $thumbsDone = $imageObj->count('optimized', array('thumbs_only' => true));
      $excludedThumbs = $imageObj->count('user_excluded', array('thumbs_only' => true));
    }

    if (isset($improvements['thumbnails']))
    {
       $excluded = ($excludedThumbs > 0) ? sprintf(__('%s (%s excluded)', 'shortpixel-image-optimiser'), '<br>', $excludedThumbs) : '';

       $output .= '<div class="thumbnails optimized">';
       if ($thumbsTotal > $thumbsDone)
         $output .= '<div class="totals">' . sprintf(__('+%s of %s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone,0), self::formatNumber($thumbsTotal,0)) . ' ' .   $excluded . '</div>';

       elseif ($thumbsDone > 0)
         $output .= '<div class="totals">' . sprintf(__('+%s thumbnails optimized','shortpixel-image-optimiser'), self::formatNumber($thumbsDone, 0)) . ' ' . $excluded . '</div>';

			 $improvs = array();

				 uasort($improvements['thumbnails'], function ($a, $b) {
					 	//return $b[0] <=> $a[0]; // @todo Efficient code to use once PHP 5 support is done.
						if ($a == $b) {
							return 0;
						}
						return ($b < $a) ? -1 : 1;
				 });

			 $cutoff = false;
			 $thumbCount = count($improvements['thumbnails']);
			 if ($thumbCount > 20)
			 {
				  $improvements['thumbnails'] =  array_slice($improvements['thumbnails'], 0, 15, true);
					$cutoff = true;
			 }


			 // Quality Check
			 foreach($improvements['thumbnails'] as $thumbName => $thumbStat)
			 {
				  $stat = $thumbStat[0];
				 	if (is_numeric($stat) && $stat >= 0)
					{
						 $improvs[$thumbName] = $stat; //self::formatNumber($stat,2);
					}
			 }

			 if (count($improvs) > 0)
			 {
		       $output .= "<div class='thumb-wrapper'>";
					 $lowrating = 0;
		       foreach($improvs as $thumbName => $stat)
		       {
						   $statText = self::formatNumber($stat, 2);
		           $title =  sprintf(__('%s : %s', 'shortpixel-image-optimiser'), $thumbName, $statText . '%');
		           $rating = ceil( round($stat) / 10);
							 if (0 == $rating)
							 {
								 	$lowrating++;
									continue;
							 }

		           $blocks_on = str_repeat('<span class="point checked">&nbsp;</span>', $rating);
		           $blocks_off = str_repeat('<span class="point">&nbsp;</span>', (10- $rating));

		           $output .= "<div class='thumb " . $thumbName . "' title='" . $title . "'>"
		                       . "<span class='thumb-name'>" .  $thumbName . '</span>' .
		                        "<span class='optimize-bar'>" . $blocks_on . $blocks_off . "</span>
		                      </div>";
		       }

					 if ($lowrating > 0)
					 {
						 $blocks_off = str_repeat('<span class="point">&nbsp;</span>', 10);

						 $output .= "<div class='thumb'>"
												 . "<span class='thumb-name'>" . sprintf(__('+ %d thumbnails ', 'shortpixel-image-optimiser'), $lowrating) . '</span>' .
													"<span class='optimize-bar'>" . $blocks_off . "</span>
												</div>";
					 }

					 if (true === $cutoff)
					 {
						 $output .= '<div class="thumb"><span class="cutoff">' . sprintf(__('+ %d more', 'shortpixel-image-optimiser'), ($thumbCount - 15)) . '</span></div>';
					 }


		       $output .=  "</div> <!-- /thumb-wrapper -->";
				}
				$output .= "</div> <!-- /thumb optimized -->";
    }

    if ($retinasDone > 0)
    {
      $output .= '<div class="filetype retina">' . sprintf(__('+%s Retina images optimized','shortpixel-image-optimiser') , $retinasDone) . '</div>';
    }
    if ($webpsTotal > 0)
    {
      $output .=  '<div class="filetype webp">' . sprintf(__('+%s Webp images ','shortpixel-image-optimiser') , $webpsTotal) . '</div>';
    }
    if ($avifsTotal > 0)
    {
        $output .=  '<div class="filetype avif">' . sprintf(__('+%s Avif images ','shortpixel-image-optimiser') , $avifsTotal) . '</div>';
    }

    if ($imageObj->isSomethingOptimized() && $imageObj->isProcessable())
    {
        list($urls, $optimizable) = $imageObj->getCountOptimizeData('thumbnails');
				list($webpUrls, $webpCount)   =  $imageObj->getCountOptimizeData('webp');
				list($avifUrls, $avifCount)   =  $imageObj->getCountOptimizeData('avif');


				$maxList = 10;

			 if (count($urls) > $maxList)
			 {
				  $urls = array_slice($urls, 0, $maxList, true);
					$urls[] = '...';
			 }
			 if (count($webpUrls) > $maxList)
			 {
				  $webpUrls = array_slice($webpUrls, 0, $maxList, true);
					$webpUrls[] = '...';
			 }
			 if (count($avifUrls) > $maxList)
			 {
				  $avifUrls = array_slice($avifUrls, 0, $maxList, true);
					$avifUrls[] = '...';
			 }

        if ($optimizable > 0)
        {
           $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d images to optimize', 'shortpixel-image-optimiser'), $optimizable) . '</h4>';
             $output .= "<span>";
               foreach($urls as $optObj)
               {
								 if ($optObj === '...')
									$output .= $optObj;
								 else
                  $output .= substr($optObj, strrpos($optObj, '/')+1) . '<br>';
               }
             $output .= "</span>";
           $output .= '</div>';
        }

        if ($webpCount > 0 )
        {

           $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d Webp files to create', 'shortpixel-image-optimiser'), $webpCount) . '</h4>';
             $output .= "<span>";
               foreach($webpUrls as $optObj)
               {
								  if ($optObj === '...')
									 $output .= $optObj;
									else
                  	$output .= self::convertImageTypeName(substr($optObj, strrpos($optObj, '/')+1), 'webp') . '<br>';
               }
             $output .= "</span>";
           $output .= '</div>';
        }
        if ($avifCount > 0)
        {
            $output .= '<div class="thumbs-todo"><h4>' . sprintf(__('%d Avif files to create', 'shortpixel-image-optimiser'), $avifCount) . '</h4>';
              $output .= "<span>";
                foreach($avifUrls as $optObj)
                {
                   $output .= self::convertImageTypeName(substr($optObj, strrpos($optObj, '/')+1), 'avif') . '<br>';
                }
              $output .= "</span>";
            $output .= '</div>';
        }
    }

    return $output;

  }

  public static function compressionTypeToText($type)
  {

     switch($type)
     {
        case ImageModel::COMPRESSION_LOSSLESS:
           $text = __('Lossless', 'shortpixel-image-optimiser');
        break;
        case ImageModel::COMPRESSION_LOSSY:
            $text = __('Lossy', 'shortpixel-image-optimiser');
        break;
        case ImageModel::COMPRESSION_GLOSSY:
            $text = __('Glossy', 'shortpixel-image-optimiser');
        break;
        default:
            $text = __('No compression', 'shortpixel-image-optimiser');
        break; 
     }


      return $text;
  }

  public static function getListActions($mediaItem, $aiDataModel = null)
  {
      $list_actions = array();
      $id = $mediaItem->get('id');

		  $keyControl = ApiKeyController::getInstance();
			if (! $keyControl->keyIsVerified())
			{
				return []; // nothing
			}

      $quotaControl = QuotaController::getInstance();

			$access = AccessModel::getInstance();
			if (! $access->imageIsEditable($mediaItem))
			{
				 return [];
			}

      if ($id === 0)
      {
				return [];
      }

      //$aiDataModel = new AiDataModel($id);

      if ($mediaItem->isSomethingOptimized() )
      {
						list($u, $optimizable) = $mediaItem->getCountOptimizeData('thumbnails');
						list($u, $optimizableWebp)   =  $mediaItem->getCountOptimizeData('webp');
						list($u, $optimizableAvif)   =  $mediaItem->getCountOptimizeData('avif');

           if ($mediaItem->isProcessable() && ! $mediaItem->isOptimizePrevented())
           {
             $action = self::getAction('optimizethumbs', $id);
             if ($optimizable > 0)
             {
							 $total = $optimizable + $optimizableWebp + $optimizableAvif;
               $thumbObj = $mediaItem->getSomethingOptimized(); 
               if (false !== $thumbObj)
               {
                  $compressionType = $thumbObj->getMeta('compressionType'); 
                  $action = self::getAction('optimizethumbs', $id, ['compressionType' => $compressionType]);
               }

							 if ($optimizableWebp > 0 || $optimizableAvif > 0)
							 	   $itemText = __('items', 'shortpixel-image-optimiser');
								else {
									 $itemText = __('thumbnails', 'shortpixel-image-optimiser');
								}
               $action['text']  = sprintf(__('Optimize %s  %s','shortpixel-image-optimiser'),$total, $itemText);


             }
             else
             {
                 if ($optimizableWebp > 0 && $optimizableAvif > 0)
                   $text  = sprintf(__('Optimize %s webps and %s avif','shortpixel-image-optimiser'),$optimizableWebp, $optimizableAvif);
                 elseif ($optimizableWebp > 0)
                   $text  = sprintf(__('Optimize %s webps','shortpixel-image-optimiser'),$optimizableWebp);
                 else
                    $text  = sprintf(__('Optimize %s avifs','shortpixel-image-optimiser'),$optimizableAvif);
                 $action['text'] = $text;
             }
             $list_actions['optimizethumbs'] = $action;
          }


          if ($mediaItem->isRestorable())
          {
            if ($mediaItem->get('type') == 'custom')
            {
                if ($mediaItem->getExtension() !== 'pdf') // no support for this
                  $list_actions['comparer'] = self::getAction('compare-custom', $id);
            }
            else
            {
                // PDF without thumbnail can't be compared.
                $showCompare = true;
                if ($mediaItem->getExtension() == 'pdf')
                {
  				            if (! $mediaItem->getThumbnail('full'))
  					               $showCompare = false;
  				            elseif(! $mediaItem->getThumbnail('full')->hasBackup())
  					             $showCompare = false;
  			         }

  				       if ($showCompare)
                   $list_actions['comparer'] = self::getAction('compare', $id);
            }
			 			if ($mediaItem->isRestorable())
						{

							 $compressionType = $mediaItem->getMeta('compressionType');
		           switch($compressionType)
		           {
		               case ImageModel::COMPRESSION_LOSSLESS:
		                 $list_actions['reoptimize-lossy'] = self::getAction('reoptimize-lossy', $id);
		                 $list_actions['reoptimize-glossy'] = self::getAction('reoptimize-glossy', $id);

		               break;
		               case ImageModel::COMPRESSION_LOSSY:
		                 $list_actions['reoptimize-lossless'] = self::getAction('reoptimize-lossless', $id);
		                 $list_actions['reoptimize-glossy'] = self::getAction('reoptimize-glossy', $id);

		               break;
		               case ImageModel::COMPRESSION_GLOSSY:
		                 $list_actions['reoptimize-lossy'] = self::getAction('reoptimize-lossy', $id);
		                 $list_actions['reoptimize-lossless'] = self::getAction('reoptimize-lossless', $id);
		               break;
		           }

							 if ($mediaItem->get('type') === 'media')
							 {
							 		$list_actions['reoptimize-smartcrop'] = self::getAction('reoptimize-smartcrop', $id, array('compressionType' => $compressionType));
							 		$list_actions['reoptimize-smartcropless'] = self::getAction('reoptimize-smartcropless', $id, array('compressionType' => $compressionType));
								}
		          		$list_actions['restore'] = self::getAction('restore', $id);
							} // isRestorable
						else
						{

						}
        } // hasBackup

				if (\wpSPIO()->env()->is_debug && $mediaItem->get('type') == 'media')
				{
					 $list_actions['redo_legacy'] = self::getAction('redo_legacy', $id);
				}
      } //isOptimized


      if (false === is_null($aiDataModel) && $aiDataModel->isProcessable() && 'media' === $mediaItem->get('type') && in_array($mediaItem->getExtension(), $aiDataModel->supportedExtensions()))
      {
         $list_actions['shortpixel-generateai'] = self::getAction('shortpixel-generateai', $id);
      }

      if(! $quotaControl->hasQuota())
      {
         $remove = array('reoptimize-lossy' => '', 'reoptimize-glossy' => '', 'reoptimize-lossless' => '', 'optimizethumbs' => '');
         $list_actions = array_diff_key($list_actions, $remove);

      }
      return $list_actions;
  }

  public static function getActions($mediaItem)
  {
    $actions = [];
    $id = $mediaItem->get('id');
    $quotaControl = QuotaController::getInstance();
    $queueController = new QueueController();

		$keyControl = ApiKeyController::getInstance();
		if (! $keyControl->keyIsVerified())
		{
			return []; // nothing
		}

		$access = AccessModel::getInstance();
		if (! $access->imageIsEditable($mediaItem))
		{
			 return [];
		}

		if ($id === 0)
    {
			return [];
    }

    if(! $quotaControl->hasQuota())
    {
       $actions['extendquota'] = self::getAction('extendquota', $id);
       $actions['checkquota'] = self::getAction('checkquota', $id);
    }
    elseif($mediaItem->isProcessable() && false === $mediaItem->isSomethingOptimized() && ! $mediaItem->isOptimizePrevented() && ! $queueController->isItemInQueue($mediaItem))
    {
       $actions['optimize'] = self::getAction('optimize', $id);
       $actions['markCompleted']  = self::getAction('markCompleted', $id);
    }
    elseif ($mediaItem->isUserExcluded() && false === $mediaItem->isSomethingOptimized() && ! $queueController->isItemInQueue($mediaItem))
    {
      $actions['optimize'] = self::getAction('forceOptimize', $id);
    }


    return $actions;
  }

  public static function getStatusText($mediaItem)
  {
    $keyControl = ApiKeyController::getInstance();
    $queueController = new QueueController();
    $settings = \wpSPIO()->settings();

    $text = '';

		$access = AccessModel::getInstance();


    if (! $keyControl->keyIsVerified())
    {
      $text = __('Invalid API Key. <a href="options-general.php?page=wp-shortpixel-settings">Check your Settings</a>','shortpixel-image-optimiser');
    }
		// This basically happens when a NextGen gallery is not added to Custom Media.
		elseif ($mediaItem->get('id') === 0)
		{
			 if ($mediaItem->isProcessable(true) === false)
			 {
				 $text = __('Not Processable: ','shortpixel_image_optimiser');
				 $text  .= $mediaItem->getProcessableReason();
			 }
			 else {
         if (\wpSPIO()->env()->has_nextgen && false == $settings->includeNextGen)
         {
           $text = __('This image was not found in our database. Enable "Optimize nextgen galleries" in the settings, or add this folder manually. ', 'shortpixel-image-optimiser');
         }
         else {
           $text = __('This image was not found in our database. Refresh folders, or add this gallery', 'shortpixel-image-optimiser');
         }
			 }
		}
    elseif ($mediaItem->isSomethingOptimized())
    {
       $text = UiHelper::renderSuccessText($mediaItem);
    }
    elseif (false === $mediaItem->isProcessable()  )
    {
       $text = __('Not Processable: ','shortpixel_image_optimiser');
       $text  .= $mediaItem->getProcessableReason();
    }
    elseif (! $mediaItem->exists())
    {
       $text = __('File does not exist.','shortpixel-image-optimiser');
    }
    elseif ($mediaItem->getMeta('status') < 0)
    {
      $text = $mediaItem->getMeta('errorMessage');
    }
    elseif( $queueController->isItemInQueue($mediaItem) === true)
		{
			 $text = '<p>' . __('This item is waiting to be processed', 'shortpixel-image-optimiser') . '</p>';
			 $action = self::getAction('cancelOptimize', $mediaItem->get('id'));

			 if ($access->imageIsEditable($mediaItem))
			 {
			 	$text .= '<p><a href="javascript:' . $action['function'] . '">' . $action['text'] . '</a></p>';
		 	 }
		}

    if ($mediaItem->isOptimizePrevented() !== false)
    {
          $retry = self::getAction('retry', $mediaItem->get('id'));
          $unmark = self::getAction('unMarkCompleted', $mediaItem->get('id'));
					$redo_legacy = false;

					if ($mediaItem->get('type') == 'media')
					{
	 					$was_converted = get_post_meta($mediaItem->get('id'), '_shortpixel_was_converted', true);
						$updateTs = 1656892800; // July 4th 2022 - 00:00 GMT

						if ($was_converted < $updateTs)
						{
							$meta = $mediaItem->getWPMetaData();
							if (is_array($meta) && isset($meta['ShortPixel']))
							{
								$redo_legacy = self::getAction('redo_legacy', $mediaItem->get('id'));
							}
						}
					}

          $status = $mediaItem->getMeta('status');
          $text = ''; // reset text

          if (ImageModel::FILE_STATUS_MARKED_DONE == $status)
          {
            $text .= "<div class='shortpixel-image-notice'>" . esc_html($mediaItem->getReason('processable'));

            $text .= "<p class='shortpixel-error-reset'>" . sprintf(__('%s Click to unmark as completed %s', 'shortpixel-image-optimiser'), '<a href="javascript:' . $unmark['function'] . '">', '</a>') . '</p>';
            $text .= '</div>';
          }
          else {
            $text .= "<div class='shortpixel-image-error'>" . esc_html($mediaItem->getReason('processable'));
            $text .= "<span class='shortpixel-error-reset'>" . sprintf(__('After you have fixed this issue, you can %s click here to retry %s', 'shortpixel-image-optimiser'), '<a href="javascript:' . $retry['function'] . '">', '</a>') . '</span>';
            $text .= '</div>';
          }



					if ($redo_legacy !== false)
					{
						$text .= "<div class='shortpixel-image-error'><span class='shortpixel-error-reset'>";

						$text .= sprintf(esc_html__('It seems you have older converted legacy data, which might cause this issue. You can try to %s %s %s . If nothing changes, this is not the cause. ','shortpixel-image-optimiser'), '<a href="javascript:' . $redo_legacy['function'] . '">', $redo_legacy['text'], '</a>');
						$text .= "</span></div>";
					}

      }

    return $text;
  }

  public static function getExifDisplayValues($exif)
  {
      if (! is_numeric($exif) || $exif < 0 ||$exif > 7 )
      {
         return false;
      }

      $removed = ($exif % 2 == 0) ? true : false;
      $seo = ($exif >= 2 && $exif <= 5) ? true : false;
      $ai = ($exif >= 2 & $exif <= 3) ? true : false;

      // 0 and 1 options are classic, without ai settings
      if ($exif <= 1)
      {
        $ai = $seo = null;
      }


      $status = [
        'removed' => $removed,
        'ai' => $seo,
        'seo' => $ai,
      ];


      $mainline =  sprintf(__('Exif: %s'), ($removed) ? __('Removed', 'shortpixel-image-optimiser') : __('Kept', 'shortpixel-image-optimiser'));

      if (! is_null($ai))
      {
         $mainline .=  sprintf(__(', AI %s '), ($ai) ? __('Allowed', 'shortpixel-image-optimiser') : __('Denied', 'shortpixel-image-optimiser'));
         $mainline .=  sprintf(__(', SEO %s'), ($seo) ? __('Allowed', 'shortpixel-image-optimiser') : __('Denied', 'shortpixel-image-optimiser'));
      }

      $status['line']  = $mainline;

      return $status;

  }

  // Defines all possible actions in the Ui
  public static function getAction($name, $id, $args = array())
  {
     $action = array('function' => '', 'type' => '', 'text' => '', 'display' => '');
     $keyControl = ApiKeyController::getInstance();

		 $compressionType = isset($args['compressionType']) ? $args['compressionType'] : null;

    switch($name)
    {
      case 'optimize':
         $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ')';
         $action['type']  = 'js';
         $action['text'] = __('Optimize Now', 'shortpixel-image-optimiser');
         $action['display'] = 'button';
         $action['is-optimizable'] = true;
      break;
      case 'forceOptimize':
        $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ', true)';
        $action['type']  = 'js';
        $action['text'] = __('Override exclusions and optimize now', 'shortpixel-image-optimiser');
        $action['display'] = 'button';
        $action['is-optimizable'] = true;
      break;
			case 'cancelOptimize':
				 $action['function'] = 'window.ShortPixelProcessor.screen.CancelOptimizeItem(' . $id . ')';
				 $action['type']  = 'js';
				 $action['text'] = __('Cancel item optimization', 'shortpixel-image-optimiser');
				 $action['display'] = 'button';
			break;
      case 'markCompleted':
          $action['function'] = 'window.ShortPixelProcessor.screen.MarkCompleted(' . $id . ')';
          $action['type']  = 'js';
          $action['text'] = __('Mark as Completed', 'shortpixel-image-optimiser');
          $action['display'] = 'button-secondary';
          $action['layout'] = 'paragraph';
          $action['title'] = __('This will cause the plugin to skip this image for optimization', 'shortpixel-image-optimiser');
      break;
      case 'unMarkCompleted':
          $action['function'] = 'window.ShortPixelProcessor.screen.UnMarkCompleted(' . $id . ')';
          $action['type']  = 'js';
          $action['text'] = __('Click to unmark this item as done', 'shortpixel-image-optimiser');
          $action['display'] = 'js';
      break;
      case 'optimizethumbs':
          if (! is_null($compressionType))
          {
            $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ', null, ' . $compressionType . ');';
          }
          else
          {
            $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ');';
          }

          $action['type'] = 'js';
          $action['text']  = '';
          $action['display'] = 'inline';
          $action['is-optimizable'] = true;
      break;
      case 'retry':
         $action['function'] = 'window.ShortPixelProcessor.screen.Optimize(' . $id . ');';
         $action['type']  = 'js';
         $action['text'] = __('Retry', 'shortpixel-image-optimiser') ;
         $action['display'] = 'button';
         $action['is-optimizable'] = true;
     break;
		 case 'redo_legacy':
		 			$action['function'] = 'window.ShortPixelProcessor.screen.RedoLegacy(' . $id . ');';
		 			$action['type']  = 'js';
		 			$action['text'] = __('Redo Conversion', 'shortpixel-image-optimiser') ;
		 			$action['display'] = 'button';
		 break;

     case 'restore':
         $action['function'] = 'window.ShortPixelProcessor.screen.RestoreItem(' . $id . ');';
         $action['type'] = 'js';
         $action['text'] = __('Restore backup','shortpixel-image-optimiser');
         $action['display'] = 'inline';
     break;

     case 'compare':
        $action['function'] = 'ShortPixel.loadComparer(' . $id . ')';
        $action['type'] = 'js';
        $action['text'] = __('Compare', 'shortpixel-image-optimiser');
        $action['display'] = 'inline';
     break;
     case 'compare-custom':
        $action['function'] = 'ShortPixel.loadComparer(' . $id . ',"custom")';
        $action['type'] = 'js';
        $action['text'] = __('Compare', 'shortpixel-image-optimiser');
        $action['display'] = 'inline';
     break;
     case 'reoptimize-glossy':
        $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . ImageModel::COMPRESSION_GLOSSY . ')';
        $action['type'] = 'js';
        $action['text'] = __('Re-optimize Glossy','shortpixel-image-optimiser') ;
        $action['display'] = 'inline';
     break;
     case 'reoptimize-lossy':
        $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . ImageModel::COMPRESSION_LOSSY . ')';
        $action['type'] = 'js';
        $action['text'] = __('Re-optimize Lossy','shortpixel-image-optimiser');
        $action['display'] = 'inline';
     break;

     case 'reoptimize-lossless':
        $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . ImageModel::COMPRESSION_LOSSLESS . ')';
        $action['type'] = 'js';
        $action['text'] = __('Re-optimize Lossless','shortpixel-image-optimiser');
        $action['display'] = 'inline';
     break;
		 case 'reoptimize-smartcrop':
        $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . $compressionType . ',' . ImageModel::ACTION_SMARTCROP . ')';
        $action['type'] = 'js';
        $action['text'] = __('Re-optimize with SmartCrop','shortpixel-image-optimiser');
        $action['display'] = 'inline';
     break;
		 case 'reoptimize-smartcropless':
        $action['function'] = 'window.ShortPixelProcessor.screen.ReOptimize(' . $id . ',' . $compressionType . ',' . ImageModel::ACTION_SMARTCROPLESS . ')';
        $action['type'] = 'js';
        $action['text'] = __('Re-optimize without SmartCrop','shortpixel-image-optimiser');
        $action['display'] = 'inline';
     break;
     case 'shortpixel-generateai': 
      $action['function'] = 'window.ShortPixelProcessor.screen.RequestAlt(' . $id . ')';
      $action['type'] = 'js';
      $action['text'] = __('Generate image SEO data','shortpixel-image-optimiser');     
      $action['ai-action'] = true;
      break; 
     case 'extendquota':
        $action['function'] = 'https://shortpixel.com/login/'. $keyControl->getKeyForDisplay();
        $action['type'] = 'button';
        $action['text'] = __('Extend Quota','shortpixel-image-optimiser');
        $action['display'] = 'button';
     break;
     case 'checkquota':
        $action['function'] = 'ShortPixel.checkQuota()';
        $action['type'] = 'js';
        $action['display'] = 'button';
        $action['text'] = __('Check&nbsp;&nbsp;Quota','shortpixel-image-optimiser');
     break;
   }

   return $action;
  }

	public static function getConvertErrorReason($error)
	{
		switch($error)
		{
			case -1: //ERROR_LIBRARY:
				$reason = __('PNG Library is not present or not working', 'shortpixel-image-optimiser');
			break;
			case -2: //ERROR_PATHFAIL:
				$reason = __('Could not create path', 'shortpixel-image-optimiser');
			break;
			case -3: //ERROR_RESULTLARGER:
				$reason  = __('Result file is larger','shortpixel-image-optimiser');
			break;
			case -4: // ERROR_WRITEERROR
				$reason = __('Could not write result file', 'shortpixel-image-optimiser');
			break;
			case -5: // ERROR_BACKUPERROR
				$reason = __('Could not create backup', 'shortpixel-image-optimiser');
			break;
			case -6:  // ERROR_TRANSPARENT
				$reason = __('Image is transparent', 'shortpixel-image-optimiser');
			break;
			default:
				$reason = sprintf(__('Unknown error %s', 'shortpixel-image-optimiser'), $error);
			break;
		}


		$message = sprintf(__('Not converted: %s ', 'shortpixel-image-optimiser'), $reason);
		return $message;
	}

	public static function getKBSearchLink($subject)
	{
			return esc_url(self::$knowledge_url); // . sanitize_text_field($subject)); //the KB search doesn't work anymore
	}

	// @param MediaLibraryModel Object $imageItem
	// @param String $size  Preferred size
	// @param String Preload The preloader tries to guess what the preview might be for a more smooth process. Ignore optimize / backup
	public static function findBestPreview($imageItem, $size = 800, $preload = false)
	{
		 	$closestObj = $imageItem;

			// set the standard.
			if ($imageItem->getExtension() == 'pdf') // try not to select non-showable extensions.
				$bestdiff = 0;
			else
				$bestdiff = abs($imageItem->get('width') - $size);

			$thumbnails = $imageItem->get('thumbnails');

			if (! is_array($thumbnails))
			{
				 return $closestObj; // nothing more to do.
			}

			foreach($thumbnails as $thumbnail)
			{
				 if (! $preload && (! $thumbnail->isOptimized() || ! $thumbnail->hasBackup()))
				 	continue;

					$diff = abs($thumbnail->get('width') - $size);
					if ($diff < $bestdiff)
					{
						 $closestObj = $thumbnail;
						 $bestdiff = $diff;
					}
			}

			return $closestObj;
	}

  public static function formatTS($ts)
  {
      //$format = get_option('date_format') .' @ ' . date_i18n(get_option('time_format');
			if (function_exists('wp_date'))
			{
      	$date = wp_date(get_option('date_format'), $ts);
				$date .= ' @ ' . wp_date(get_option('time_format'), $ts);
			}
			else
			{
      	$date = date_i18n(get_option('date_format'), $ts);
				$date .= ' @ ' . date_i18n(get_option('time_format'), $ts);

			}
      return $date;
  }

  public static function formatBytes($bytes, $precision = 2) {
      $units = array('B', 'KB', 'MB', 'GB', 'TB');

      $bytes = max($bytes, 0);
      $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
      $pow = min($pow, count($units) - 1);

      $bytes /= pow(1024, $pow);

      return number_format_i18n(round($bytes, $precision), $precision) . ' ' . $units[$pow];
  }

	public static function formatNumber($number, $precision = 2)
	{
			global $wp_locale;
			$decimalpoint = isset($wp_locale->number_format['decimal_point']) ? $wp_locale->number_format['decimal_point'] : '.';
			$number =  number_format_i18n( (float) $number, $precision);

 			$hasDecimal = (strpos($number, $decimalpoint) === false) ? false : true;

			// Don't show trailing zeroes if number is a whole unbroken number. -> string comparison because number_format_i18n returns string.
			if ($decimalpoint !== false && $hasDecimal && substr($number, strpos($number, $decimalpoint) + 1) === '00')
			{
				 $number = substr($number, 0, strpos($number, $decimalpoint));
			}
			// Some locale's have no-breaking-space as thousands separator. This doesn't work well in JS / Cron Shell so replace with space.
			$number = str_replace('&nbsp;', ' ', $number);
		  return $number;
	}

	public static function formatDate( $date ) {

	if ( '0000-00-00 00:00:00' === $date->format('Y-m-d ') ) {
			$h_time = '';
	} else {
			$time   = $date->format('U'); //get_post_time( 'G', true, $post, false );
			if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
					if ( $t_diff < 0 ) {
							$h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
					} else {
							$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
					}
			} else {
					$h_time = $date->format( 'Y/m/d' );
			}
	}

	return $h_time;
}

	protected static function convertImageTypeName($name, $type)
	{
		if ($type == 'webp')
		{
			$is_double = \wpSPIO()->env()->useDoubleWebpExtension();
		}
		if ($type == 'avif')
		{
			$is_double = \wpSPIO()->env()->useDoubleAvifExtension();
		}

		if ($is_double)
		{
			 return $name . '.' . $type;
		}
		else
		{
			 return substr($name, 0, strrpos($name, '.')) . '.' . $type;
		}

	}

  /* Strings on settings page that need to be available for both JS and PHP  */
  public static function getSettingsStrings($name = false)
  {

      $strings = array(
      );

      $exclusion_types = array(
          'name' => __('Image Name', 'shortpixel-image-optimiser'),
          'path' => __('Image Path', 'shortpixel-image-optimiser'),
          'size' => __('Image Size', 'shortpixel-image-optimiser'),
      );

      $exclusion_apply = array(
           'all' => __('All', 'shortpixel-image-optimiser'),
           'only-thumbs' => __('Only Thumbnails', 'shortpixel-image-optimiser'),
           'only-custom' =>  __('Only Custom Media Images', 'shortpixel-image-optimiser'),
           'selected-thumbs' => __('Selected Images', 'shortpixel-image-optimiser'),
      );

      $dashboard_string = [
            'ok' => __('Everything ok', 'shortpixel-image-optimiser'),
            'warning' => __('Improvement possible', 'shortpixel-image-optimiser'),
            'alert' => __('Action needed', 'shortpixel-image-optimiser'),
      ];

      $ai_string = [
            'imagemodaltitle' => __('Select an image for AI SEO data preview', 'shortpixel-image-optimiser'), 
            'selectimage' => __('Use this image', 'shortpixel-image-optimiser'),
            'preview_requested' => __('Working on your AI SEO data preview. This may take a while ... ', 'shortpixel-image-optimiser'),
      ];

      $strings['exclusion_types'] = $exclusion_types;
      $strings['exclusion_apply'] = $exclusion_apply;
      $strings['dashboard_strings'] = $dashboard_string;
      $strings['ai_strings'] = $ai_string; 

      if ($name !== false && isset($strings[$name]))
      {
         return $strings[$name];
      }

      return $strings;
  }

  public static function getIcon($path, $args = array())
  {
      $defaults = array(

      );

      $icon_url = plugins_url($path, SHORTPIXEL_PLUGIN_FILE);

      $html = sprintf('<img src="%s" class="icon" />', esc_attr($icon_url));

      return $html;

  }



} // class
