/*
 * $Id$
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log$
 * Revision 1.4  2006/06/06 20:35:59  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.3  2006/04/04 07:53:40  korowa
 * Konvertierung ins PDF-Format hinzugefügt.Nur erlaubte Konvertierungen werden durchgeführt(DocConverter:conversions) bzw. zurückgeliefert.
 *
 * Revision 1.2  2006/03/23 11:36:41  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.1  2006/03/10 09:05:06  korowa
 * +PowerPoint Presentationen können jetzt von OpenOffice konvertiert werden
 *
 * Revision 1.5  2004/11/10 15:02:43  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.4  2004/06/27 17:12:47  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.3  2003/11/29 22:13:53  koppy
 * InputStreams in VKCInputStream gekappselt
 *
 * Revision 1.2  2003/09/11 08:27:24  lawern
 * einige Methoden public gemacht
 *
 * Revision 1.1  2003/07/28 11:52:50  lawern
 * initiale Version
 *
 *
 */
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.*;

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

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

	public static String docSuffix = ".ppt";

	private File zipFile = null;

	private File pdfFile = null;

	private String htmlFile = null;

	private File htmlDir = null;

	private HtmlDocConverter htmlConverter = null;

	public SoPowerPointDocConverter() {
	}

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

		InputStream docStream = null;
		File tmpFile = null;

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

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

			FileUtils.saveInputStream(tmpFile, docStream, true);
			FileUtils.closeInputStream(docStream);
		
			if (enableHtml || enableTdf) {//da TDF Stream aus HTML konvertiert wird 
				try {
					htmlDir = File.createTempFile("PowerPointDoc", "");
					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);
				}
			}
			
			//Dokument konvertieren
			if (enablePdf) {
				pdfFile = File.createTempFile("temp", ".pdf");
			}
			
			try {
				int formatsNumber = 0;
			
				if (enablePdf) {
					formatsNumber++;
				}
				
				if (enableHtml || enableTdf) {
					formatsNumber++;//da TDF Stream aus HTML konvertiert wird 
				}
				
				String[] convertTypes = new String[formatsNumber];
				int i = 0;
				
				if (enableHtml || enableTdf) {
					convertTypes[i] = "impress_html_Export";
					i++;
				}
				
				if (enablePdf) {
					convertTypes[i] = "impress_pdf_Export";
					i++;
				}

				i = 0;
				URL[] urls = new URL[formatsNumber];
				
				if (enableHtml || enableTdf) {
					urls[i] = new File(htmlFile).toURL();
					i++;
				}
				
				if (enablePdf) {
					urls[i] = pdfFile.toURL();
					i++;
				}

				new SOfficeDocConverter().convert(docFile, convertTypes, urls);
			} catch (IOException e1) {
				VKCLogManager.errorLog(this, "", e1.getMessage(), e1);
			}

			if (enableHtml || enableTdf) {
				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("PowerPointDoc", ".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!!!                      
				//alle text_.html-Dateien im HtmlVerzeichnis konvertieren
				if (enableTdf) {
					if (htmlDir != null) {
						File[] html_files = FileUtils.listFilesByPrefix(htmlDir, "text");
						Compare comparator = new Compare();
						Arrays.sort(html_files, comparator);
						
						if (html_files.length > 0) {
							Collection urls = new ArrayList(html_files.length);

							for (int i = 0; i < html_files.length; i++) {
								urls.add(html_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);
						}
					}
				}

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

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

	/*Problem: SOffice generierte Html werde wie folgt nummeriert: text0,text1,text2,...,text22
	 * ---> beim Einlesen falsche Reihenfolge der Dateien: text0, text1, text10, text11, text12...
	 * ---> muss sortiert werden 
	 * input 2 Strings von Type text_.html, mit _ = eine Zahl
	 */
	public class Compare implements Comparator {
		public int compare(Object arg0, Object arg1) {
			String name0 = arg0.toString();
			String name1 = arg1.toString();
			int startNum = name0.lastIndexOf("text") + 4;
			int endNum0 = name0.indexOf('.');
			int endNum1 = name1.indexOf('.');
			Integer a = Integer.valueOf(name0.substring(startNum, endNum0));
			Integer b = Integer.valueOf(name1.substring(startNum, endNum1));
			
			if (a.intValue() > b.intValue()) {
				return 1;
			}
			
			if (a.intValue() < b.intValue()) {
				return -1;
			}
			
			return 0;
		}
	}
}