/****************************************************************************/
/* Copyright/Copyleft: 
 * 
 * For this source the LGPL Lesser General Public License, 
 * published by the Free Software Foundation is valid.
 * It means:
 * 1) You can use this source without any restriction for any desired purpose.
 * 2) You can redistribute copies of this source to everybody.
 * 3) Every user of this source, also the user of redistribute copies 
 *    with or without payment, must accept this license for further using.
 * 4) But the LPGL ist not appropriate for a whole software product,
 *    if this source is only a part of them. It means, the user 
 *    must publish this part of source,
 *    but don't need to publish the whole source of the own product.
 * 5) You can study and modify (improve) this source 
 *    for own using or for redistribution, but you have to license the
 *    modified sources likewise under this LGPL Lesser General Public License.
 *    You mustn't delete this Copyright/Copyleft inscription in this source file.    
 *
 * @author www.vishia.de/Java
 * @version 2006-06-15  (year-month-day)
 * list of changes: 
 * 2006-05-00: www.vishia.de creation
 *
 ****************************************************************************/

package org.vishia.xml;

import org.jdom.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
//import java.io.*;

import org.vishia.mainCmd.*;
import org.vishia.xmlSimple.XmlException;

/** Class to transform XML files with XSLT. 
 *  This class is also used inside the vishia.xslt.Xslt XSL Translator. 
 *  See <a href="Xslt.html">Xslt</a> for Description of command line
 *  or argument string invocation and Description of features of the translator.
 */
public class XslTransformer
{
  /** contact to the streamoriented output*/
  private final Report main;
  //Document docu;
  private Element xmlRoot;

  /** Class holding one element inside the List "listFileIn" of the transform-method.
   * 
   * 
   */
  public static class FileTypeIn
  { public static final int mReplaceWhiteSpaceWith1Space = 0x0001;
    public static final int mExpandAsciiFormating        = 0x0002;
    private final String sName;
    /** Mode of preprocessing inputfile, see m... */
    private final int mode; 

    private final File fileIn;
    
    public FileTypeIn(String sFileIn, int mode)
    { sName = sFileIn;
      fileIn = new File(sName);
      this.mode = mode;
    }
    
    public Element readXmlFile()
    throws XsltException, FileNotFoundException
    {
      Element xmlInput = null;
      try
      { if( (mode & mReplaceWhiteSpaceWith1Space ) != 0)
        { xmlInput = XmlExtensions.readXmlFileTrimWhiteSpace(fileIn);
        }
        else
        { xmlInput = XmlExtensions.readXmlFile(fileIn);
        }
      }
      catch(XmlException exception){ throw new XsltException(exception.getMessage(), Report.exitWithFileProblems, exception);}
      return xmlInput;
    }
    
    public String getAbsolutePath()
    { return fileIn.getAbsolutePath();
    }
  }

  
  
  
  
  /** The instance should known a main interface 
   * 
   * @param main The instance to report something.
   */
  XslTransformer(Report main)
  { this.main = main;
  }


  /** Transforms some input XML-files via XSL to one output XML-file.
    @param listFileIn List of input file pathes, given as Instances of FileTypeIn.
    @param fileXsl translater xsl file
    @param sFileOut Path of the output file
    @param mode Mode of conversion, text or xml
    @param fileInputOnError may be null, if not null and any error occurs, the input tree
           is written to this file to enable check it by user.
    @throws XsltException if any error. The exception contains a string from this
            method with pathes, the exitErrorLevel and the original exception.
   * @throws FileNotFoundException if the output file cannot be written or replaced.
   * @throws XmlException 
  */
  public void transform
  ( List<FileTypeIn> listFileIn
  , File fileXsl
  , File  fileOut
  , XmlExtensions.XmlMode mode
  , File fileInputOnError
  )
  throws XsltException, FileNotFoundException, XmlException
  { //boolean bOk = true;  //successfull work

    String sPath = fileOut.getAbsolutePath();
    xmlRoot = new Element("root");
    Iterator<FileTypeIn> iterFileIn = listFileIn.iterator();
    while(iterFileIn.hasNext())
    { //add one xml-tree from the given input file to /root
      FileTypeIn input = (FileTypeIn)(iterFileIn.next());
      String sFileIn = input.sName;
      main.reportln(Report.info, "reading " + sFileIn);
      Element xmlInput = input.readXmlFile();
      xmlInput.detach();
      xmlRoot.addContent(xmlInput);
      main.report(Report.info," ...done.");
    }
    try{ XmlExtensions.writeXmlDirect(xmlRoot, new File(sPath + ".i.xml"), "ISO-8859-1"); }
    catch(XmlException exception){ main.report("test", exception); }
    if(mode.isText())
    { //conversion produce a text
      //catch(IOException exception ){ main.exit("ERROR writing" + sName + "\n  " + exception.getMessage(), Report.exitWithFileProblems, exception);}
    }
    else if(mode.isXml())
    { //conversion produce a xml tree or xhtml tree:
      Element xmlOut = null;
      Exception transformException = null;
      main.reportln(Report.info, "translating via " + fileXsl.getAbsolutePath());
      try{ xmlOut = XmlExtensions.xslTransformXml(xmlRoot, fileXsl);}
      catch(XmlException exception)
      { //System.out.println("...error transformation!");
      	transformException = exception;
      }
      if(transformException != null)
      { //try to write the input tree to the output file to report the input:
        Element xmlError = new Element("TheInputTreeOnError");
        xmlRoot.detach();
        xmlError.addContent(xmlRoot);
      	if(fileInputOnError != null)
        { try{ XmlExtensions.writeXmlFile(xmlError, fileInputOnError, mode); }
	        catch(XmlException exception)
	        { throw new XsltException
	        	( "ERROR translating and writing:" 
	          + fileOut.getAbsolutePath() 
	          + "\n  " + exception.getMessage()
	          + transformException.getMessage()
	          , Report.exitWithFileProblems, exception);
	        }
        }
	      throw new XsltException("ERROR translating with:" + fileXsl.getAbsolutePath() + "\n  " + transformException.getMessage(), Report.exitWithFileProblems, transformException);
      }
      main.report(Report.info," ...done.");
      main.reportln(Report.info, "writing " + sPath);

	    try{ XmlExtensions.writeXmlDirect(xmlOut, new File(sPath + ".a.xml"), "ISO-8859-1"); }
	    catch(XmlException exception){ main.report("test-a", exception); }
      
      //ConverterWikistyleTextToXml toWikistyle = new ConverterWikistyleTextToXml(main); 
      //toWikistyle.testXmlTreeAndConvert(xmlOut);

	    try{ XmlExtensions.writeXmlDirect(xmlRoot, new File(sPath + ".b.xml"), "ISO-8859-1"); }
	    catch(XmlException exception){ main.report("test-b", exception); }
      

      if(mode.isIndent())
      { xmlOut = XmlExtensions.beautificationBewareTextContent(xmlOut);
      }
      try{ XmlExtensions.writeXmlFile(xmlOut, fileOut, mode); }
      catch(XmlException exception)
      { throw new XsltException("ERROR writing:" + fileOut.getAbsolutePath() + "\n  " + exception.getMessage(), Report.exitWithFileProblems, exception);
      }
      main.report(Report.info, " ...done.");
    }
    else
    { throw new XsltException("failed convert mode", Report.exitWithArgumentError);
    }
  }

  
  
  
}







