/*
 * NAT - An universal Translator
 * Copyright (C) 2005 Bruno Mascret
 * Contact: bmascret@free.fr
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package outils;

import gestionnaires.GestionnaireErreur;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

import nat.ConfigNat ;
import nat.Nat;
//import nat.Nat;
import outils.CharsetToolkit;


public class FileToolKit {
	
	/** Enregistre une chaîne de caractères dans un
	 * fichier avec l'encodage donné. Si l'encodage est absent,
	 * choisit l'encodage de sortie de la configuration
	 * courant de NAT */
	
	public static boolean saveStrToFile (String stringToSave, String fileName, String encodageFichier)

	{
		String encodage ;
		boolean retour = false ;

		if (encodageFichier!=null) { encodage=encodageFichier ;	}
		else { encodage = ConfigNat.getCurrentConfig().getSortieEncoding() ; }
		try
		{
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName),encodage));
			bw.write(stringToSave);
			//gest.AfficheMessage ("Fichier "+fileName,Nat.LOG_VERBEUX)
			
			bw.close();
			retour = true ;
		}
		catch (IOException e)
		{
			System.out.println("erreur dans: " + e);
			//System.out.println("<html><p color=\"red\">Erreur lors de l'enregistrement</p></html>");
		}
		return retour ;
	}
	
	/** Enregistre une chaîne de caractères dans un
	 * fichier avec l'encodage donné. Si l'encodage est absent,
	 * choisit l'encodage de sortie de la configuration
	 * courant de NAT */
	
	public static boolean saveStrToFile (String stringToSave, String fileName)
	{
		return saveStrToFile (stringToSave,fileName,ConfigNat.getCurrentConfig().getSortieEncoding());
	}
	
	/** Lit le fichier en paramètre avec l'encoding donné
	 * et renvoie une String contenant ce fichier. Si l'encoding
	 * est omis, prend le charset par défaut du système */
	
	public static String loadFileToStr (String fileName, String encodageFichier)

	{
		String encodage ;
		String retour = "" ;

		if (encodageFichier!=null) { encodage=encodageFichier ;	}
		else { encodage = CharsetToolkit.getDefaultSystemCharset().name() ; }
		try
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),encodage));
			String ligne = null ;
			while ( (ligne = br.readLine()) != null )
		  	{
	    	  retour=retour+ligne+"\n";
	  	    }
	     
			//gest.AfficheMessage ("Fichier "+fileName,Nat.LOG_VERBEUX)
			br.close();
		}
		catch (IOException e)
		{
			System.out.println("erreur dans: " + e);
			//System.out.println("<html><p color=\"red\">Erreur lors de l'enregistrement</p></html>");
		}
		return retour ;
	}
	
	/** Lit le fichier en paramètre avec l'encoding par défaut
	 * et renvoie une String contenant ce fichier. */
	
	public static String loadFileToStr (String fileName)
	{
		return loadFileToStr (fileName,CharsetToolkit.getDefaultSystemCharset().name());
	}
	
	/** Copie un fichier vers un autre en changeant d'encodage */
	
	public static boolean copyFile (String fileIn, String fileOut, String encodingIn, String encodingOut)
	{
		boolean retour = false ;
		
		try 
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileIn),encodingIn));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileOut),encodingOut));
			String ligne;
			while ((ligne = br.readLine()) != null)
			{
				bw.write(ligne+"\n");
				//System.out.println(ligne);
			}
			br.close();
			bw.close();
			retour = true ;
		}
		catch (FileNotFoundException fnfe)
		{
			System.out.println("Erreur fnfe");
			fnfe.printStackTrace();
		}
		catch(IOException ioe)
		{
			System.out.println("Erreur ioe");
			ioe.printStackTrace();
		}
		return retour ;
	}
	
	/** Copie un fichier vers un autre à l'identique (sans changer d'encodage) */
	
	public static boolean copyFile (String fileIn, String fileOut)
	{
		FileChannel in = null; // canal d'entrée
		FileChannel out = null; // canal de sortie
		boolean retour = false ;
		try 
		    {
			// Init
			in = new FileInputStream(fileIn).getChannel();
			out = new FileOutputStream(fileOut).getChannel();
			
			// Copie depuis le in vers le out
			in.transferTo(0, in.size(), out);
			in.close();
			out.close();
			retour = true ;
		    }
		catch (IOException e)
		    {
			e.printStackTrace(); // n'importe quelle exception
		    }
		
		return retour ;
	}
	
	/** change la table braille d'un fichier texte. Pour ce faire,
	 * ajoute les entetes XML au fichier source, copie les deux
	 * tables brailles entree et sortie dans ./xsl/tablesUsed,
	 * fait la transfo avec convert.xsl et recopie la sortie
	 * UTF-8 vers l'encoding de sortie voulu.
	 * @param fileIn fichier texte d'entrée
	 * @param fileOut fichier texte de sortie (brf)
	 * @param table1 table du fichier d'entrée
	 * @param table2 table pour le fichier de sortie
	 * @param encoding1 encoding du fichier d'entrée
	 * @param encoding2 encoding du fichier de sortie
	 * @param g gestionnaire d'erreur (peut être null)
	 * @return true si tout s'est bien passé
	 */
	
	public static boolean convertBrailleFile (String fileIn, String fileOut, String table1, String table2, String encoding1, String encoding2, GestionnaireErreur g )
	{
		
		Boolean retour = false;
		GestionnaireErreur gest = g ;
		
		if ((table1.equals(table2)))
		{
			retour = copyFile (fileIn,fileOut, encoding1, encoding2);
		}
		else
		{
			String fichConvTmpXml = "./tmp/tmpConv.xml";
			String fichConvTmpTxt = "./tmp/tmpConv.txt";
			String filtre = "./xsl/convert.xsl";
			String convTable1 = "./xsl/tablesUsed/ConvtabIn.ent";
			String convTable2 = "./xsl/tablesUsed/ConvtabOut.ent";
						
			if(ajouteEntete(loadFileToStr(fileIn,encoding1),fichConvTmpXml) 
					&& copyFile("./xsl/tablesBraille/"+table1+".ent", convTable1)
					&& copyFile("./xsl/tablesEmbosseuse/"+table2+".ent", convTable2))
			{
				if (gest!=null) gest.AfficheMessage("ok\n*** Création de la fabrique (DocumentBuilderFactory) ...",Nat.LOG_VERBEUX);
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				//configuration de la fabrique
				factory.setNamespaceAware(false);
				factory.setValidating(false);//je mets a false: pas besoin de réseau: non, voir xhtmlDocument
				//factory.setIgnoringElementContentWhitespace(true);
				factory.setIgnoringComments(true);
				factory.setIgnoringElementContentWhitespace(false);
				
				try 
				{
					DocumentBuilder builder = factory.newDocumentBuilder();
					if (gest!=null) gest.AfficheMessage("ok\n*** Parsage du document teste d'entrée avec SAX ...",Nat.LOG_VERBEUX);
					//builder.setErrorHandler(gest);
					Document doc = builder.parse(new File(fichConvTmpXml));
					doc.setStrictErrorChecking(true);
					if (gest!=null) gest.AfficheMessage("ok\n*** Initialisation et lecture de la feuille de style de conversion...",Nat.LOG_VERBEUX);
					TransformerFactory transformFactory = TransformerFactory.newInstance();
					StreamSource styleSource = new StreamSource(new File(filtre));
					// lire le style
					
					Transformer transform = transformFactory.newTransformer(styleSource);
					// conformer le transformeur au style
					DOMSource in = new DOMSource(doc);
					if (gest!=null) gest.AfficheMessage("ok\n*** Création du fichier d'impression ...",Nat.LOG_VERBEUX);
					// Création du fichier de sortie
					File file = new File(fichConvTmpTxt);
					StreamResult out = new StreamResult(file);
					if (gest!=null) gest.AfficheMessage("ok\n*** Transformation du fichier d'entrée pour l'impression...",Nat.LOG_VERBEUX);
					transform.transform(in, out);
					
					/* après la transformation, l'encoding de sortie est en UTF-8 donc il faut
					 * recopier le fichier dans le bon encoding	 */
					copyFile (fichConvTmpTxt, fileOut, "UTF-8", encoding2);
				
					retour = true;
				}
				catch (Exception e)  
				{
					if (gest!=null)
					{
						gest.setException(e);
						gest.GestionErreur();
					}
					e.printStackTrace(); // n'importe quelle exception
				}
			}
			
		}
		return retour ;
	}
	
	
	/** appelle l'autre convertBrailleFile avec l'encoding de sortie
	 * de NAT pour les deux encoding entrée et sortie
	 */
	
	public static boolean convertBrailleFile (String fileIn, String fileOut, String table1, String table2, GestionnaireErreur g)
	{
		String encoding = ConfigNat.getCurrentConfig().getSortieEncoding();
		return convertBrailleFile (fileIn, fileOut, table1, table2, encoding, encoding, g);
	}
	
	/** méthode privée ajoute les entetes XML a une string donnée et l'enregistre ds un fichier
	 * @param stringToSave string du contenu texte
	 * @param fileOut fichier xml de sortie
	 * @return true si ça s'est bien passé
	 */
	
	private static boolean ajouteEntete(String stringToSave, String fileOut)
	{
		boolean retour = false;
		try
		{
			//gest.AfficheMessage("\n** Ajout des entêtes et création fichier temp impression", Nat.LOG_VERBEUX);
			//il faut retranscrire en UTF-8 avant le traitement XSL
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileOut),"UTF-8"));
			//ajout entete
			bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><textconv>");
			bw.write(stringToSave.replace("<","&lt;"));
			//gest.AfficheMessage ("Fichier "+fileName,Nat.LOG_VERBEUX)
			bw.write("</textconv>");
			bw.close();
			retour = true;
		}
		catch (IOException e)
		{
			System.out.println("erreur d'ajout d'entete dans: " + e);
			//gest.AfficheMessage("Erreur entrée/sortie ajout entête impression", Nat.LOG_SILENCIEUX);
		}
		return retour;
	}
}
