package net.sf.jooreports.opendocument;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;


import org.apache.commons.io.IOUtils;

public class OpenDocumentIO {
	
	public static final Charset UTF_8 = Charset.forName("UTF-8");

	public static InputStreamReader toUtf8Reader(InputStream inputStream) {
		return new InputStreamReader(inputStream, UTF_8);
	}

	public static OutputStreamWriter toUtf8Writer(OutputStream outputStream) {
		return new OutputStreamWriter(outputStream, UTF_8);
	}

	public static OpenDocumentArchive readZip(InputStream inputStream) throws IOException {
		OpenDocumentArchive archive = new OpenDocumentArchive();
		ZipInputStream zipInputStream = new ZipInputStream(inputStream);
		while (true) {
			ZipEntry zipEntry = zipInputStream.getNextEntry();
			if (zipEntry == null) {
				break;
			}
			OutputStream entryOutputStream = archive.getEntryOutputStream(zipEntry.getName());
			IOUtils.copy(zipInputStream, entryOutputStream);
			entryOutputStream.close();
			zipInputStream.closeEntry();
		}
		zipInputStream.close();
		return archive;
	}

	public static OpenDocumentArchive readDirectory(File directory) throws IOException {
		if (!(directory.isDirectory() && directory.canRead())) {
			throw new IllegalArgumentException("not a readable directory: " + directory);
		}
		OpenDocumentArchive archive = new OpenDocumentArchive();
		readSubDirectory(directory, "", archive);
		return archive;
	}

	private static void readSubDirectory(File subDirectory, String parentName, OpenDocumentArchive archive) throws IOException {
		String[] fileNames = subDirectory.list();
		for (int i = 0; i < fileNames.length; i++) {
			File file = new File(subDirectory, fileNames[i]);
			String relativeName = parentName + fileNames[i];
			if (file.isDirectory()) {
				readSubDirectory(file, relativeName + "/", archive);
			} else {
				InputStream fileInputStream = new FileInputStream(file);
				OutputStream entryOutputStream = archive.getEntryOutputStream(relativeName);
				IOUtils.copy(fileInputStream, entryOutputStream);
				entryOutputStream.close();
				fileInputStream.close();
			}
		}
	}

	public static void writeZip(OpenDocumentArchive archive, OutputStream outputStream) throws IOException {
		ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
		Set entryNames = archive.getEntryNames();
		
		// OpenDocument spec requires 'mimetype' to be the first entry
		writeZipEntry(zipOutputStream, archive, "mimetype");
		
		for (Iterator it = entryNames.iterator(); it.hasNext();) {
			String entryName = (String) it.next();
			if (!"mimetype".equals(entryName)) {
				writeZipEntry(zipOutputStream, archive, entryName);
			}
		}
		zipOutputStream.close();
	}

	private static void writeZipEntry(ZipOutputStream zipOutputStream, OpenDocumentArchive archive, String entryName) throws IOException {
		ZipEntry zipEntry = new ZipEntry(entryName);
		zipOutputStream.putNextEntry(zipEntry);
		InputStream entryInputStream = archive.getEntryInputStream(entryName);
		IOUtils.copy(entryInputStream, zipOutputStream);
		entryInputStream.close();
		zipOutputStream.closeEntry();
	}
}

@@ -319,24 +319,52 @@
 a.util.Set;%0A
+import java.util.zip.CRC32;%0A
 import java.
@@ -2823,16 +2823,33 @@
 imetype%22
+, ZipEntry.STORED
 );%0A%09%09%0A%09%09
@@ -3038,24 +3038,43 @@
 e, entryName
+, ZipEntry.DEFLATED
 );%0A%09%09%09%7D%0A%09%09%7D%0A
@@ -3217,16 +3217,28 @@
 ntryName
+, int method
 ) throws
@@ -3420,82 +3420,467 @@
 ;%0A%09%09
-IOUtils.copy(entryInputStream, zipOutputStream);%0A%09%09entryInputStream.close(
+zipEntry.setMethod(method);%0A%09%09if (method == ZipEntry.STORED) %7B%0A%09%09%09byte%5B%5D inputBytes = IOUtils.toByteArray(entryInputStream);%0A%09%09%09CRC32 crc = new CRC32();%0A%09%09%09crc.update(inputBytes);%0A%09%09%09zipEntry.setCrc(crc.getValue());%0A%09%09%09zipEntry.setSize(inputBytes.length);%0A%09%09%09zipEntry.setCompressedSize(inputBytes.length);%0A%09%09%09IOUtils.write(inputBytes, zipOutputStream);%0A%09%09%7D else %7B%0A%09%09%09IOUtils.copy(entryInputStream, zipOutputStream);%0A%09%09%7D%0A%09%09IOUtils.closeQuietly(entryInputStream
 );%0A%09

fix compress method bug in mimetype entry of output ODF files