/**
 *############################################################################
 * A component of the Greenstone Librarian Interface, part of the Greenstone
 * digital library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * Author: David Bainbridge, NZDL Project, University of Waikato, NZ
 *
 * Copyright (C) 2005 New Zealand Digital Library Project
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *############################################################################
 */

package org.greenstone.gatherer.remote;


import java.io.*;
import java.util.zip.*;


public class ZipTools
{
    static public void zipFiles(String zip_file_path, String base_directory_path, String[] relative_file_paths)
    {
	try {
	    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip_file_path));
	    ZipFilter null_zip_filter = new NullZipFilter();

	    // Add each file/directory in turn to the zip file
	    for (int i = 0; i < relative_file_paths.length; i++) {
		String relative_file_path = relative_file_paths[i];
		addFileToZip(zos, base_directory_path, relative_file_path, null_zip_filter);
	    }

	    zos.close();
	}
	catch (Exception exception) {
	    exception.printStackTrace();
	}
    }


    static public void addFileToZip(ZipOutputStream zos, String base_directory_path, String relative_file_path, ZipFilter zip_filter)
    {
	File file = new File(base_directory_path + File.separator + relative_file_path);

	// Check that the file/directory exists
	if (!file.exists()) {
	    System.err.println("File " + file + " does not exist!");
	    return;
	}

	try {
	    // Directory case
	    if (file.isDirectory()) {
		// Add a zip entry for this directory
		// Actually, don't -- this messes things up completely on Windows and doesn't seem to matter on Linux
		// zos.putNextEntry(new ZipEntry(relative_file_path + File.separator));

		// Apply recursively to each of the children of the directory
		File[] child_files = file.listFiles();
		for (int i = 0; i < child_files.length; i++) {
		    addFileToZip(zos, base_directory_path, relative_file_path + File.separator + child_files[i].getName(), zip_filter);
		}

		// empty directory. Java zips don't allow empty dirs, so need to put some dummy file in there
		if(child_files.length == 0) {
		    String rel_path = relative_file_path.replace('\\', '/') + File.separator + "empty";
		    System.err.println("Zipping empty dir requires dummy file: " + rel_path);
		    zos.putNextEntry(new ZipEntry(rel_path));
		}
	    }

	    // File case
	    else {
		// Add a zip entry for this file
		if (zip_filter.shouldIncludeFile(relative_file_path)) {
		    // Always use Unix style paths in zip files, even on Windows
		    zos.putNextEntry(new ZipEntry(relative_file_path.replace('\\', '/')));

		    if (zip_filter.shouldIncludeFileContent(relative_file_path)) {
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			zip_filter.filterFileContent(relative_file_path, bis, zos);
			bis.close();
		    }
		}
	    }
	}
	catch (Exception exception) {
	    exception.printStackTrace();
	}
    }


    public interface ZipFilter
    {
	public boolean shouldIncludeFile(String relative_file_path);

	public boolean shouldIncludeFileContent(String relative_file_path);

	public void filterFileContent(String relative_file_path, BufferedInputStream bis, ZipOutputStream zos);
    }


    static public class NullZipFilter
	implements ZipFilter
    {
	public boolean shouldIncludeFile(String relative_file_path)
	{
	    // All files are included
	    return true;
	}


	public boolean shouldIncludeFileContent(String relative_file_path)
	{
	    // Content for all files is included
	    return true;
	}


	public void filterFileContent(String relative_file_path, BufferedInputStream bis, ZipOutputStream zos)
	{
	    // No filtering: just read the file and write it directly out to zip
	    try {
		byte[] data = new byte[1024];
		int bytes_read;
		while ((bytes_read = bis.read(data, 0, 1024)) > -1) {
		    zos.write(data, 0, bytes_read);
		}
	    }
	    catch (Exception exception) {
		// We can't use DebugStream here
		exception.printStackTrace();
	    }
	}
    }
}
