/*
 * $Id: PsDocConverter.java,v 1.16 2007/02/12 07:15:57 lawern Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: PsDocConverter.java,v $
 * Revision 1.16  2007/02/12 07:15:57  lawern
 * Überarbeitung und Anpassung an Linux
 *
 * Revision 1.15  2006/06/06 20:36:04  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.14  2006/04/11 13:50:31  korowa
 * Konvertierung ins PDF-Format hinzugefügt.Nur erlaubte Konvertierungen werden durchgeführt(DocConverter:conversions) bzw. zurückgeliefert.
 *
 * Revision 1.13  2006/03/23 11:36:43  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.12  2005/02/01 10:32:33  lawern
 * Ausgabe von Warnings bei pdftohtml unterdrückt: Führt zum Aufhängen.
 *
 * Revision 1.11  2004/11/10 15:02:43  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.10  2004/06/27 17:12:47  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.9  2003/11/29 22:13:53  koppy
 * InputStreams in VKCInputStream gekappselt
 *
 * Revision 1.8  2003/10/01 08:49:25  lawern
 * Html-Versionen auf Frames umgestellt
 *
 * Revision 1.7  2003/09/24 15:00:16  lawern
 * von getPath auf getCannonicalPath umgestellt
 *
 * Revision 1.6  2003/09/11 08:27:25  lawern
 * einige Methoden public gemacht
 *
 * Revision 1.5  2003/07/24 11:51:22  lawern
 * Umstellung auf XmlExtractor
 *
 * Revision 1.4  2003/06/26 15:15:22  lawern
 * XLS und PPT eingefügt und Konverter überarbeitet
 *
 * Revision 1.3  2003/06/18 12:42:03  lawern
 * erste funktionsfähige Version
 *
 *
 */
package vkc.converter;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;

import vkc.misc.VKCLogManager;
import vkc.misc.VKCProcess;
import vkc.util.FileUtils;
import vkc.util.VKCInputStream;
import vkc.util.ZipUtils;

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

	public static String docSuffix = ".ps";

	private XmlExtractor xmlExtractor;

	private String[] cmdarr1;

	private String[] cmdarr2;

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

	private File dir = null;

	private File zipFile = null;

	private String htmlFile = null;

	private File htmlDir = null;

	private File pdfFile = null;

	public PsDocConverter() {
	}

	/**
	 * 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("PsDocConverter: " + 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();
			tmpFile = File.createTempFile("PsDoc", ".ps");

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

			FileUtils.saveInputStream(tmpFile, docStream, true);
			FileUtils.closeInputStream(docStream);

			try {
				htmlDir = File.createTempFile("PsDoc", "");
				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);
			}

			try {
				pdfFile = File.createTempFile("PsDoc", ".pdf");

				if (!debug) {
					pdfFile.deleteOnExit();
				}
			} catch (java.io.IOException ioe) {
				VKCLogManager.errorLog(this, "8", "Can't create temp-pdf-file.", ioe);
			}

			// Environment-Variablen setzen
			env[0] = "path=" + dir + File.separator + "gs" + File.separator
					+ "bin;" + dir + File.separator + "gs" + File.separator
					+ "lib";
			env[1] = "GS_LIB=" + dir + File.separator + "fonts;" + dir
					+ File.separator + "gs" + File.separator + "lib";

			// Kommando-Array mit Voreinstellung für den PS2PDF-Konverter
			// initialisieren
            if (windows) {
                cmdarr1 = new String[5];
                cmdarr1[0] = "cmd";
                cmdarr1[1] = "/c";
                cmdarr1[2] = "ps2pdf";
                cmdarr1[3] = tmpFile.getCanonicalPath();
                cmdarr1[4] = pdfFile != null ? pdfFile.getAbsolutePath() : "";
            } else {
                cmdarr1 = new String[3];
                cmdarr1[0] = "ps2pdf";
                cmdarr1[1] = tmpFile.getCanonicalPath();
                cmdarr1[2] = pdfFile != null ? pdfFile.getAbsolutePath() : "";
            }

			process = new VKCProcess(cmdarr1, env, dir);
			process.executeAndWaitWithTimeout(timeout * 60);

			FileUtils.deleteZeroByteFile(pdfFile);
			
			if (pdfFile != null && pdfFile.exists() && enableHtml) {
				// Kommando-Array mit Voreinstellung für den PDFTOHTML-Konverter
				// initialisieren
                if (windows) {
                    cmdarr2 = new String[7];
                    cmdarr2[0] = "cmd";
                    cmdarr2[1] = "/c";
                    cmdarr2[2] = "pdftohtml";
                    // cmdarr2[3] = "-noframes";
                    cmdarr2[3] = "-c";
                    cmdarr2[4] = "-q";
                    cmdarr2[5] = pdfFile.getCanonicalPath();
                    cmdarr2[6] = htmlFile;
                } else {
                    cmdarr2 = new String[5];
                    cmdarr2[0] = "./pdftohtml";
                    // cmdarr2[1] = "-noframes";
                    cmdarr2[1] = "-c";
                    cmdarr2[2] = "-q";
                    cmdarr2[3] = pdfFile.getCanonicalPath();
                    cmdarr2[4] = htmlFile;
                }

				process = new VKCProcess(cmdarr2, env, dir);
				process.executeAndWaitWithTimeout(timeout * 60);

				FileUtils.deleteZeroByteFile(new File(htmlFile));

				if (htmlFile != null && !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("PsDoc", ".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);
					}

					//Html-Verzeichnis löschen
					try {
						FileUtils.deleteDirectory(htmlDir);
					} catch (Exception ex) {
						VKCLogManager.errorLog(this, "5", "Can't delete temp-dir.", ex);
					}
				}
			}
			
			if (pdfFile != null && pdfFile.exists() && enableTdf) {
				//XML-Datei erzeugen
				File xmlFile = File.createTempFile("PsDoc", "");
				if (windows) {
                    cmdarr2 = new String[7];
                    cmdarr2[0] = "cmd";
                    cmdarr2[1] = "/c";
                    cmdarr2[2] = "pdftohtml";
                    cmdarr2[3] = "-xml";
                    cmdarr2[4] = "-q";
                    cmdarr2[5] = pdfFile.getCanonicalPath();
                    cmdarr2[6] = xmlFile.getCanonicalPath();
                } else {
                    cmdarr2 = new String[5];
                    cmdarr2[0] = "./pdftohtml";
                    cmdarr2[1] = "-xml";
                    cmdarr2[2] = "-q";
                    cmdarr2[3] = pdfFile.getCanonicalPath();
                    cmdarr2[4] = xmlFile.getCanonicalPath();
                }

				process = new VKCProcess(cmdarr2, env, dir);
				process.executeAndWaitWithTimeout(timeout * 60);

				//XML-File korrigieren, da pdftohtml das .xml selbst anhängt
				String xmlFileName = xmlFile.getCanonicalPath();
				xmlFile.delete();
				xmlFile = new File(xmlFileName + ".xml");
				
				if (!debug) {
					xmlFile.deleteOnExit();
				}

				FileUtils.deleteZeroByteFile(xmlFile);

				if (xmlFile.exists() && enableTdf) {
					//TDL-Stream erzeugen
					xmlExtractor = new XmlExtractor();

					try {
						xmlExtractor.analyse(xmlFile.toURL().toString());
					} catch (MalformedURLException e) {
					}

					if (!debug) {
						xmlFile.delete();
					}
				}
			}
		} catch (IOException ioe) {
			if (tmpFile != null) {
				VKCLogManager.errorLog(this, "8", "Can't create temp-file: " + tmpFile.getPath(), ioe);
			} else {
				VKCLogManager.errorLog(this, "8", "Can't create temp-file: ", ioe);
			}

			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 (xmlExtractor != null && enableTdf) {
			byte[] tdfArray = xmlExtractor.getTdfArray();
			
			return new VKCInputStream(new ByteArrayInputStream(tdfArray), tdfArray.length);
		}

		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();
	}

	/**
	 * 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 (xmlExtractor != null) {
			return xmlExtractor.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
	}
}