package net.y3n20u.aeszip;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;

import org.junit.Test;
import org.omg.PortableInterceptor.SUCCESSFUL;

public class AesZipTest {

	private static final String FILE_NAME_ENCODING = "UTF-8";

	@Test
	public void testArchive1() {
		String password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword";
		
		String srcBase = "./test/resource/";
		String encFileName = "./test/resource/abctest.zip";
		String decBase = "./test/resource/out/";
		String suffix = "in/";
		
		File source = new File(srcBase + suffix);
		File encDestination = new File(encFileName);
		File decDestination = new File(decBase);
		File resultDestination = new File(decBase + suffix);
		
		FileUtil.deleteRecursive(encDestination);
		FileUtil.deleteRecursive(decDestination);

		try {
			AesZipRecursiveEncrypter enc = new AesZipRecursiveEncrypter(source, password, encDestination);
			enc.setFileNameCharset(Charset.forName(FILE_NAME_ENCODING));
			enc.archive();
			
			decDestination.mkdirs();
			AesZipDecrypter dec = new AesZipDecrypter(encDestination);
			for (String f: dec.getEntryNames()) {
				if (f.matches("svn")) {
					continue;
				}
				File dest = new File(decDestination, f);
				if (dec.getEntry(f).isDirectory()) {
					dest.getCanonicalFile().mkdir();
				}
				else {
					dec.decryptAndExtract(f, dest, password);
				}
			}
			assertTrue(FileUtil.compareFilesRecursive(source, resultDestination));
		} catch (Exception e) {
			e.printStackTrace();
			fail(e.getMessage());
		}
	}

	@Test
	public void testArchive2() {
		String password = "passwordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpassword";
		String wrongPwd = "passwordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpasswordpasswordpasswordpassowrdpassword";
		
		String[] sourceFiles = {"abc", "パリの写真.jpg", "abc/abc.txt", "abc/aiueo.txt", "abc/def"};
		
		String srcBase = "./test/resource/";
		String encFileName = "./test/resource/abctest.zip";
		String decBase = "./test/resource/out/";
		String suffix = "in/";
		
		File encDestination = new File(encFileName);
		File decDestination = new File(decBase);
		
		FileUtil.deleteRecursive(encDestination);
		FileUtil.deleteRecursive(decDestination);

		try {
			AesZipEncrypter enc = new AesZipEncrypter(encDestination);
			enc.setFileNameCharset(Charset.forName(FILE_NAME_ENCODING));
			for (String name: sourceFiles) {
				enc.add(name, new File(srcBase + suffix + name), password);
			}
			enc.archive();
			
			decDestination.mkdirs();
			AesZipDecrypter dec = new AesZipDecrypter(encDestination);
			for (String f: dec.getEntryNames()) {
				try {
					File dest = new File(decDestination, f);
					dec.decryptAndExtract(f, dest, wrongPwd);
					if (!dec.getEntry(f).isDirectory()) {
						// if the entry is not a directory, 'PasswordNotCorrectException' should occur.
						fail();
					}
				}
				catch (PasswordNotCorrectException pnce) {
					if (dec.getEntry(f).isDirectory()) {
						// if the entry is a directory, 'PasswordNotCorrectException' should not occur.
						fail();
					}
					pnce.printStackTrace();
				}
			}
			for (String name: sourceFiles) {
				System.out.println(name);
				File f = new File(decBase + name);
				assertTrue((f.isDirectory() && f.exists()) || (!f.isDirectory() && !f.exists()));
			}
		} catch (Exception e) {
			e.printStackTrace();
			fail(e.getMessage());
		}
	}

	/**
	 * test for OutputStreams. This test will check the streams not to be closed in some methods.
	 */
	@Test
	public void testArchive3() {
		String password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword";
		
		String srcBase = "./test/resource/";
		String encFileName = "./test/resource/abctest4.zip";
		String decBase = "./test/resource/out4/";
		String suffix = "in4/";
		
		File source = new File(srcBase + suffix);
		File encDestination = new File(encFileName);
		File decDestination = new File(decBase);
		File resultDestination = new File(decBase + suffix);
		
		FileUtil.deleteRecursive(encDestination);
		FileUtil.deleteRecursive(decDestination);
		
		FileOutputStream encDestinationStream = null;
		try {
			encDestinationStream = new FileOutputStream(encDestination);
			AesZipRecursiveEncrypter enc = new AesZipRecursiveEncrypter(source, password, encDestinationStream);
			enc.setFileNameCharset(Charset.forName(FILE_NAME_ENCODING));
			enc.archive();
			
			encDestinationStream.flush();
			try { // check if the stream has been already closed.
				encDestinationStream.write(0);
			}
			catch(IOException e) {
				e.printStackTrace();
				fail(e.getMessage());
			}
			encDestinationStream.close();
			
			decDestination.mkdirs();
			AesZipDecrypter dec = new AesZipDecrypter(encDestination);
			for (String f: dec.getEntryNames()) {
				System.out.println("start : " + f);
				if (f.matches("svn")) {
					continue;
				}
				File dest = new File(decDestination, f);
				if (!dest.getCanonicalFile().getParentFile().exists()) {
					dest.getCanonicalFile().getParentFile().mkdirs();
				}
				if (dec.getEntry(f).isDirectory()) {
					dest.getCanonicalFile().mkdirs();
					continue;
				}
				FileOutputStream decDestinationStream = new FileOutputStream(dest);
				try {
					dec.decryptAndExtract(f, decDestinationStream, password);
					try { // check if the stream has been already closed.
						decDestinationStream.write(0);
					}
					catch(IOException e) {
						e.printStackTrace();
						fail(e.getMessage());
					}
				}
				finally {
					if (decDestinationStream != null) {
						decDestinationStream.close();
					}
				}
				
			}
			//assertTrue(FileUtil.compareFilesRecursive(source, resultDestination));
		} catch (Exception e) {
			e.printStackTrace();
			fail(e.getMessage());
		}
		finally {
			if (encDestinationStream != null) {
				try {
					encDestinationStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
