package net.y3n20u.aeszip;

import static net.y3n20u.aeszip.CommonValues.FILE_NAME_SEPARATOR;
import static net.y3n20u.aeszip.CommonValues.ZIP_EXTENTION_WITH_PERIOD;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;


public class AesZipRecursiveEncrypter extends AesZipEncrypter {
	private FileFilter fileFilter;

	private URI baseURI;
	private String password;
	private File source;

	/**
	 * Constructs this object without its destination.
	 */
	public AesZipRecursiveEncrypter(File source, String password) {
		this(source, password, new File(source.getParent(), source.getName() + ZIP_EXTENTION_WITH_PERIOD));
	}

	/**
	 * Constructs this object with its destination stream.
	 * 
	 * @param destination
	 */
	public AesZipRecursiveEncrypter(File source, String password, OutputStream destination) {
		super(destination);
		setSourceAndPassword(source, password);
	}

	/**
	 * Constructs this object with its destination file.
	 * 
	 * @param destination
	 */
	public AesZipRecursiveEncrypter(File source, String password, File destination) {
		super(destination);
		setSourceAndPassword(source, password);
	}

	private void setSourceAndPassword(File source, String password) {
		if (source == null || password == null) {
			// TODO: more comprehensive message.
			throw new IllegalArgumentException(new NullPointerException());
		}
		this.source = source;
		this.password = password;
		this.baseURI = source.getParentFile().toURI();
	}

	public void setFileFilter(FileFilter fileter) {
		this.fileFilter = fileter;
	}

	private boolean checkFileFilter(File pathName) {
		if (fileFilter == null) {
			return true;
		}
		return fileFilter.accept(pathName);
	}

	@Override
	public void archive() throws IOException {
		this.archiveImplRecursive(source);
		super.archive();
	}

	private void archiveImplRecursive(File file) {
		if (!this.checkFileFilter(file)) {
			return;
		}
		String entryName = baseURI.relativize(file.toURI()).getPath();
		entryName += (file.isDirectory() && !entryName.endsWith(FILE_NAME_SEPARATOR)) ? FILE_NAME_SEPARATOR : "";
		this.add(entryName, file, password);

		if (file.isDirectory()) {
			for (File childFile : file.listFiles()) {
				this.archiveImplRecursive(childFile);
			}
		}
	}
}
