<?php
// +-------------------------------------------------+
// © 2002-2004 PMB Services / www.sigb.net pmb@sigb.net et contributeurs (voir www.sigb.net)
// +-------------------------------------------------+
// $Id: Compress.php,v 1.4.2.2 2025/06/12 09:13:52 rtigero Exp $
namespace Pmb\Docnums\Library;

use explnum;
use Pmb\Common\Library\Image\Image;

class Compress {
    protected $filepath = "";
    protected $outputFilepath = "";
    const PDF_RESULTION = 72;
    const IMG_QUALITY = 50;

    /**
     * Exécute la compression sur un document numérique
     *
     * @param explnum $explnum
     * @throws \RuntimeException
     * @return bool
     */
    public function processExplnum(explnum $explnum): bool
    {
        try {
            if ($explnum->isEnBase()) {
                $oldExplnumData = $explnum->explnum_data;
                $explnum->explnum_data = $this->processBinary($explnum->explnum_data);
                $explnum->save();

                return $oldExplnumData != $explnum->explnum_data;
            } elseif ($explnum->isEnUpload()) {
                $filepath = $explnum->explnum_rep_path . $explnum->explnum_nomfichier;

                return $this->processFile($filepath);
            }
        } catch (\RuntimeException $e) {
            trigger_error($e->getMessage(), E_USER_WARNING);
            return false;
        }

        return false;
    }

    /**
     * Exécute la compression sur un fichier passé en paramètre
     *
     * @param string $filepath
     * @return bool
     * @throws \RuntimeException
     */
    public function processFile(string $filepath)
    {
        if (! file_exists($filepath)) {
            throw new \RuntimeException("Input file does not exist : $this->filepath");
        }

        $this->filepath = $filepath;

        $filename = basename($filepath);
        $this->outputFilepath = str_replace($filename, time() . '_compress_' . $filename, $filepath);

        $mimetype = mime_content_type($this->filepath);
        try {

            set_time_limit(0);


            switch ($mimetype) {
                case "application/pdf":
                    $this->processPdf();
                    break;

                case "image/jpeg":
                case "image/jpg":
                case "image/x-png":
                case "image/png":
                case "image/webp":
                    $this->processImage();
                    break;

                default:
                    break;
            }

            // On ecrase l'ancien fichier
            if (copy($this->outputFilepath, $this->filepath)) {
                unlink($this->outputFilepath);
                return true;
            } else {
                return false;
            }

        } catch (\RuntimeException $e) {
            trigger_error($e->getMessage(), E_USER_WARNING);
            return false;
        }
    }

    /**
     * Exécute la compression sur un fichier PDF
     *
     * @return void
     * @throws \RuntimeException
     */
    protected function processPdf()
    {
        if (! file_exists($this->filepath)) {
            throw new \RuntimeException("Input file does not exist : $this->filepath");
        }

        try {
            $this->compressPdf();
        } catch (\RuntimeException $e) {
            trigger_error($e->getMessage(), E_USER_WARNING);
        }
    }

    /**
     * Exécute la compression sur un fichier image
     *
     * @return void
     * @throws \RuntimeException
     */
    protected function processImage()
    {
        if (! file_exists($this->filepath)) {
            throw new \RuntimeException("Input file does not exist : $this->filepath");
        }

        try {
            Image::setCompressionQuality($this->filepath, $this->outputFilepath, self::IMG_QUALITY);
        } catch (\RuntimeException $e) {
            trigger_error($e->getMessage(), E_USER_WARNING);
        }
    }

    /**
     * Exécute la compression sur un binaire passé en paramètre
     *
     * @return string
     * @throws \RuntimeException
     */
    public function processBinary(string $binary)
    {
        global $base_path;

        $filename = $base_path . '/temp/' . time() . '_compress_process';
        $extension = finfo_buffer(finfo_open(), $binary, FILEINFO_EXTENSION);
        $filename = $filename . '.' . $extension;

        $size = file_put_contents($filename, $binary);

        if ($size) {
            try {
                $this->processFile($filename);

                $newBinary = file_get_contents($filename);
                if (false !== $newBinary) {
                    $binary = $newBinary;
                    unlink($filename);
                }
            }  catch (\RuntimeException $e) {
                trigger_error($e->getMessage(), E_USER_WARNING);
            }
        }

        return $binary;
    }

    /**
     * Compresse le fichier PDF en utilisant Ghostscript.
     *
     * @return void
     * @throws \RuntimeException
     */
    protected function compressPdf(): void
    {
        // Vérifie si le fichier d'entrée existe
        if (!file_exists($this->filepath)) {
            throw new \RuntimeException("Input file does not exist : $this->filepath");
        }

        // Construction de la commande Ghostscript
        $command = escapeshellcmd(
            sprintf(
                'gs -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/screen -dColorImageResolution=%s -dGrayImageResolution=%s -dMonoImageResolution=%s -sOutputFile=%s %s',
                escapeshellarg(self::PDF_RESULTION),  // Résolution pour les images en couleur
                escapeshellarg(self::PDF_RESULTION),  // Résolution pour les images en niveaux de gris
                escapeshellarg(self::PDF_RESULTION),  // Résolution pour les images monochromes
                escapeshellarg($this->outputFilepath),
                escapeshellarg($this->filepath)
            )
        );

        // Exécution de la commande Ghostscript
        $output = [];
        $returnVar = 0;
        exec($command, $output, $returnVar);

        // Vérifie si la commande a échoué
        if ($returnVar !== 0) {
            throw new \RuntimeException("Ghostscript command failed with exit code : $returnVar");
        }
    }
}