package com.diaam.xmlfr.faqjaxp;

import java.io.*;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FilterOutputStream;
import java.io.PrintStream;
import javax.xml.parsers.SAXParserFactory; 
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;


/**
* Le principe est de lancer la tache pour placer une DTD dans le document,
* et une tâche pour valider selon la DTD.
*
* @param args [fichier XML] [fichier DTD]
* 
* 
*/
public class MetDTD
{
  public static void main(String[] args) throws Exception
  {
    String nomFichierXML;
    String nomFichierDTD;
    File propsFichierXML;
    PipedOutputStream pipeEcrit;
    PipedInputStream pipeLu;
    FilterOutputStream fluxAvecDTD;
    StreamResult résultatAvecDTD;
    InputSource entréeAvecDTD;
    Thread courseDTD;
    Thread courseValidante;
    Runnable coureurDTD;
    Runnable coureurValidant;
        
    nomFichierXML = args[0];
    nomFichierDTD = args[1];
    
    // on fait le pipe entre la tache qui place la DTD et la tache qui valide
    propsFichierXML = new File(nomFichierXML);
    propsFichierXML = propsFichierXML.getCanonicalFile();
    pipeEcrit = new PipedOutputStream();
    pipeLu = new PipedInputStream(pipeEcrit);
    fluxAvecDTD = new PrintStream(pipeEcrit);
    résultatAvecDTD = new StreamResult(fluxAvecDTD);
    entréeAvecDTD = new InputSource(pipeLu);
    entréeAvecDTD.setSystemId(propsFichierXML.getParentFile().toURL().toString());
    
    // on lance les threads correspondants.
    coureurDTD = new CoursePourPlacerDTD
    (nomFichierXML, nomFichierDTD, résultatAvecDTD);
    coureurValidant = new CoursePourValider(entréeAvecDTD);
    courseDTD = new Thread(coureurDTD);
    courseValidante = new Thread(coureurValidant);
    courseDTD.start();
    courseValidante.start();
  }
  
  /**
  * Thread pour placer la DTD.
  */
  private static class CoursePourPlacerDTD implements java.lang.Runnable
  {
    private Transformer m_transfo;
    private Source m_source;
    private Result m_résultat;
    
    CoursePourPlacerDTD
    (String nomFichierXML, String nomFichierDTD, Result résultat) 
    throws Exception
    {
      FileInputStream fichierXML;
      TransformerFactory fabrique;
    
      fichierXML = new FileInputStream(nomFichierXML);
      fabrique = TransformerFactory.newInstance();
      m_transfo = fabrique.newTransformer();
      m_transfo.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, nomFichierDTD);
      m_source = new StreamSource(fichierXML);
      m_résultat = résultat;
    }
    
    public void run()
    {
      try
      {
	m_transfo.transform(m_source, m_résultat);
	Object o = new Object();
	((StreamResult)m_résultat).getOutputStream().close();
      }
      catch (Exception e)
      {
	e.printStackTrace();
      }
    }
  }
  
  /**
  * Thread pour valider.
  *
  */
  private static class CoursePourValider implements java.lang.Runnable
  {
    private SAXParser m_pilote;
    private InputSource m_fluxLecture;
    
    CoursePourValider(InputSource fluxAValider) throws Exception
    {
      SAXParserFactory fabriquePilotes;
      SAXParser piloteValidant;
      
      fabriquePilotes = SAXParserFactory.newInstance();
      fabriquePilotes.setValidating(true);
      m_pilote = fabriquePilotes.newSAXParser();
      m_fluxLecture = fluxAValider;
    }
    
    public void run()
    {
      try
      {
	m_pilote.parse(m_fluxLecture, new DenonceErreurs());
      }
      catch (Exception e)
      {
	e.printStackTrace();
      }
    }
    
    private class DenonceErreurs extends org.xml.sax.helpers.DefaultHandler
    {
      public void error(SAXParseException e) throws SAXException
      {
	System.err.println("-- DOCUMENT INVALIDE --");
	System.err.println(e.getMessage());
	System.err.println(" colonne : "+e.getColumnNumber());
	System.err.println(" ligne : "+e.getLineNumber());
	System.err.println(" PublicId : "+e.getPublicId());
	System.err.println(" SystemId : "+e.getSystemId());
      }
    }
  }
}
