/* $Id: Xml2Latex.java,v 1.23 2005/10/17 17:14:52 m31 Exp $
 *
 * This file is part of the project "Hilbert II" - http://www.qedeq.org
 *
 * Copyright 2000-2005,  Michael Meyling <mime@qedeq.org>.
 *
 * "Hilbert II" 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, or (at your option) any later version.
 *
 * 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.
 */

package org.qedeq.kernel.rel.test.text;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.xml.parsers.ParserConfigurationException;

import org.qedeq.kernel.bo.control.IllegalModuleDataException;
import org.qedeq.kernel.context.KernelContext;
import org.qedeq.kernel.latex.Qedeq2Latex;
import org.qedeq.kernel.log.Trace;
import org.qedeq.kernel.utility.IoUtility;
import org.qedeq.kernel.xml.handler.module.QedeqHandler;
import org.qedeq.kernel.xml.parser.SaxDefaultHandler;
import org.qedeq.kernel.xml.parser.SaxParser;
import org.qedeq.kernel.xml.parser.SyntaxException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;


/**
 * Test application.
 *
 * @version $Revision: 1.23 $
 * @author    Michael Meyling
 */
public final class Xml2Latex  {

    /** Location of trace file. */
    public static final String TRACE_FILE_PATH = "log/trace.txt";

    /** Is the trace already initialized? */
    private static boolean initialized;


    /**
     * Constructor.
     */
    private Xml2Latex() {
        // nothing to do
    }

    /**
     * Main method.
     *
     * @param   args    Various parameters. See implementation of {@link #printProgramInformation()}.
     */
    public static void main(final String[] args) {
        String language = null;
        String level = null;
        String from = null;
        String to = null;

        if (args.length == 0) {
            printProgramInformation();
            return;
        }

        for (int i = 0; i < args.length; i++) {
            if (args[i].startsWith("-")) {  // option
                final String option = args[i].substring(1).toLowerCase();
                if (option.equals("help") || option.equals("h")
                        || option.equals("?")) {
                    printProgramInformation();
                    return;
                }
                if (option.equals("language")) {
                    if (i + 1 >= args.length) {
                        printArgumentError("\"-language\" must be followed by a language.");
                        return;
                    }
                    language = args[i + 1];
                    i++;
                } else if (option.equals("level")) {
                    if (i + 1 >= args.length) {
                        printArgumentError("\"-level\" must be followed by a level.");
                        return;
                    }
                    level = args[i + 1];
                    i++;
                } else if (option.equals("to")) {
                    if (i + 1 >= args.length) {
                        printArgumentError("\"-to\" must be followed by a filename.");
                        return;
                    }
                    to = args[i + 1];
                    i++;
                } else {                    // unknown option
                    printArgumentError("Unknown option: " + option);
                    return;
                }
            } else {                        // no option, must be file name
                if (from != null) {
                    printArgumentError("XML file name must only be specified once.");
                    return;
                }
                from = args[i];
            }
        }
        if (from == null) {
            printArgumentError("XML file must be specified.");
            return;
        }
        System.out.println(IoUtility.getClassName(Xml2Latex.class) + ", running on: "
            + KernelContext.getDescriptiveKernelVersion());
        try {
            System.out.println("Successfully generated:\n" + generate(from, to, language, level));
        } catch (XmlFilePositionException e) {
            System.out.println(e.getDescription());
        } catch (RuntimeException e) {
            System.out.println(e);
        }
    }

    /**
     * Initialize trace file. See {@link #TRACE_FILE_PATH}.
     *
     * @throws  IOException Initialization failed.
     */
    public static void initalizeTrace() throws IOException {
        if (!initialized) {
            final File traceFile = new File(TRACE_FILE_PATH);
            IoUtility.createNecessaryDirectories(traceFile);
            Trace.setPrintStream(new PrintStream(new FileOutputStream(traceFile)));
            initialized = true;
            System.out.println("Logging into file: " + traceFile.getAbsolutePath());
        }
    }

    /**
     * Writes calling convention to <code>System.err</code>.
     */
    public static void printProgramInformation() {
        System.err.println("Name");
        System.err.println("----");
        System.err.println(IoUtility.getClassName(Xml2Latex.class) + " - create LaTeX document");
        System.err.println();
        System.err.println("Synopsis");
        System.err.println("-------------------");
        System.err.println("[-h] [-language <language>] [-level <level>] <xmlFile> [-to <latexFile>]");
        System.err.println();
        System.err.println("Description");
        System.err.println("-----------");
        System.err.println("This program creates a LaTeX file out of *Hilbert II* XML files.");
        System.err.println("If no \"-to\" filename was given, the resulting LaTeX file is at the same");
        System.err.println("place as the original file but has the extension \".xml\".");
        System.err.println();
        System.err.println("Options and Parameter");
        System.err.println("---------------------");
        System.err.println("-h         writes this text and returns");
        System.err.println("-language  set the language filter (default: \"en\")");
        System.err.println("-level     the level filter (default: \"1\")");
        System.err.println("<xmlFile>  XML file that fulfills the XSD from \"http://www.qedeq.org/"
            + KernelContext.getKernelVersionDirectory() + "\"");
        System.err.println("-to <file> write result into this file");
        System.err.println();
        System.err.println("Parameter Examples");
        System.err.println("------------------");
        System.err.println("sample/qedeq_basic_concept.xml");
        System.err.println();
        System.err.println("Further information");
        System.err.println("-------------------");
        System.err.println("For more information about *Hilbert II* look at:");
        System.err.println("\thttp://www.qedeq.org/");
        System.err.println();
    }

    private static void printArgumentError(final String message) {
        System.err.println(">>>ERROR reason:");
        System.err.println(message);
        System.err.println();
        System.err.println(">>>Calling convention:");
        printProgramInformation();
    }
    
    /**
     * Generate LaTeX file out of XML file. Also initializes trace file.
     *
     * @param   from            Read this XML file.
     * @param   to              Write to this file. Could be <code>null</code>.
     * @param   language        Resulting language. Could be <code>null</code>.
     * @param   level           Resulting detail level. Could be <code>null</code>.
     * @return  File name of generated LaTeX file.
     * @throws  XmlFilePositionException 
     */
    public static String generate(final String from, final String to, final String language, final String level)
            throws XmlFilePositionException {
        final String method = "generate(String, String, String, String)";
        try {
            initalizeTrace();
            Trace.traceBegin(Xml2Latex.class, method);
            Trace.traceParam(Xml2Latex.class, method, "from", from);
            Trace.traceParam(Xml2Latex.class, method, "to", to);
            Trace.traceParam(Xml2Latex.class, method, "language", language);
            Trace.traceParam(Xml2Latex.class, method, "level", level);
            final File source = new File(from);
            final File destination;
            if (to != null) {
                destination = source;
            } else {
                String tex = source.getName();
                if (tex.toLowerCase().endsWith(".xml")) {
                    tex = tex.substring(0, tex.length() - 4);
                }
                if (language != null && language.length() > 0) {
                    tex = tex + "_" + language;
                }
                destination = new File(source.getParentFile(), tex + ".tex");
            }
            SaxDefaultHandler handler = new SaxDefaultHandler();
            QedeqHandler simple = new QedeqHandler(handler);
            handler.setBasisDocumentHandler(simple);
            SaxParser parser = new SaxParser(handler);
            try {
                parser.parse(source);
            } catch (SAXException ex) {
                if (parser.getExceptionList().size() > 0) {
                    final Exception exc = parser.getExceptionList().get(0);
                    if (exc instanceof SyntaxException) {   // TODO mime 20050826: give more than one
                        throw new XmlFilePositionException((SyntaxException) exc);
                    }
                }
                throw ex;
            }

            // System.out.println(simple.getQedeq().toString());
            final Qedeq2Latex converter;
            try {
                converter = new Qedeq2Latex(from, simple.getQedeq());
            } catch (IllegalModuleDataException e) {
                throw new XmlFilePositionException(e);
            }
            IoUtility.createNecessaryDirectories(destination);
            final OutputStream outputStream = new FileOutputStream(destination);
            converter.printLatex(language, level, outputStream);
            outputStream.close();
            return destination.getAbsolutePath();
        } catch (RuntimeException e) {
            Trace.trace(Xml2Latex.class, method, e);
            throw new XmlFilePositionException(from, e);
        } catch (IOException e) {
            Trace.trace(Xml2Latex.class, method, e);
            throw new XmlFilePositionException(e);
        } catch (ParserConfigurationException e) {
            Trace.trace(Xml2Latex.class, method, e);
            throw new XmlFilePositionException(e);
        } catch (final SAXParseException e) {
            Trace.trace(Xml2Latex.class, method, e);
            throw new XmlFilePositionException(e);
        } catch (SAXException e) {
            Trace.trace(Xml2Latex.class, method, e);
            throw new XmlFilePositionException(from, e);
        } catch (javax.xml.parsers.FactoryConfigurationError e) {
            Trace.trace(Xml2Latex.class, method, e);
            final String msg = "SAX Parser not in classpath, "
                + "add for example \"xercesImpl.jar\" and \"xml-apis.jar\".";
            throw new XmlFilePositionException(new IOException(msg));
        } finally {
            Trace.traceEnd(Xml2Latex.class, method);
        }
    }

}
