<?php

/**
 * Plugin CIBLOC
 * @copyright 2018 MTECT
 * @author Christophe IMBERTI (cf. CPI art L121-1)
 * @license GNU/GPLv3
 */

if (!defined('_ECRIRE_INC_VERSION')) {
	return;
}

include_spip('inc/cibloc_lire_cache');

/*
 * Ajout automatique des blocs ressources
 * Transforme en liste
 * les pieces jointes (en mode document) et/ou des liens
 * precedes par des retours a la ligne
 * si la constante _CIBLOC_BLOC_RESSOURCES_AUTOMATIQUE a comme valeur 'oui'
 * Exceptions :
 * - s'ils sont dans un tableau
 * - s'ils sont dans un bloc
 * - s'ils sont dans un multi colonnes
 * - si c'est une image inseree avec <doc...>
 */
function cibloc_ajout_automatique_bloc_ressources($texte) {
	$texte_a_traiter = '';
	$parties_a_ne_pas_traiter = [];
	$demo_doc = false;
	$constante = false;

	// lire le cache
	cibloc_lire_cache_definition();

	if ((defined('_CIBLOC_BLOC_RESSOURCES_AUTOMATIQUE') and _CIBLOC_BLOC_RESSOURCES_AUTOMATIQUE == 'oui')) {
		$constante = true;
		if ($texte and (strpos($texte, '<demodoc') !== false)) {
			$demo_doc = true;
		}
	}

	if ($texte
			and $constante
			and (strpos($texte, '<doc') !== false
					or strpos($texte, '->') !== false or $demo_doc)) {

		// Texte avec des blocs
		if (strpos($texte, '[bloc_') !== false) {
			/*
				// lire le cache
				include_spip('inc/cibloc_lire_cache');
				cibloc_lire_cache_definition();
				// liste des identifiants de blocs qui ont convertir_ressources_en_liste egal a 'oui'
				$ressources_en_liste = array();
				$fonc = 'cibloc_ressources_en_liste';
				if (function_exists($fonc))
			$ressources_en_liste = $fonc();
				// prendre uniquement les blocs dont on veut convertir les ressources en liste
				if ($ressources_en_liste){
			if (preg_match_all(',\[bloc_(.*?)\].*?\[\/bloc_,s', $texte, $regs, PREG_SET_ORDER))
				} else {
			 */
			// noter les blocs a ne pas traiter
			if (preg_match_all(',\[bloc_(.*?)\].*?\[\/bloc_,s', $texte, $regs, PREG_SET_ORDER)) {
				foreach ($regs as $t) {
					$parties_a_ne_pas_traiter[] = $t[0];
				}
			}

			//                }

			// ne pas traiter les multi
			if (strpos($texte, '[multi_') !== false) {
				if (preg_match_all(',\[multi_(.*?)\].*?\[\/multi_,s', $texte, $regs, PREG_SET_ORDER)) {
					foreach ($regs as $t) {
						$parties_a_ne_pas_traiter[] = $t[0];
					}
				}
			}

			// prendre le texte sauf les blocs a ne pas traiter et les multi
			if ($parties_a_ne_pas_traiter) {
				$texte_a_traiter = str_replace($parties_a_ne_pas_traiter, '', $texte);
			} else {
				$texte_a_traiter = $texte;
			}

			// Texte sans blocs
		} else {
			// ne pas traiter les multi
			if (strpos($texte, '[multi_') !== false) {
				if (preg_match_all(',\[multi_(.*?)\].*?\[\/multi_,s', $texte, $regs, PREG_SET_ORDER)) {
					foreach ($regs as $t) {
						$parties_a_ne_pas_traiter[] = $t[0];
					}
				}
			}

			// prendre le texte sauf les multi
			if ($parties_a_ne_pas_traiter) {
				$texte_a_traiter = str_replace($parties_a_ne_pas_traiter, '', $texte);
			} else {
				$texte_a_traiter = $texte;
			}
		}

		if ($texte_a_traiter) {
			$texte_a_traiter = str_replace("\r\n", "\r", $texte_a_traiter);
			$texte_a_traiter = str_replace("\r", "\n", $texte_a_traiter);

			// modele <doc...> precede d'un retour a la ligne
			if (!defined('_CIBLOC_RACCOURCI_DOC_ISOLE')) {
				define(
					'_CIBLOC_RACCOURCI_DOC_ISOLE',
					'(\n<doc' # <modele
					. '\s*([0-9]+)\s*' # id
					. '([|](?:<[^<>]*>|[^>])*?)?' # |arguments (y compris des tags <...>)
					. '\s*/?' . '>)' # fin du modele >
				);
			}

			// raccourcis SPIP [xxx->url]  precede d'un retour a la ligne
			if (!defined('_CIBLOC_RACCOURCI_LIEN_ISOLE')) {
				define('_CIBLOC_RACCOURCI_LIEN_ISOLE', "/\n\[([^][]*?([[]\w*[]][^][]*)*)->(>?)([^]]*)\]/msS");
			}

			// modele <demodoc...> precede d'un retour a la ligne
			if (!defined('_CIBLOC_DEMO_DOC')) {
				define(
					'_CIBLOC_DEMO_DOC',
					'(\n<demodoc' # <modele
					. '([|](?:<[^<>]*>|[^>])*?)?' # |arguments
					. '\s*/?' . '>)' # fin du modele >
				);
			}

			// Proteger les tableaux
			// (sans oublier les tableaux au debut ou a la fin du texte)
			$texte_a_traiter = preg_replace(",^\n?[|],S", "\n\n|", $texte_a_traiter);
			$texte_a_traiter = preg_replace(",\n\n+[|],S", "\n\n\n\n|", $texte_a_traiter);
			$texte_a_traiter = preg_replace(",[|](\n\n+|\n?$),S", "|\n\n\n\n", $texte_a_traiter);
			if (preg_match_all(',[^|](\n[|].*[|]\n)[^|],UmsS', $texte_a_traiter, $regs, PREG_SET_ORDER)) {
				foreach ($regs as $t) {
					$texte_a_traiter = str_replace($t[1], '', $texte_a_traiter);
				}
			}

			// les documents
			$id_docs = [];
			$id_images = [];
			if (preg_match_all(_CIBLOC_RACCOURCI_DOC_ISOLE, $texte_a_traiter, $doc_matches, PREG_SET_ORDER)) {
				// Identifier les images inserees avec <doc...>
				foreach ($doc_matches as $doc_match) {
					$id_docs[] = $doc_match[1];
				}
				$in = sql_in('id_document', $id_docs) . ' AND ' . sql_in('extension', ['jpg', 'png', 'gif']);
				$result = sql_select('id_document', 'spip_documents', $in);
				while ($row = sql_fetch($result)) {
					$id_images[] = $row['id_document'];
				}

				// Pour les <doc...> (sauf les images inserees avec <doc...>)
				foreach ($doc_matches as $doc_match) {
					if (!in_array($doc_match[1], $id_images)) {
						$search = substr($doc_match[0], 1);
						$replace = 'ciblocitem' . substr($doc_match[0], 1);
						$texte = str_replace($search, $replace, $texte);
					}
				}
			}

			// les liens
			if (preg_match_all(_CIBLOC_RACCOURCI_LIEN_ISOLE, $texte_a_traiter, $lien_matches, PREG_SET_ORDER)) {
				foreach ($lien_matches as $lien_match) {
					$search = substr($lien_match[0], 1);
					$replace = 'ciblocitem' . substr($lien_match[0], 1);
					$texte = str_replace($search, $replace, $texte);
				}
			}

			// les documents de demo
			if ($demo_doc) {
				if (preg_match_all(_CIBLOC_DEMO_DOC, $texte_a_traiter, $demodoc_matches, PREG_SET_ORDER)) {
					// Pour les <demodoc...>
					foreach ($demodoc_matches as $demodoc_match) {
						$search = substr($demodoc_match[0], 1);
						$replace = 'ciblocitem' . substr($demodoc_match[0], 1);
						$texte = str_replace($search, $replace, $texte);
					}
				}
			}

			$texte = cibloc_listes($texte);
		}

	}

	return $texte;
}

function cibloc_listes($valeur) {
	$texte = '';
	$classe_li = '';
	$classe_ul = ' class="cibloc_ul_ressources"';
	$parags = preg_split(",\n[[:space:]]*\n,S", $valeur);

	// chaque paragraphe est traite a part
	foreach ($parags as $para) {
		$niveau = 0;
		$pile_li = $pile_type = [];
		$lignes = explode('ciblocitem', "\n" . $para);

		// ne pas toucher a la premiere ligne
		$debut = array_shift($lignes);
		$texte .= $debut;

		// chaque item a sa profondeur = nb d'etoiles
		$type = '';
		foreach ($lignes as $item) {
			$profond = 1;
			$classe_li = ' class="cibloc_li_ressources_lien"';
			if (substr($item, 0, 4) == '<doc' or substr($item, 0, 8) == '<demodoc') {
				$classe_li = ' class="cibloc_li_ressources_doc"';
			}

			$ajout = '';

			// changement de type de liste au meme niveau : il faut
			// descendre un niveau plus bas, fermer ce niveau, et
			// remonter
			$nouv_type = 'ul';
			$change_type = ($type and ($type <> $nouv_type) and ($profond == $niveau)) ? 1 : 0;
			$type = $nouv_type;

			// d'abord traiter les descentes
			while ($niveau > $profond - $change_type) {
				$ajout .= $pile_li[$niveau];
				$ajout .= $pile_type[$niveau];
				if (!$change_type) {
					unset($pile_li[$niveau]);
				}
				$niveau --;
			}

			// puis les identites (y compris en fin de descente)
			if ($niveau == $profond && !$change_type) {
				$ajout .= $pile_li[$niveau];
			}

			// puis les montees (y compris apres une descente un cran trop bas)
			while ($niveau < $profond) {
				if ($niveau == 0) {
					$ajout .= "\n\n";
				} elseif (!isset($pile_li[$niveau])) {
					$ajout .= "<li$classe_li>";
					$pile_li[$niveau] = '</li>';
				}
				$niveau ++;
				$ajout .= "<ul$classe_ul>";
				$pile_type[$niveau] = "</$type>";
			}

			$ajout .= "<li$classe_li>";
			$pile_li[$profond] = '</li>';

			$texte .= $ajout . $item;
		}

		// retour
		$ajout = '';
		while ($niveau > 0) {
			$ajout .= $pile_li[$niveau];
			$ajout .= $pile_type[$niveau];
			$niveau --;
		}
		$texte .= $ajout;

		// paragraphe
		$texte .= "\n\n";
	}

	// sucrer les deux derniers \n
	return substr($texte, 0, -2);
}

/*
 * Ajout automatique des blocs texte
*/
function cibloc_ajout_automatique_bloc_texte($texte) {

	if ($texte
		and (defined('_CIBLOC_BLOC_TEXTE_AUTOMATIQUE') and _CIBLOC_BLOC_TEXTE_AUTOMATIQUE == 'oui')
		and (strpos($texte, '[bloc_') !== false) or strpos($texte, '[multi_') !== false) {

		/*----- Traitement des parties hors bloc et multi colonnes ----*/

		// pour simplifier les traitements
		// remplacer [multi_colonnes] par [bloc_multi_colonnes]
		// remplacer [/multi_colonnes] par [/bloc_multi_colonnes]
		$texte = str_replace([
			'[multi_colonnes]', '[/multi_colonnes]'],
			['[bloc_multi_colonnes]', '[/bloc_multi_colonnes]'],
			$texte
		);

		// tableau des positions debut et fin de chaque bloc
		$tableau = [];
		$tableau_hors_blocs = [];
		$prefixe_balise_debut = '[bloc_';
		$prefixe_balise_fin = '[/bloc_';
		$taille = strlen($texte);
		$offset = 0;

		while ($offset < $taille) {
			$balise_debut = '';
			$pos_debut = strpos($texte, $prefixe_balise_debut, $offset);
			if ($pos_debut === false) {
				break;
			}
			// nom de la balise
			$pos = strpos($texte, ']', $pos_debut);
			$balise_debut = substr($texte, $pos_debut + 1, $pos - $pos_debut - 1);
			// position de la balise fin correspondante
			$pos_fin = strpos($texte, '[/' . $balise_debut . ']', $pos_debut);
			if ($pos_fin === false) {
				break;
			}
			$pos_fin = strpos($texte, ']', $pos_fin);
			if ($pos_fin === false) {
				break;
			}

			$offset = $pos_fin + 1;
			$tableau[] = [$pos_debut, $pos_fin];

		}

		$offset = 0;
		foreach ($tableau as $positions) {
			$debut = $offset;
			$longueur = $positions[0] - $debut;
			$extrait = substr($texte, $debut, $longueur);
			if (str_ireplace([' ', CHR(10), CHR(13), '<br>', '<br/>', '<br />'], '', $extrait)) {
				$tableau_hors_blocs[$debut] = $longueur;
			}
			$offset = 1 + $positions[1];
		}

		if ($offset < $taille) {
			$debut = $offset;
			$longueur = $taille - $offset;
			$tableau_hors_blocs[$debut] = $longueur;
		}

		$rallonge = 0;
		/*
					// pour le test
					foreach ($tableau_hors_blocs AS $debut=>$longueur){
					  $texte = substr_replace($texte, '[bloc_texte]', $debut+$rallonge, 0);
					  $rallonge = $rallonge + 12;
					  $texte = substr_replace($texte, '[/bloc_texte]', $debut+$longueur+$rallonge, 0);
					  $rallonge = $rallonge + 13;
					}
		 */
		foreach ($tableau_hors_blocs as $debut => $longueur) {
			$texte = substr_replace($texte, '<div class="cibloc cibloc_texteauto">', $debut + $rallonge, 0);
			$rallonge = $rallonge + 37;
			$texte = substr_replace($texte, '</div>', $debut + $longueur + $rallonge, 0);
			$rallonge = $rallonge + 6;
		}

		// remettre multi_colonnes
		// remplacer [bloc_multi_colonnes] par [multi_colonnes]
		// remplacer [/bloc_multi_colonnes] par [/multi_colonnes]
		$texte = str_replace([
			'[bloc_multi_colonnes]', '[/bloc_multi_colonnes]'],
			['[multi_colonnes]', '[/multi_colonnes]'],
			$texte
		);
	}

	return $texte;
}

/*
Recherche des erreurs :
- bloc ouvert non ferme
- bloc ferme non ouvert
- bloc dans un bloc
*/
function cibloc_verifier_article($texte, $type) {
	$erreurs = [];
	if (empty($texte)) {
		return $erreurs;
	}
	$taille = strlen($texte);
	$balise_debut = '[' . $type . '_';
	$balise_fin = '[/' . $type . '_';

	$tableau_position_bloc = [];
	$tableau_balise_ouverte = [];
	$balise_ouvrante = '';

	// tableau des positions de debut de chaque bloc
	$offset = 0;
	while ($offset < $taille) {
		$pos_debut = strpos($texte, $balise_debut, $offset);
		if ($pos_debut === false) {
			break;
		}
		$pos_fin = strpos($texte, ']', $pos_debut);
		if ($pos_fin === false) {
			$erreurs[] = [$pos_debut, '[' . $type, "Il manque le crochet de fin ] dans une balise d'ouverture de " . $type];
			break;
		}
		$tableau_position_bloc[$pos_debut] = substr($texte, $pos_debut + 1, $pos_fin - $pos_debut - 1);

		$offset = $pos_fin + 1;
	}

	// tableau des positions de fin de chaque bloc
	$offset = 0;
	while ($offset < $taille) {
		$pos_debut = strpos($texte, $balise_fin, $offset);
		if ($pos_debut === false) {
			break;
		}
		$pos_fin = strpos($texte, ']', $pos_debut);
		if ($pos_fin === false) {
			$erreurs[] = [$pos_debut, '[/' . $type, 'Il manque le crochet de fin ] dans une balise de fin de ' . $type];
			break;
		}
		$tableau_position_bloc[$pos_debut] = substr($texte, $pos_debut + 1, $pos_fin - $pos_debut - 1);

		$offset = $pos_fin + 1;
	}

	// tri selon les index
	ksort($tableau_position_bloc);

	// parcourir le tableau
	foreach ($tableau_position_bloc as $cle => $valeur) {

		if (substr($valeur, 0, 1) == '/') {
			// cas d'une balise de fin
			$balise_ouvrante = substr($valeur, 1);
			if (!in_array($balise_ouvrante, $tableau_balise_ouverte)) {
				$erreurs[] = [
					$cle,
					'[/' . $balise_ouvrante . ']',
					'Un ' . $type . ' ' . $balise_ouvrante . ' a une balise de fin [/' . $balise_ouvrante . '] mais il lui manque une balise de début [' . $balise_ouvrante . ']',
				];
			} else {
				// enlever la balise de debut de la pile
				$cle_ouverte = array_search($balise_ouvrante, $tableau_balise_ouverte);
				unset($tableau_balise_ouverte[$cle_ouverte]);
			}
		} else {
			// cas d'une balise de debut

			// cas d'un bloc dans un autre bloc
			if (count($tableau_balise_ouverte) >= 1) {
				$current = current($tableau_balise_ouverte);
				if ($type == 'colonne') {
					$erreurs[] = [
						$cle,
						'[' . $valeur . ']',
						'Une ' . $type . ' [' . $valeur . ']...[/' . $valeur . '] est contenue dans une autre ' . $type . ' [' . $current . ']...[/' . $current . '] or une ' . $type . ' ne doit pas en contenir une autre.',
					];
				} elseif ($type == 'multi') {
					$erreurs[] = [
						$cle,
						'[' . $valeur . ']',
						'Un ' . $type . '_colonnes [' . $valeur . ']...[/' . $valeur . '] est contenu dans un autre ' . $type . '_colonnes [' . $current . ']...[/' . $current . '] or un ' . $type . '_colonnes ne doit pas en contenir un autre.',
					];
				} elseif ($type == 'texte') {
					// Exception : permettre de mettre par exemple un texte_center dans un texte_dessus
					$align = 0;
					$tableau_align = ['texte_left', 'texte_center', 'texte_right'];
					if (in_array($valeur, $tableau_align)) {
						$align++;
					}
					foreach ($tableau_balise_ouverte as $balise_ouverte) {
						if (in_array($balise_ouverte, $tableau_align)) {
							$align++;
						}
					}
					if ($align != 1) {
						$erreurs[] = [
							$cle,
							'[' . $valeur . ']',
							'Un ' . $type . ' [' . $valeur . ']...[/' . $valeur . '] est contenu dans un autre ' . $type . ' [' . $current . ']...[/' . $current . '] or un ' . $type . ' ne doit pas en contenir un autre.',
						];
					}
				} else {
					$erreurs[] = [
						$cle,
						'[' . $valeur . ']',
						'Un ' . $type . ' [' . $valeur . ']...[/' . $valeur . '] est contenu dans un autre ' . $type . ' [' . $current . ']...[/' . $current . '] or un ' . $type . ' ne doit pas en contenir un autre.',
					];
				}
			}
			// mettre la balise de debut dans la pile
			$tableau_balise_ouverte[$cle] = $valeur;
			krsort($tableau_balise_ouverte);
		}
	}

	// s'il reste des balises de debut sans balise de fin
	if ($tableau_balise_ouverte) {
		foreach ($tableau_balise_ouverte as $cle => $valeur) {
			$erreurs[] = [
					$cle,
					'[' . $valeur . ']',
					'Un bloc ' . $valeur . ' a une balise de début [' . $valeur . '] mais il lui manque une balise de fin [/' . $valeur . ']',
				];
		}
	}

	return $erreurs;
}
