/*
 * $Id: TexDocConverter.java,v 1.9 2007/11/05 08:53:42 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: TexDocConverter.java,v $
 * Revision 1.9  2007/11/05 08:53:42  marbobo
 * + Bugfix (Statt List werden HashSet benutzt)
 *
 * Revision 1.8  2007/07/10 11:24:01  marbobo
 * + Bugfix: Dateiname die an ProcessKiller übergeben wird korrigiert
 *
 * Revision 1.7  2007/02/12 07:15:57  lawern
 * Überarbeitung und Anpassung an Linux
 *
 * Revision 1.6  2006/06/06 20:36:02  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.5  2006/04/13 09:59:18  korowa
 * Nur erlaubte Konvertierungen werden durchgeführt(DocConverter:conversions) bzw. zurückgeliefert.
 *
 * Revision 1.4  2005/01/21 12:55:35  lawern
 * debug=false vergessen
 *
 * Revision 1.3  2005/01/21 12:52:52  lawern
 * Ausgabe von hevea mit Parameter "-s" ausgeschaltet.
 *
 * Revision 1.2  2005/01/14 08:48:25  lawern
 * debug auf false gesetzt
 *
 * Revision 1.1  2005/01/14 08:07:56  lawern
 * Latex-Konverter hinzugefügt
 *
 */
package vkc.converter;

import vkc.misc.ProcessKiller;
import vkc.misc.VKCLogManager;
import vkc.misc.VKCProcess;

import vkc.util.FileUtils;
import vkc.util.VKCInputStream;
import vkc.util.ZipUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import java.net.URL;

import java.util.ArrayList;
import java.util.Collection;

/**
 * Klasse zum Konvertieren von Textdokumenten.
 *
 * @author lawern
 */
public class TexDocConverter extends DocConverter {
	private static final boolean debug = false;

	public static String docSuffix = ".tex";

	private HtmlDocConverter htmlConverter = null;

	private String[] cmdarr;

	private String[] env = new String[1];

	private File dir = null;

	private File zipFile = null;

	private String htmlFile = null;

	private File htmlDir = null;

	private File pdfFile = null;

	public TexDocConverter() {
	}

	/**
	 * Liefert den Suffix für temporäre Dateien zurück.
	 *
	 * @return docSuffix
	 */
	public String getDocSuffix() {
		return docSuffix;
	}

	/**
	 * Diese Methode konvertiert das übergebene Dokument in die in der
	 * Collection definierten Formate. Der Parameter conversions wird zur Zeit
	 * noch nicht ausgewertet.
	 *
	 * @param docFile URL des zu konvertierendes Dokument
	 * @param conversions Collection von VKCDocumentTypes welche die zu
	 *        erzeugenden Konvertierungen beschreibt.
	 */
	public void convert(URL docFile, Collection conversions) {
		if (debug) {
			System.out.println("TexDocConverter: " + docFile);
		}

		//String docFileString = VKCUtils.getLocalPath(docFile);
		VKCProcess process = null;

		try {
			dir = new File(basePath).getCanonicalFile();
		} catch (IOException ioe) {
			VKCLogManager.errorLog(this, "7", "Base path not found!", ioe);
		}

		InputStream docStream = null;
		File tmpFile = null;

		try {
			//Datei von Url in temporäre Datei schreiben
			docStream = docFile.openStream();

			if (docStream != null) {
				tmpFile = File.createTempFile("TexDoc", ".tex");

				if (!debug) {
					tmpFile.deleteOnExit();
				}

				//InputStream in StringBuffer einlesen
				StringBuffer buffer = FileUtils.toStringBuffer(docStream);

				//Testen ob Latex-Bedingungen erfüllt und ggf. Latex-Styles ergänzen
				if (buffer.indexOf("\\begin{document}") < 0) {
					buffer.insert(0, "\\begin{document}\n");
				}

				if (buffer.indexOf("\\end{document}") < 0) {
					buffer.append("\\end{document}\n");
				}

                if (buffer.indexOf("{inputenc}")< 0) {
                    buffer.insert(0, "\\usepackage[latin1]{inputenc}\n");
                }
                
				if (buffer.indexOf("\\documentclass") < 0) {
					buffer.insert(0, "\\documentclass[11pt]{article}\n");
				}

				//geänderten StringBuffer schreiben
                FileUtils.saveByteArray(tmpFile, buffer.toString().getBytes("iso-8859-1"), null, true);
				FileUtils.closeInputStream(docStream);

				try {
					htmlDir = File.createTempFile("TexDoc", "");
					htmlDir.delete();
					htmlDir.mkdir();

					if (!debug) {
						htmlDir.deleteOnExit();
					}

					htmlFile = htmlDir.getCanonicalPath() + File.separator + "index.html";
				} catch (java.io.IOException ioe) {
					VKCLogManager.errorLog(this, "3", "Can't create temp-file.", ioe);
				}

				// Kommando-Array mit Voreinstellung für den Konverter
				// initialisieren
                if (windows) {
//                  Environment-Variablen setzen
                    env[0] = "heveadir=" + dir + File.separator + "hevea"; 
                    
                    cmdarr = new String[5];
                    cmdarr[0] = dir + File.separator + "hevea" + File.separator
                            + "hevea.exe";
                    cmdarr[1] = tmpFile.getCanonicalPath();
                    cmdarr[2] = "-s";
                    cmdarr[3] = "-o";
                    cmdarr[4] = htmlFile;
                    
                    String texFile = cmdarr[1].substring(cmdarr[1].lastIndexOf(File.separator) + 1);
                    ProcessKiller killer = new ProcessKiller(texFile, timeout + 1);
                    killer.start();
                    process = new VKCProcess(cmdarr, env, dir);
                    process.executeAndWaitWithTimeout(timeout * 60);
                    killer.interrupt();
                } else {
                    cmdarr = new String[5];
                    cmdarr[0] = "hevea";
                    cmdarr[1] = tmpFile.getCanonicalPath();
                    cmdarr[2] = "-s";
                    cmdarr[3] = "-o";
                    cmdarr[4] = htmlFile;
                    
                    process = new VKCProcess(cmdarr, null, dir);
                    process.executeAndWaitWithTimeout(timeout * 60);
                }

				FileUtils.deleteZeroByteFile(new File(htmlFile));

				if (!new File(htmlFile).exists()) {
					VKCLogManager.errorLog(this, "6", "HTML conversion not generated.");

					try {
						FileUtils.deleteDirectory(htmlDir);
					} catch (Exception ex) {
						VKCLogManager.errorLog(this, "", ex.getMessage(), ex);
					}
				} else {
					try {
						//Html-Version zusammenzipen
						zipFile = File.createTempFile("TexDoc", ".zip");

						if (!debug) {
							zipFile.deleteOnExit();
						}

						ZipUtils.zip(htmlDir, zipFile, true, htmlDir.getCanonicalPath() + File.separator);
					} catch (java.io.IOException ioe) {
						VKCLogManager.errorLog(this, "4", "Can't create temp-file.", ioe);
					}

					//Der übergeben null-Parameter muss später durch eine Collection ersetzt werden,
					//welche dafür sorgt, dass nur ein Tdf-Stream erzeugt wird!!!
					if (enableTdf) {
						htmlConverter = new HtmlDocConverter();
						htmlConverter.convert(new File(htmlFile).toURL(), null);
					}

					//PDF-Stream erzeugen. Geht nur mit installiertem OpenOffice
					/*
					 if(enablePdf && openOffice){
					 try {
					 pdfFile = File.createTempFile("temp",".pdf");
					 if (!debug) {
					 pdfFile.deleteOnExit();
					 }
					 String[] convertTypes = new String[1];
					 TODO: im Mai 2006 sollte neuer Update für OO mit LatexExportFilter erscheinen,
					 dann muss die Pdf-Erzeugung verfolständigt werden
					 convertTypes[0] = " hier soll der Name des Filters rein";
					 
					 
					 URL[] urls = new URL[1];
					 urls[0] = pdfFile.toURL();                       
					 
					 new SOfficeDocConverter().convert(new File(htmlFile).toURL(), convertTypes, urls);
					 } catch (IOException e1) {
					 VKCLogManager.errorLog(this, "", e1.getMessage(),e1);
					 } 	
					 }
					 */
                    if (enablePdf && openOffice) {
                        try {
                            pdfFile = File.createTempFile("temp", ".pdf");
                            
                            if (!debug) {
                                pdfFile.deleteOnExit();
                            }
                            
                            String[] convertTypes = new String[1];
                            convertTypes[0] = "writer_web_pdf_Export";

                            URL[] urls = new URL[1];
                            urls[0] = pdfFile.toURL();

                            new SOfficeDocConverter().convert(new File(htmlFile).toURL(), convertTypes, urls);
                        } catch (IOException e1) {
                            VKCLogManager.errorLog(this, "", e1.getMessage(), e1);
                        }
                    }
                    
					FileUtils.deleteZeroByteFile(pdfFile);
					//Html-Verzeichnis löschen
					try {
						FileUtils.deleteDirectory(htmlDir);
					} catch (Exception ex) {
						VKCLogManager.errorLog(this, "5", "Can't delete temp-dir.", ex);
					}
				}
			} else {
				VKCLogManager.errorLog(this, "9", "Can't open stream from url: " + docFile);
			}
		} catch (Exception e) {
			if (tmpFile != null) {
				VKCLogManager.errorLog(this, "8", "Can't create temp-file: " + tmpFile.getPath(), e);
			} else {
				VKCLogManager.errorLog(this, "8", "Can't create temp-file!", e);
			}

			FileUtils.closeInputStream(docStream);
		} finally {
			//temporäre Dokumentendatei löschen
			if (!debug) {
				if (tmpFile != null) {
					tmpFile.delete();
				}
			}
		}
	}

	/**
	 * Liefert nach dem Aufruf der convert-Methode den Stream der
	 * Tdf-Konvertierung.
	 *
	 * @return Stream der Tdf-Konvertierung oder <code>null</code> falls er
	 *         nicht existiert
	 */
	public VKCInputStream getTdfStream() {
		if (htmlConverter != null && enableTdf) {
			return htmlConverter.getTdfStream();
		}

		return null;
	}

	/**
	 * Liefert nach dem Aufruf der convert-Methode den Stream der
	 * HTML-Konvertierung.
	 *
	 * @return Stream der HTML-Konvertierung oder <code>null</code> falls er
	 *         nicht existiert
	 */
	public VKCInputStream getHtmlStream() {
		if (zipFile != null && enableHtml) {
			incOpenStreams();

			try {
				return new VKCInputStream(new BufferedInputStream(new FileInputStream(zipFile)), zipFile.length()) {
					public void close() throws IOException {
						super.close();
						closeHtmlStream();
					}
				};
			} catch (Exception e) {
				VKCLogManager.errorLog(this, "2", "ZIP-File not found!", e);
			}
		}

		return null;
	}

	/**
	 * Liefert nach dem Aufruf der convert-Methode den Stream der
	 * PDF-Konvertierung.
	 *
	 * @return Stream der PDF-Konvertierung oder <code>null</code> falls er
	 *         nicht existiert
	 */
	public VKCInputStream getPdfStream() {
		if (pdfFile != null && enablePdf) {
			incOpenStreams();

			try {
				return new VKCInputStream(new BufferedInputStream(new FileInputStream(pdfFile)), pdfFile.length()) {
					public void close() throws IOException {
						super.close();
						closePdfStream();
					}
				};
			} catch (Exception e) {
				VKCLogManager.errorLog(this, "1", "PDF-File not found!", e);
			}
		}

		return null;
	}

	void closePdfStream() {
		if (debug) {
			System.out.println("closePdfStream");
		}

		decOpenStreams();
	}

	/**
	 * Gibt eine Liste zurueck, der alle HREFs einer Seite enthält.
	 *
	 * @return Link-Vektor
	 */
	public ArrayList getLinks() {
		if (htmlConverter != null) {
			return htmlConverter.getLinks();
		}

		return null;
	}

	/**
	 * Liefert den Titel des Dokuments zurück.
	 *
	 * @return Titel des Dokuments oder <code>null</code>
	 */
	public String getTitle() {
		if (htmlConverter != null) {
			return htmlConverter.getTitle();
		}

		return null;
	}

	/**
	 * Liefert eine Collection mit Objekten vom Typ TdfElement zurück, welche
	 * das Dokument beschreiben.
	 *
	 * @return Collection mit Objekten vom Typ TdfElement
	 */
	public Collection getElements() {
		if (htmlConverter != null) {
			return htmlConverter.getElements();
		}

		return null;
	}

	/**
	 * Löschen der TDF-Streams
	 */
	void closeTdfStream() {
		if (debug) {
			System.out.println("closeTdfStream");
		}

		decOpenStreams();
	}

	/**
	 * Löschen des Ascii-Streams
	 */
	void closeHtmlStream() {
		if (debug) {
			System.out.println("closeHtmlStream");
		}

		decOpenStreams();

		//ZIP-Datei löschen
		if (zipFile != null) {
			zipFile.delete();
		}
	}

	/**
	 * Schließt das Konverter-Objekt und fügt es wieder in den Konverter-Pool
	 * ein.
	 */
	final void closeConverter() {
		//temporäre Dateien löschen
		if (zipFile != null) {
			zipFile.delete();
		}
		//this-Referenz wieder in die Queue einfügen
	}
}