/*
 * $Id: MsExcelDocConverter.java,v 1.16 2007/07/10 11:24:00 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: MsExcelDocConverter.java,v $
 * Revision 1.16  2007/07/10 11:24:00  marbobo
 * + Bugfix: Dateiname die an ProcessKiller übergeben wird korrigiert
 *
 * Revision 1.15  2006/06/06 20:35:59  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.14  2006/04/18 09:44:56  korowa
 * Nur erlaubte Konvertierungen werden durchgeführt(DocConverter:conversions) bzw. zurückgeliefert.
 *
 * Revision 1.13  2006/03/23 11:36:42  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.12  2005/07/28 06:15:22  lawern
 * .htm-Suffix in .html geändert, weil ansonsten nur die index.html gefunden wurde.
 *
 * Revision 1.11  2005/04/18 12:22:48  lawern
 * Timeout in wscript-Aufruf eingebaut.
 *
 * Revision 1.10  2004/11/10 15:02:43  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.9  2004/08/31 14:15:49  lawern
 * ProcessKiller eingebaut
 *
 * Revision 1.8  2004/06/27 17:12:46  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.7  2003/11/29 22:13:52  koppy
 * InputStreams in VKCInputStream gekappselt
 *
 * Revision 1.6  2003/11/11 08:50:58  lawern
 * Fehler behoben.
 *
 * Revision 1.5  2003/09/11 08:27:21  lawern
 * einige Methoden public gemacht
 *
 * Revision 1.4  2003/07/08 16:38:13  lawern
 * Anpassung an Office XP
 *
 * Revision 1.3  2003/06/26 15:15:21  lawern
 * XLS und PPT eingefügt und Konverter überarbeitet
 *
 */
package vkc.converter;

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;

import vkc.misc.ProcessKiller;
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 MsExcelDocConverter extends DocConverter {
	private static final boolean debug = false;

	public static String docSuffix = ".xls";

	private static Object semaphor = new Object();

	private String[] cmdarr = new String[6];

	private String[] env = null;

	private File dir = null;

	private File zipFile = null;

	private String htmlFile = null;

	private File htmlDir = null;

	private HtmlDocConverter htmlConverter = null;

	public MsExcelDocConverter() {
	}

	/**
	 * 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.
	 */
	//Html convertierung wird für den TDF-Stream benötigt
	public void convert(URL docFile, Collection conversions) {
		if (debug) {
			System.out.println("MsExcelDocConverter: " + docFile);
		}

		InputStream docStream = null;
		File tmpFile = null;

		try {
			//Datei von Url in temporäre Datei schreiben
			docStream = docFile.openStream();
			tmpFile = File.createTempFile("ExcelDoc", ".xls");

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

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

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

			dir = new File(basePath).getAbsoluteFile();
			
			if (enableHtml || enableTdf) {
				try {
					htmlDir = File.createTempFile("ExcelDoc", "");
					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
				cmdarr[0] = new File("wscript").toString();
				cmdarr[1] = "excelToHTML.vbs";
				cmdarr[2] = "//B";
				cmdarr[3] = "//T:" + (timeout * 60 - 5);
				cmdarr[4] = tmpFile.getCanonicalPath();
				cmdarr[5] = htmlFile;

				//immer nur ein Excel starten
				synchronized (semaphor) {
					String tempFile = tmpFile.getCanonicalPath();
					tempFile = tempFile.substring(tempFile.lastIndexOf(File.separator) + 1);

					ProcessKiller killer = new ProcessKiller(tempFile, timeout + 1);
					killer.start();
					process = new VKCProcess(cmdarr, env, dir);
					process.executeAndWaitWithTimeout(timeout * 60);
					killer.interrupt();
				}

				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 {
				if (enableHtml) {
					try {
						//Html-Version zusammenzipen
						zipFile = File.createTempFile("ExcelDoc", ".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);
					}
				}
				//TDF-Stream erzeugen
				//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) {
					File[] files = htmlDir.listFiles();
					File subDir = null;

					//Das von Excel erstellte Unterverzeichnis suchen
					for (int i = files.length - 1; i >= 0; i--) {
						if (files[i].isDirectory()) {
							subDir = files[i];
						}
					}

					//alle .html-Dateien im Unterverzeichnis konvertieren
					if (subDir != null) {
						files = FileUtils.listFilesBySuffix(subDir, ".html");

						if (files.length > 0) {
							Collection urls = new ArrayList(files.length);

							for (int i = 0; i < files.length; i++) {
								urls.add(files[i].toURL());
							}

							htmlConverter = new HtmlDocConverter();
							htmlConverter.convert(urls, null);
						} else {
							//Falls im Unterverzeichnis keine HTML-Dateien existieren
							//nur die Hauptdatei konvertieren
							htmlConverter = new HtmlDocConverter();
							htmlConverter.convert(new File(htmlFile).toURL(), null);
						}
					} else {
						//Falls kein Unterverzeichnis existiert nur die HTML-Datei
						//konvertieren
						htmlConverter = new HtmlDocConverter();
						htmlConverter.convert(new File(htmlFile).toURL(), null);
					}
				}
				//Html-Verzeichnis löschen
				try {
					FileUtils.deleteDirectory(htmlDir);
				} catch (Exception ex) {
					VKCLogManager.errorLog(this, "5", "Can't delete temp-dir.",
							ex);
				}
			}
		} 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 (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;
	}

	/**
	 * 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
	}
}