package nat;

//import des packages maison
import gestionnaires.GestionnaireErreur;
import nat.ConfigNat;
import nat.transcodeur.Transcodeur;
import nat.convertisseur.*;
import nat.presentateur.*;
import outils.CharsetToolkit;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.io.FileNotFoundException;
import java.io.IOException;

import java.nio.charset.Charset;
//import java.util.Locale;

public class Transcription
{
    //Attributs
    private Convertisseur conv;
    private Transcodeur trans;
    private Presentateur pres;

    private String sourceMimeType="";

    private GestionnaireErreur gest;
    
    //fichiers temporaires
    public static final String fTempXML = "tmp/tmp.xml";
    public static final String fTempXHTML = "tmp/tmp.xhtml";
    public static final String fTempTxt = "tmp/tmp.txt";
    public static final String fTempEntetes = "tmp/convTexteEntetes.tmp";

    //constructeur
    private Transcription(){};
    private Transcription(GestionnaireErreur g, Convertisseur c, Transcodeur t, Presentateur p)
    {
		gest=g;
		pres=p;
		trans=t;
		conv=c;
    }
	
    public static Transcription fabriqueTranscription(String fs, String fc, GestionnaireErreur g)
    {
		Transcription retour = null;
		/* **** Conversion et présentation******* */
		Convertisseur c;
		Presentateur p;
		Transcodeur t;
		String sourceEncoding = ConfigNat.getCurrentConfig().getSourceEncoding();
		String sortieEncoding = ConfigNat.getCurrentConfig().getSortieEncoding();
		String sourceMimeType ="";
		//récupération des informations sur le fichier source
		g.AfficheMessage("\nAnalyse du fichier source ", Nat.LOG_SILENCIEUX);
		if(verifFichier(new File(fs), g))
		{	
			sourceMimeType = trouveMimeTypeSource(fs, g);
			g.AfficheMessage("\n** Le fichier source est de type " + sourceMimeType , Nat.LOG_NORMAL);
			if (sourceMimeType.equals("text/plain"))
			{
				if (!sourceEncoding.equals("automatique")&&!(sourceEncoding==null)&&!sourceEncoding.equals(""))
				{
					g.AfficheMessage("\n** Utilisation de l'encodage "+sourceEncoding+" spécifié dans les options pour le fichier source\n", Nat.LOG_NORMAL);
				}
				else
				{
					sourceEncoding = trouveEncodingSource(fs, g);
					if(sourceEncoding == null||sourceEncoding.equals(""))
					{
						// pas de bol, on n'a pas réussit à trouver le charset correct
						sourceEncoding = Charset.defaultCharset().name();
						g.AfficheMessage("\n** Impossible de détecter l'encodage du fichier source.\n** Utilisation de l'encodage par défaut: " + sourceEncoding + "\n",Nat.LOG_NORMAL);
					}
					else
					{
						g.AfficheMessage("\n** Détection automatique de l'encodage du fichier source: "+sourceEncoding+"\n", Nat.LOG_NORMAL);
					}
				}
				if(ConfigNat.getCurrentConfig().getTraiterMaths()||ConfigNat.getCurrentConfig().getTraiterMusique())
				{
					c=new ConvertisseurTexteMixte(fs,fTempXML, sourceEncoding);
					//TODO une fois prêt, remplacer par ConvertisseurTexteXML
				}
				else
				{
					c=new ConvertisseurTexte(fs,fTempXML, sourceEncoding);
				}
			}
			else if (sourceMimeType.equals("")||fs.endsWith("odt")||fs.endsWith("sxw"))
			{
				// fichier openoffice
				g.AfficheMessage("\n** Le fichier source est identifié comme document openoffice ", Nat.LOG_NORMAL);
				c=new ConvertisseurOpenOffice(fs,fTempXML);
			}
			else if(sourceMimeType.equals("text/html"))
			{
				g.AfficheMessage("\n** Le fichier source est identifié comme document xml/html" , Nat.LOG_NORMAL);
				c=new ConvertisseurXML(fs,fTempXML);
			}
			else if(sourceMimeType.equals("application/xml"))
			{
				c=new ConvertisseurXML(fs,fTempXML);
			}
			else
			{
				//defaut
				g.AfficheMessage("\n** Le fichier source est identifié par défaut comme texte" , Nat.LOG_NORMAL);
				c=new ConvertisseurTexteXML(fs,fTempXML);
				p=new PresentateurSans(g, "UTF-8", fTempTxt, fc);
			}		
			
			//sortieEncoding = conf.getSortieEncoding();
			if (sortieEncoding.compareTo("automatique")==0)
		    {
				if(sourceEncoding.equals("automatique"))
				{
					sortieEncoding = Charset.defaultCharset().name();
				}
				else
				{
					sortieEncoding = sourceEncoding;
				}	
		    }
			
			p=new PresentateurSans(g, sortieEncoding, fTempTxt, fc);
			t=new Transcodeur(fTempXML,fTempTxt,"UTF-8");
			/* TAN **/
			if(fs.endsWith(".tan"))
			    {
				t.setSens(true);
			    }
			retour = new Transcription(g, c, t, p);
		    }
		return retour;
    }
    public String getSourceMimeType(){return sourceMimeType;}
    /*
    //methodes d'accès
    public void setConvertisseur(Convertisseur c){conv=c;}
    public void setTranscodeur(Transcodeur t){trans=t;}
    public void setPresentateur(Presentateur p){pres=p;}
    public void setGestionnaireErreur(GestionnaireErreur g){gest = g;}
    public void setSource(String s){source = s;}
    public void setCible(String c){sortie=c;}
    */
    public boolean transcrire()
    {
		boolean ok = true;
		/*TAN ! */
		if (trans.getSens())
	    {
			gest.AfficheMessage("\n     ********\n     * TAN \n     *******",Nat.LOG_SILENCIEUX);
	    }
		gest.AfficheMessage("\nDébut de la conversion du document ... \n",Nat.LOG_SILENCIEUX);
		ok = conv.convertir(gest);
		if(ok)
	    {
			gest.AfficheMessage("\n--Conversion terminée en " + conv.donneTempsExecution() + " msec.\n",Nat.LOG_SILENCIEUX);
			ok=trans.Transcrire(gest);
	    }
		if(ok)
	    {
			gest.AfficheMessage("\n--Transcription terminée en " + trans.donneTempsExecution() + " msec.\n",Nat.LOG_SILENCIEUX);
			ok=pres.presenter();
	    }
		if(ok)
	    {
			gest.AfficheMessage("\n--Mise en forme terminée en " + pres.donneTempsExecution() + " msec.\n",Nat.LOG_SILENCIEUX);
			long tempsExecution = conv.donneTempsExecution() + trans.donneTempsExecution() + pres.donneTempsExecution();
			gest.AfficheMessage("\n----Transcription terminée en " + tempsExecution/1000 +"," + tempsExecution%1000+" sec.\n",Nat.LOG_SILENCIEUX);
	    }
		return ok;
    }	
	private static String trouveMimeTypeSource(String source, GestionnaireErreur gest)
	{
	    String retour ="";
		File file = new File(source);
		if (verifFichier(file,gest))
		{
			try
			{
				 // file.toURL() déprécié en java 6
				 URL url = file.toURI().toURL();
				 URLConnection connection = url.openConnection();
				 retour = connection.getContentType();
			}
			catch(MalformedURLException mue)
			{
				gest.setException(mue);
				gest.GestionErreur();
			}
			catch(IOException ioe)
			{
				gest.setException(ioe);
				gest.GestionErreur();
			}
		}
		return retour;
	}

	public static String trouveEncodingSource(String source, GestionnaireErreur gest)
	{
		String sourceEncoding = "";
		File file = new File(source);
		if (verifFichier(file,gest))
		{
			try
			{
				 URL url = file.toURI().toURL();
				 URLConnection connection = url.openConnection();
				 sourceEncoding = connection.getContentEncoding();
			}
			catch(MalformedURLException mue)
			{
				gest.setException(mue);
				gest.GestionErreur();
			}
			catch(IOException ioe)
			{
				gest.setException(ioe);
				gest.GestionErreur();
			}
		}
		//l'encoding n'est pas forcément détecté, si c'est le cas on essaye avec une autre méthode
		if (sourceEncoding==null)
		{
			//gest.AfficheMessage("Deuxième méthode encodage", 1);
			try
			{
				File fsource = new File(source);
				Charset guessedCharset = CharsetToolkit.guessEncoding(fsource, 4096,Charset.defaultCharset());
				if (guessedCharset != null)
				{
					sourceEncoding=guessedCharset.name();
				}
			}
			catch (FileNotFoundException fnfe)
			{
				gest.setException(fnfe);
				gest.GestionErreur();
			}
			catch (IOException ioe)
			{
				gest.setException(ioe);
				gest.GestionErreur();
			}
		}
		return sourceEncoding;
	}

	private static boolean verifFichier(File file, GestionnaireErreur gest)
	{
		boolean retour = true;
		if(file.isDirectory())
		{
			gest.AfficheMessage("nok\n *Erreur: "+file.getAbsolutePath()+" est un répertoire et non un fichier",Nat.LOG_SILENCIEUX);
			retour = false;
		}
		else if(!file.exists())
		{
			gest.AfficheMessage("nok\n*Erreur: le fichier "+file.getAbsolutePath()+" n'existe pas", Nat.LOG_SILENCIEUX);
			retour = false;
		}
		
		return retour;
	}
}