The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package oEdtk::libXls;

use strict;

use Cwd;
use oEdtk::Main;
use File::Basename;
use Spreadsheet::WriteExcel;
use oEdtk::Config	qw(config_read);

use Exporter;

our $VERSION 	= 0.463;
our @ISA 	= qw(Exporter);
our @EXPORT 	= qw(prod_Xls_Init
		     prod_Xls_New		prod_Xls_Insert_Val
		     prod_Xls_Col_Init	prod_Xls_Edit_Ligne
		     prod_Xls_Row_Height	prod_Xls_Add_Sheet
		     prod_Xls_Close		prod_Xls_Liste_Output
		     %XLS_FORMAT);


my $LOCAL_REF_WORKBOOK;
my $CFG = config_read();

 # METHODES ASSOCIEES A LA GESTION DU FORMAT EXCEL
 my $MAX_ROW_BY_FIC =$CFG->{'EDTK_XLS_MAX_ROW'};
 my $XLSCOL = 0;
 my $XLSROW = 0;
 my $XLSHEIG= undef;
 my $MAXCOL =32;
 my $FNTSZ1 =12;
 my $FNTSZ2 =10;
 my $FNTSZ3 = 8;
 my $SHEET  = 0;
 our %XLS_FORMAT;

 my @TAB_VALUE;
 my @TAB_HEAD;
 my @TAB_COL_SIZE;
 my @TAB_LISTE_XLS;
 my ($FILENAME_REF, $XLS_NAME, $HEADER_LEFT,$HEADER_CENTER,$HEADER_RIGHT);

sub prod_Xls_Init(;$$$){
	# INITIALISATION DE LA FEUILLE EXCEL
	# ARGUMENTS : [TEXTE EN-TÊTE GAUCHE], [TEXTE EN-TÊTE CENTRE], [TEXTE EN-TÊTE DROIT]
    	($HEADER_LEFT,$HEADER_CENTER,$HEADER_RIGHT) =@_;
	$HEADER_RIGHT		||="Édition du &D";

	# EN FONCTION DU NOMBRE D'ÉLÉMENTS ON FABRIQUE L'INDICE DU PROCHAIN FICHIER
	my $item = sprintf ("%03s", $#TAB_LISTE_XLS+2);

	eval {
		$XLS_NAME = $CFG->{'EDTK_PRGNAME'}.".".$item.".".$CFG->{'EDTK_EXT_EXCEL'};
	};
	if ($@) {
		$XLS_NAME = $ARGV[0].$item.".xls";
	}

#	$XLS_NAME = basename($TXT_NAME);
#	$XLS_NAME =~ s/\.[^.]+/.xls/;
#	$XLS_NAME =~ s/(.+)\.\D{2,}$/$1.xls/;
	push (@TAB_LISTE_XLS, $XLS_NAME);
#	if ($#TAB_LISTE_XLS==0) {$FILENAME_REF=$XLS_NAME;}

	# CREATION D'UN FICHIER EXCEL
	my $workbook = Spreadsheet::WriteExcel->new($XLS_NAME)
		or die "echec a l'ouverture de $XLS_NAME, code retour $!\n";
	$LOCAL_REF_WORKBOOK=\$workbook;

	# AJOUT D'UNE FEUILLE EXCEL
	my $worksheet =$workbook->add_worksheet($0=~/([\w-]+)\.pl$/); # CREATION D'UNE FEUILLE DANS LE CLASSEUR, CETTE FEUILLE POPRTE LE NOM DE L'APPLI PERL SANS L'EXTENSION .PL
	&prod_Xls_Set_Format();
	&prod_Xls_Set_Sheet($worksheet);

	return \$workbook;
}

sub prod_Xls_New (;$$){
	# deux paramètres optionnels
	# 	- "HEAD" pour répéter la tête de tableau
#	#	- une racine de nom de fichier (s'intègre à la gestion des ruptures automatiques de fichiers)
	if ($TAB_LISTE_XLS[0]){
		my $option1=shift;
		$option1 ||="";
		if ($option1 eq "HEAD") {
			&prod_Xls_Head;
		}

		# CRÉATION D'UN NOUVEAU FICHIER XLS
		# ON RÉCUPÈRE LE NOM DU FICHIER DANS LE TABLEAU S'IL N'EST PAS PASSE EN PARAMETRE
#		my $xls_name;
#		if ($xls_name=shift) {$FILENAME_REF=$xls_name;}
#		$xls_name ||=$FILENAME_REF;

		# EN FONCTION DU NOMBRE D'ÉLÉMENTS ON FABRIQUE L'INDICE DU PROCHAIN FICHIER
#		my $item= sprintf ("%03s", $#TAB_LISTE_XLS+2);

		# ON CRÉE LE NOM DU FICHIER
#		$xls_name=~s/(.+\.).*$/$1$item.xls/;

		# CRÉATION DU NOUVEAU FICHIER AVEC SES PROPRIÉTÉS PAR DÉFAUT
		$SHEET  =0;
		$XLSROW =0;

		#return prod_Xls_Init($xls_name,$HEADER_LEFT,$HEADER_CENTER,$HEADER_RIGHT);
		return prod_Xls_Init($HEADER_LEFT,$HEADER_CENTER,$HEADER_RIGHT);
	} else {
		die "No init found for prodEdtkXls\n";
	}
}


sub prod_Xls_Col_Init{
	# INITIALISATION ET DÉFINITION DES PROPRIÉTÉS STYLES ET LARGEUR DES COLONNES
	my $paire	="";
	my $cpt	=0;
	while (my $paire =shift){
		if ($paire=~/^(\D*)/)	{$TAB_COL_SIZE[$cpt][0]=$1;} 	else {$TAB_COL_SIZE[$cpt][0]='AC';}
		if ($paire=~/([\d\.]*)$/){$TAB_COL_SIZE[$cpt][1]=$1;} 	else {$TAB_COL_SIZE[$cpt][1]=10;}
		$cpt++;
	}
	1;
}

sub prod_Xls_Row_Height($){
	$XLSHEIG=shift;

	my $worksheet	=${$LOCAL_REF_WORKBOOK}->sheets($SHEET);
	$worksheet->set_row($XLSROW, $XLSHEIG);
	$XLSHEIG=undef;
	1;
}

sub prod_Xls_Add_Sheet($){
	my $sheetName=shift;
	my $worksheet =${$LOCAL_REF_WORKBOOK}->add_worksheet($sheetName);
	&prod_Xls_Set_Sheet($worksheet);
	$SHEET++;
	$XLSROW=0;

	if (@TAB_HEAD) {
		&prod_Xls_Head;
	}

	return $worksheet;
}

sub prod_Xls_Set_Sheet($) {
	my $worksheet=shift;
	my $doc_HEADER_LEFT		='&L&10&"Arial,Bold"'.$HEADER_LEFT;
	my $doc_HEADER_CENTER	='&C&10&"Arial,Bold"'.$HEADER_CENTER;
	my $doc_HEADER_RIGHT 	='&R&10&"Arial,Bold"'.$HEADER_RIGHT;
	my $ref		 		='&L&6Réf/doc : &A - Edité le &D - &P - &F'.'&R&10Page &P/&N';

	$worksheet ->set_paper(0);		# FORMAT D'IMPRESSION (PRINTER DEFAULT))
	$worksheet ->set_landscape();		# SET_PORTRAIT() # A METTRE EN VARIABLE
	$worksheet ->set_margins_LR(0.4);	# EN INCH
	$worksheet ->set_margins_TB(0.65);	# EN INCH
	$worksheet ->fit_to_pages(1, 0);	# ADAPTE L'IMPRESSION À LA LARGEUR DE LA PAGE
	$worksheet ->set_header("$doc_HEADER_LEFT$doc_HEADER_CENTER$doc_HEADER_RIGHT", 0.4);
	$worksheet ->set_footer($ref, 0.4);
	$worksheet ->center_horizontally();
	$worksheet ->hide_gridlines();
	$worksheet ->freeze_panes(1, 0); 	# FRACTIONNE LA PREMIÈRE LIGNE POUR VISUALISATION
	$worksheet ->repeat_rows(0);		# RANG À RÉPÉTER EN TÊTE DE PAGE POUR L'IMPRESSION # A METTRE EN VARIABLE

	# DEFINITION DES FORMATS DE CHACUNE DES COLONNES
	$worksheet ->set_column(0, $MAXCOL, 10, $XLS_FORMAT{'AL'});	# FORMAT PAR DEFAUT

	my $i=0;
	# SI LES COLONNES SONT DÉFINIES EN STYLES ET EN LARGEUR, ON PREND EN COMPTE LES PROPRIÉTÉS
	while ( $TAB_COL_SIZE[$i][0] ){
		$worksheet ->set_column($i, $i, $TAB_COL_SIZE[$i][1],  $XLS_FORMAT{$TAB_COL_SIZE[$i][0]});
		$i++;
	}
	1;
}

sub prod_Xls_Insert_Val{
	# AJOUT DE LA OU LES VALEURS TRANSMISES AU TABLEAU DE VALEURS LOCAL

	@TAB_VALUE=(@TAB_VALUE, @_);
	1;
}

sub prod_Xls_Edit_Ligne (;$$){
	# LA FONCTION PEUT RECEVOIR EN PARAMÈTRE
	#	$format = UNE INSTRUCTUCTION DE FORMATTAGE UNIQUE POUR LA LIGNE COURANTE
	#	$f_tete_col = "HEAD" DESIGNE UNE TETE DE COLONNE A REPETER SUR CHAQUE PAGE
	my $oldFormat	=0;
	my $format	=shift; 				# OPTION
	my $f_tete_Col	=shift; 				# OPTION
	$f_tete_Col 	||="";

	# ON ÉDITE PAS LES LIGNES SANS VALORISATIONS (COMPLÈTEMENT VIDES)
	if ($#TAB_VALUE == -1) {
		return "OK", $XLSROW; 	# Sortie
	}

	my $worksheet	=${$LOCAL_REF_WORKBOOK}->sheets($SHEET);
	my $statut	="OK";
	my $col 		=0; 					# CETTE VARIABLE PERMET DE REPARTIR DE LA PREMIÈRE COLONNE DANS LALIGNE
	my $format_unique =0;
	if ($format) {
		 $format_unique = 1;
	}

	if ($f_tete_Col eq "HEAD"){
		undef @TAB_HEAD;
		@TAB_HEAD=("START_HEAD_$format", @TAB_VALUE, "STOP_HEAD");
	}

	# TRAITEMENT DES VALEURS DU TABLEAU, UNE PAR UNE
	#  CELLULE PAR CELLULE, Y COMPRIS LES VALEURS UNDEF
	while ($#TAB_VALUE > -1) {
		my $valeur=shift(@TAB_VALUE);
		if ($format_unique) {			# l'ensemble de la ligne est formattée avec le format transmis en paramètre
		} elsif ($TAB_COL_SIZE[$col][0]) {	# format pré défini
			$format=$TAB_COL_SIZE[$col][0];

		} else {
			$format = "AC";			# format par défaut
		}

		if ($valeur =~/NEW_PAGE/) {
			$worksheet ->set_h_pagebreaks($XLSROW+1);
			$col++;
		} elsif ($valeur =~/NEW_LINE/) {
			$col=0;
			$XLSROW++;
		} elsif ($valeur =~/STOP_HEAD/) {
			$format_unique=$oldFormat;
		} elsif ($valeur =~/START_HEAD/) {
			$oldFormat=$format_unique;
			if ($valeur =~/START_HEAD_(\w{2})/) {
				$format=$1;
				$format_unique=1;
			} else {
				$format_unique=0;
        		}
			# OUVERTURE D'UN NOUVEAU FICHIER EXCEL
			if ($XLSROW != 0) {
				&prod_Xls_New();
			}
		} elsif (ref $format eq 'HASH') {
			# enrichissement du format de mise en forme de la cellule
			# attention les valeurs modifiées ne sont pas sauvegardées
			my $xlsfmt = ${$LOCAL_REF_WORKBOOK}->add_format();
			if ($TAB_COL_SIZE[$col][0]) {
				$xlsfmt->copy($XLS_FORMAT{$TAB_COL_SIZE[$col][0]});
			}
			$xlsfmt->set_format_properties(%$format);
			$worksheet->write($XLSROW, $col, $valeur, $xlsfmt);
			$col++;
		} elsif ($format =~ /^N/) {
			$valeur=~s/\s//g;
			$worksheet->write_number($XLSROW, $col, $valeur, $XLS_FORMAT{$format});
			$col++;
		} else {
			$valeur=~s/\ +/ /g;	# on ne substitue que les blancs par les caractères tq cr lf
			$worksheet->write_string($XLSROW, $col, $valeur, $XLS_FORMAT{$format});
			$col++;
		}
	}
	if ($col > 0) { $XLSROW++ ; }

	if ($XLSROW < ($MAX_ROW_BY_FIC-1)) {
		$statut="OK";
	} elsif ($XLSROW == ($MAX_ROW_BY_FIC-1)) {
		$statut="WARN_EOF";
	} elsif ($XLSROW > $MAX_ROW_BY_FIC-1) {
		$statut="NEW";

		&prod_Xls_New('HEAD');
		&prod_Xls_Insert_Val ("NEW_LINE");
		#print "XLSROW=$XLSROW  - \$#TAB_VALUE=$#TAB_VALUE /insert head @TAB_VALUE \n" ;
	}

	return $statut, $XLSROW;
}

sub prod_Xls_Head(){
	if (!(@TAB_HEAD)) {
		@TAB_HEAD =("START_HEAD", "Suite...", "STOP_HEAD");
	}
	&prod_Xls_Insert_Val (@TAB_HEAD);
	1;
}

sub prod_Xls_Set_Format(){
	#  DEFINITION DES FORMATS PAR DEFAUT
	$XLS_FORMAT{'T1'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'T1'} ->set_bold(1);
	$XLS_FORMAT{'T1'} ->set_align('center');
	$XLS_FORMAT{'T1'} ->set_align('vcenter');
	$XLS_FORMAT{'T1'} ->set_size($FNTSZ1);
	$XLS_FORMAT{'T1'} ->set_border(0);

	$XLS_FORMAT{'T2'}=${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'T2'}->set_bold(1);
	$XLS_FORMAT{'T2'}->set_align('center');
	$XLS_FORMAT{'T2'}->set_align('vcenter');
	$XLS_FORMAT{'T2'}->set_color('white');
	$XLS_FORMAT{'T2'}->set_size($FNTSZ2);
	$XLS_FORMAT{'T2'}->set_bg_color('black');
	$XLS_FORMAT{'T2'}->set_border(1);
	$XLS_FORMAT{'T2'}->set_text_wrap();

	$XLS_FORMAT{'T3'}=${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'T3'}->set_bold(1);
	$XLS_FORMAT{'T3'}->set_align('left');
	$XLS_FORMAT{'T3'}->set_color('white');
	$XLS_FORMAT{'T3'}->set_size($FNTSZ3);
	$XLS_FORMAT{'T3'}->set_bg_color('black');
	$XLS_FORMAT{'T3'}->set_border(1);
	$XLS_FORMAT{'T3'}->set_text_wrap();

	$XLS_FORMAT{'T4'}=${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'T4'}->set_bold(1);
	$XLS_FORMAT{'T4'}->set_align('left');
	$XLS_FORMAT{'T4'}->set_size($FNTSZ3);
	$XLS_FORMAT{'T4'}->set_border(1);
	$XLS_FORMAT{'T4'}->set_text_wrap();

	$XLS_FORMAT{'BD'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'BD'} ->set_bold(1);
	$XLS_FORMAT{'BD'} ->set_align('center');
	$XLS_FORMAT{'BD'} ->set_border(1);
	$XLS_FORMAT{'BD'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'BD'}->set_text_wrap();

	$XLS_FORMAT{'AL'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'AL'} ->set_align('left');
	$XLS_FORMAT{'AL'} ->set_border(1);
	$XLS_FORMAT{'AL'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'AL'} ->set_num_format('@'); # POUR EMPECHER EXCEL DE RECONVERTIR LES VALEURS NUMÉRIQUES EN NUMÉRIQUES
	$XLS_FORMAT{'AL'}->set_text_wrap();

	$XLS_FORMAT{'AR'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'AR'} ->set_align('right');
	$XLS_FORMAT{'AR'} ->set_border(1);
	$XLS_FORMAT{'AR'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'AR'} ->set_num_format('@'); # POUR EMPECHER EXCEL DE RECONVERTIR LES VALEURS NUMÉRIQUES EN NUMÉRIQUES
	$XLS_FORMAT{'AR'}->set_text_wrap();

	$XLS_FORMAT{'AC'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'AC'} ->set_align('center');
	$XLS_FORMAT{'AC'} ->set_border(1);
	$XLS_FORMAT{'AC'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'AC'} ->set_num_format('@'); # POUR EMPECHER EXCEL DE RECONVERTIR LES VALEURS NUMÉRIQUES EN NUMÉRIQUES

	$XLS_FORMAT{'Ac'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'Ac'} ->set_align('center');
	$XLS_FORMAT{'Ac'} ->set_border(1);
	$XLS_FORMAT{'Ac'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'Ac'} ->set_num_format('@'); # POUR EMPECHER EXCEL DE RECONVERTIR LES VALEURS NUMÉRIQUES EN NUMÉRIQUES
	$XLS_FORMAT{'Ac'}->set_text_wrap();

	$XLS_FORMAT{'NR'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'NR'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'NR'} ->set_num_format('# ### ##0.00'); # UN MONTANT DOIT ÊTRE PASSÉ AU FORMAT US
	$XLS_FORMAT{'NR'} ->set_align('right');
	$XLS_FORMAT{'NR'} ->set_border(1);

	$XLS_FORMAT{'NC'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'NC'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'NC'} ->set_num_format('# ### ##0.00'); # UN MONTANT DOIT ÊTRE PASSÉ AU FORMAT US
	$XLS_FORMAT{'NC'} ->set_align('center');
	$XLS_FORMAT{'NC'} ->set_border(1);

	$XLS_FORMAT{'NL'} =${$LOCAL_REF_WORKBOOK}->add_format();
	$XLS_FORMAT{'NL'} ->set_size($FNTSZ3);
	$XLS_FORMAT{'NL'} ->set_num_format('# ### ##0.00'); # UN MONTANT DOIT ÊTRE PASSÉ AU FORMAT US
	$XLS_FORMAT{'NL'} ->set_align('left');
	$XLS_FORMAT{'NL'} ->set_border(1);

	1;
}

sub prod_Xls_Liste_Output (){
	return @TAB_LISTE_XLS;
}

sub  prod_Xls_Close(;$$) {
	my $fi =shift;
	# EDITION EVENTUELLE DE LA DERNIERE LIGNE ET PURGE DU TAMPON
	prod_Xls_Edit_Ligne();

	my $cwd = getcwd();
	# ON INDIQUE LA LISTE DES FICHIERS EXCEL PRODUITS
	foreach (prod_Xls_Liste_Output()) {
		print "$cwd/$_\n";
	}

	${$LOCAL_REF_WORKBOOK}->close() or die "ERR. closing file, return code $!\nDIE";

	if ($fi) {
		close (IN)  or die "ERR. fermeture $fi, return code $!\nDIE";
	}

	undef $LOCAL_REF_WORKBOOK;
	1;
}


END {
	prod_Xls_Close() if ($LOCAL_REF_WORKBOOK);
}

1;