/*
 * $Id: MsWordDocConverter.java,v 1.24 2007/07/10 11:24:00 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: MsWordDocConverter.java,v $
 * Revision 1.24  2007/07/10 11:24:00  marbobo
 * + Bugfix: Dateiname die an ProcessKiller übergeben wird korrigiert
 *
 * Revision 1.23  2006/06/06 20:36:00  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.22  2006/04/18 11:40:19  korowa
 * Nur erlaubte Konvertierungen werden durchgeführt(DocConverter:conversions) bzw. zurückgeliefert.
 *
 * Revision 1.21  2005/04/18 12:22:48  lawern
 * Timeout in wscript-Aufruf eingebaut.
 *
 * Revision 1.20  2004/11/10 15:02:43  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.19  2004/08/31 14:15:49  lawern
 * ProcessKiller eingebaut
 *
 * Revision 1.18  2004/06/27 17:12:46  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.17  2003/11/29 22:13:52  koppy
 * InputStreams in VKCInputStream gekappselt
 *
 * Revision 1.16  2003/09/23 11:34:31  lawern
 * auf absolute Pfade umgestellt
 *
 * Revision 1.15  2003/09/11 08:27:22  lawern
 * einige Methoden public gemacht
 *
 * Revision 1.14  2003/07/21 10:38:21  lawern
 * Zurückgestellt auf RTFExtrector
 *
 * Revision 1.13  2003/07/08 16:39:44  lawern
 * wieder von RTF zurückgestellt, da RTF von Office XP nicht korrekt verarbeitet wird
 *
 * Revision 1.12  2003/07/01 11:33:14  lawern
 * Temporäre RTF-Datei wird jetzt gelöscht.
 *
 * Revision 1.11  2003/06/27 12:22:25  lawern
 * RTFExtractor eingebunden
 *
 * Revision 1.10  2003/06/10 14:50:45  lawern
 * Anpassung an Pfade mit Leerzeichen
 *
 * Revision 1.9  2003/06/10 13:08:14  lawern
 * Korrektur bei der Erzeugung der Zip-Dateien
 *
 * Revision 1.8  2003/06/06 10:57:21  lawern
 * Anpassungen an Retriever
 *
 * Revision 1.7  2003/04/10 11:32:04  lawern
 * Fehler beseitigt
 *
 * Revision 1.6  2003/04/02 10:34:52  bigmac
 * *** empty log message ***
 *
 * Revision 1.5  2003/03/20 09:11:33  lawern
 * Konverter und Analyse überarbeitet
 *
 * Revision 1.4  2003/03/12 14:40:57  lawern
 * Fehlerkorrektur
 *
 * Revision 1.3  2003/03/11 15:24:22  lawern
 * Fehlerkorrektur
 *
 * Revision 1.2  2003/03/07 13:05:04  lawern
 * Exception an JDK1.3 angepasst
 *
 * Revision 1.1  2003/03/07 11:55:48  lawern
 * initiale Version
 */
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.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import java.net.MalformedURLException;
import java.net.URL;

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

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

	public static String docSuffix = ".doc";

	private static Object semaphor = new Object();

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

	private String[] env = null;

	private File dir = null;

	private File zipFile = null;

	private String asciiFile = null;

	private File rtfFile = null;

	private String htmlFile = null;

	private File htmlDir = null;

	//private DocConverter htmlConverter = null;
	private RTFExtractor rtfExtractor = null;

	public MsWordDocConverter() {
	}

	/**
	 * 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("MsWordDocConverter: " + docFile);
		}

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

		dir = new File(basePath).getAbsoluteFile();
		
		if (enableHtml || enableTdf) {
			try {
				htmlDir = File.createTempFile("WordDoc", "");
				htmlDir.delete();
				htmlDir.mkdir();

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

				asciiFile = File.createTempFile("WordDoc", ".txt").getCanonicalPath();
				rtfFile = File.createTempFile("WordDoc", ".rtf");

				if (!debug) {
					(new File(asciiFile)).deleteOnExit();
					rtfFile.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
			try {
				cmdarr[0] = new File("wscript").toString();
				cmdarr[1] = "wordToHTML.vbs";
				cmdarr[2] = "//B";
				cmdarr[3] = "//T:" + (timeout * 60 - 5);
				cmdarr[4] = docFile.toString();
				cmdarr[5] = asciiFile;
				cmdarr[6] = htmlFile;
				cmdarr[7] = rtfFile.getCanonicalPath();
			} catch (IOException e1) {
			}

			//immer nur ein Word starten
			synchronized (semaphor) {
				String tmpFile = docFile.toString();
				tmpFile = tmpFile.substring(tmpFile.lastIndexOf(File.separator) + 1);

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

			FileUtils.deleteZeroByteFile(new File(asciiFile));
			FileUtils.deleteZeroByteFile(new File(htmlFile));
			FileUtils.deleteZeroByteFile(rtfFile);
		}
		
		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("WordDoc", ".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);
				}
			}
			//TDL-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!!!
			//            URL htmlFileUrl = null;
			//
			//            try {
			//                htmlFileUrl = (new File(htmlFile)).toURL();
			//            } catch (java.net.MalformedURLException mue) {
			//                System.out.println("Url stimmt nicht!");
			//            }
			//
			//            htmlConverter = createConverter(htmlFileUrl);
			//            htmlConverter.convert(htmlFileUrl, null);
			if (enableTdf) {
				rtfExtractor = new RTFExtractor();

				try {
					rtfExtractor.analyse(rtfFile.toURL().toString());
				} catch (MalformedURLException e) {
				}

				rtfFile.delete();

				//Html-Verzeichnis löschen
				try {
					FileUtils.deleteDirectory(htmlDir);
				} catch (Exception ex) {
					VKCLogManager.errorLog(this, "5", "Can't delete temp-dir.", ex);
				}
			}
		}
	}

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

			try {
				return new VKCInputStream(new BufferedInputStream(new FileInputStream(asciiFile)), asciiFile.length()) {
					public void close() throws IOException {
						super.close();
						closeAsciiStream();
					}
				};
			} catch (Exception e) {
				VKCLogManager.errorLog(this, "1", "Ascii-File not found: " + asciiFile, e);
			}
		}

		return null;
	}

	/**
	 * 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) {
		//            return htmlConverter.getTdfStream();
		//        }
		if (rtfExtractor != null && enableTdf) {
			byte[] tdfArray = rtfExtractor.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;
	}

	/**
	 * 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();
		//        }
		if (rtfExtractor != null) {
			return rtfExtractor.getTitle();
		}

		return null;
	}

	/**
	 * Liefert die Beschreibung des Dokuments zurück.
	 *
	 * @return Beschreibung des Dokuments oder <code>null</code>
	 */
	public String getDescription() {
		if (rtfExtractor != null) {
			return rtfExtractor.getDescription();
		}

		return null;
	}

	/**
	 * Liefert die Schlagwörter des Dokuments zurück.
	 *
	 * @return Schlagwörter des Dokuments oder <code>null</code>
	 */
	public String getKeyWords() {
		if (rtfExtractor != null) {
			return rtfExtractor.getKeyWords();
		}

		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();
		//        }
		if (rtfExtractor != null) {
			return rtfExtractor.getElements();
		}

		return null;
	}

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

		decOpenStreams();

		//Ascii-Datei löschen
		if (asciiFile != null) {
			new File(asciiFile).delete();
		}
	}

	/**
	 * 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 (asciiFile != null) {
			new File(asciiFile).delete();
		}

		if (zipFile != null) {
			zipFile.delete();
		}
		//this-Referenz wieder in die Queue einfügen
	}
}