<?php
if (!defined('__ROOT__')) {
    list($environmentPath) = explode(DIRECTORY_SEPARATOR . 'modules', dirname(__FILE__));
    $environmentPath .= DIRECTORY_SEPARATOR;
    define('__ROOT__', $environmentPath);
}
require_once __ROOT__ . '/modules/base/php/Encoding.php';


// Informations complémentaires sur la doc de l'ATIH
// https://atih.atlassian.net/wiki/spaces/DocDRUIDES/pages/3917479983/Fichier+de+sauvegarde
// Les fichiers issus de Druides suivent cette convention
// <N°Finess>.<Année de transmission>.<Mois de transmission>.<Champs>.<Catégorie de données>.<Sous-catégorie de données>.<Date/heure du dernier contrôle au format AAAAMMJJHHmmSS>.<UID>


// Si on veut lancer depuis l'invit de commande
if (PHP_SAPI === "cli") {
    // -fs : Le Fichier Druide zipé situé dans le dossier temp
    if ($argc === 3 && ($argv[1]) === "-fs") {
        convertDruide($argv[2]);
    }else {
        var_dump("Utilisez l'option -f");
    }
}


function convertDruide($druidesZipSource)
{
    // Initialisation du fichier ZIP source
    if (!file_exists($druidesZipSource)) {
        throw new RuntimeException("Fichier $druidesZipSource inexistant");
    }

    $tempPathFromCti = pathinfo($druidesZipSource, PATHINFO_DIRNAME);

    $originalFilename = pathinfo($druidesZipSource, PATHINFO_FILENAME);

    // Traitement des fichiers IN
    $druideTypesInFromCti = array(".DRUIDE_SEJ.", ".DRUIDE_ACE.", ".DRUIDE_OQN.");
    if (striposa($druidesZipSource, $druideTypesInFromCti)) {
        $inZipTargetPath = $tempPathFromCti . DIRECTORY_SEPARATOR . $originalFilename . ".in.zip";
        $inZipTargetPath = str_replace(array(".DRUIDE_SEJ.", ".DRUIDE_OQN.", ".DRUIDE_ACE."), array(".ZIN.", ".ZIN.", ".ZIF."), $inZipTargetPath);
        creerLegacyInOutDepuisZipsImbriques($druidesZipSource, $inZipTargetPath, array('orig.zip'));
    }

    // Traitement des fichiers OUT
    $druideTypesOutFromCti = array(".DRUIDE_SEJ.", ".DRUIDE_OQN.");
    if (striposa($druidesZipSource, $druideTypesOutFromCti)) {
        $outZipTargetPath = $tempPathFromCti . DIRECTORY_SEPARATOR . $originalFilename . ".out.zip";
        $outZipTargetPath = str_replace(array(".DRUIDE_SEJ.", ".DRUIDE_OQN."), ".ZOU.", $outZipTargetPath);
        creerLegacyInOutDepuisZipsImbriques($druidesZipSource, $outZipTargetPath, array('in4ctl.zip', 'data2.zip'));
    }


}


// Utils
function endsWith($haystack, $needle)
{
    $length = strlen($needle);
    return $length > 0 ? substr($haystack, -$length) === $needle : true;
}

function striposa($haystack, array $needles, $offset = 0)
{
    foreach ($needles as $needle) {
        if (stripos($haystack, $needle, $offset) !== false) {
            return true; // stop on first true result
        }
    }
    return false;
}


function creerLegacyInOutDepuisZipsImbriques($zipSourcePath, $zipCiblePath, $fileSuffixesCibles)
{
    $zipCible = new ZipArchive();

    if ($zipCible->open($zipCiblePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === false) {
        throw new RuntimeException("Erreur dans la création du fichier $zipCiblePath");
    }


    $contenuInitial = file_get_contents($zipSourcePath);
    if ($contenuInitial === false) {
        throw new RuntimeException("Impossible de lire le zip source : $zipSourcePath");
    }

    trouverExtraireFichierZipCible($contenuInitial, $fileSuffixesCibles, $zipCible);

    $zipCible->close();
}

function trouverExtraireFichierZipCible($zipContent, $fileSuffixesCibles, $zipCible)
{
    // Utilisation de fichiers temporaires et de nom unique pour éviter le problème de path trop long dans windows lorsque l'on dézip
    $tmp = tempnam(sys_get_temp_dir(), 'zip_') . '.zip';
    file_put_contents($tmp, $zipContent);

    $zipTmp = new ZipArchive();
    if ($zipTmp->open($tmp) === true) {
        for ($i = 0; $i < $zipTmp->numFiles; $i++) {
            $nomFichier = $zipTmp->getNameIndex($i);
            if (endsWith($nomFichier, '.zip')) {
                $contenuZip = $zipTmp->getFromIndex($i);
                // Si le nom du zip correspond à un suffixe ciblé
                foreach ($fileSuffixesCibles as $suffixe) {
                    if (endsWith(strtoupper($nomFichier), strtoupper($suffixe))) {
                        // On traite le zip druide ciblé
                        extraireFichiersDepuisZipBinaire($contenuZip, $zipCible);
                        break;
                    }
                }

                // Continuer récursivement à parcourir le zip imbriqué
                trouverExtraireFichierZipCible($contenuZip, $fileSuffixesCibles, $zipCible);
            }
        }
        $zipTmp->close();

    }
    if (file_exists($tmp)) {
        unlink($tmp);
    }
}

function extraireFichiersDepuisZipBinaire($zipData, $zipCible)
{
    $tmp = tempnam(sys_get_temp_dir(), 'inner_zip_') . '.zip';
    file_put_contents($tmp, $zipData);

    $innerZip = new ZipArchive();
    if ($innerZip->open($tmp) === true) {
        for ($j = 0; $j < $innerZip->numFiles; $j++) {
            $nomFichier = $innerZip->getNameIndex($j);
            $contenu = $innerZip->getFromIndex($j);
            $zipCible->addFromString(basename($nomFichier), $contenu);
        }
        $innerZip->close();

    }
    if (file_exists($tmp)) {
        unlink($tmp);
    }
}