/////////////////////////////////////////////////////////////////////////
//
// © University of Southampton IT Innovation Centre, 2004
//
// Copyright in this library belongs to the IT Innovation Centre of
// 2 Venture Road, Chilworth Science Park, Southampton, SO16 7NP, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created by:             P. Melas
//      Created date:           21-10-03
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

package uk.ac.soton.itinnovation.gemss.utils.zip;

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

public class ZipUtils{


  /**
   * Takes a file directory a recursively stores the files and directories it contains in a zip file. Option is provided to create zip file with or without relative paths to all files
   * @param dirName Directory to be zipped
   * @param withPath Flag to direct storage of relative path names
   * @return Zip file
   */
  public static void compress(String zipFile,String dirName, boolean withPath) throws ZipException {

    File file = new File(zipFile);
    FileOutputStream fos;
    ZipOutputStream zos;
    try {
      // Create the file output streams for both the file and the zip.
      // These object variables had to be declared globally outside main.
      fos = new FileOutputStream(file);
      zos = new ZipOutputStream(fos);
      String rootDir = dirName;

      if(rootDir.endsWith(File.separator)){
        rootDir = rootDir.substring(0,(rootDir.length()-1));

        int foo = rootDir.lastIndexOf(File.separator);
        rootDir = rootDir.substring(0, foo);

      }
      else{
        int foo = rootDir.lastIndexOf(File.separator);
        if(foo!=-1)
            rootDir = rootDir.substring(0, foo);
        else
            rootDir = "";

      }

      dirFunc(dirName,rootDir,withPath,zos);


      // Close the file output streams for both the file and the zip.
      zos.flush();
      zos.close();
      fos.close();
    } catch (IOException e) {
    } // end try


  }

  /**
   *
   * @param dirName name of current directory
   */
  private static void dirFunc(String dirName,String rootDir, boolean withPath,ZipOutputStream zos) throws ZipException {
    File dirObj = new File (dirName);
    if (dirObj.exists() == true) {
      if (dirObj.isDirectory() == true) {
        // Create an array of File objects, one for each file or directory in dirObj.
        File [] fileList = dirObj.listFiles();
        // Loop through File
        for (int i = 0; i < fileList.length; i++) {
          if (fileList[i].isDirectory()) {
            dirFunc (fileList[i].getPath(),rootDir,withPath,zos);
          } else if (fileList[i].isFile()) {
            // Call the zipFunc function
            //zipFunc(fileList[i].getPath());
            zipFunc(rootDir,fileList[i],withPath,zos);
          }
        } // for loop
      }

    }
  }

  /**
   *
   * @param file Name of current file
   */
  private static void zipFunc(String rootDir,File file,boolean withPath,ZipOutputStream zos) throws ZipException {
    try{
        String fileName = file.getName();
        String filePath = file.getPath();
        String relPath = null;
        if(filePath.startsWith(rootDir)){
            int root_length = rootDir.length() +1;
            relPath = filePath.substring(root_length);
        }

        if(relPath != null){


            // Create a file input stream and a buffered input stream.
            FileInputStream fis = new FileInputStream(filePath);
            BufferedInputStream bis = new BufferedInputStream(fis);

            // Create a Zip Entry and put it into the archive (no data yet).
            ZipEntry fileEntry = null;
            if(withPath){
                fileEntry = new ZipEntry(relPath);
            }
            else{
                fileEntry = new ZipEntry(fileName);
            }
            zos.putNextEntry(fileEntry);

            // Create a byte array object named data and declare byte count variable.
            byte[] data = new byte[1024];
            int byteCount;
            // Create a loop that reads from the buffered input stream and writes
            // to the zip output stream until the bis has been entirely read.
            while ((byteCount = bis.read(data, 0, 1024)) > -1) {
                zos.write(data, 0, byteCount);
            }


        }
        else{
            throw new ZipException("Have a null relative path");
        }
    }
    catch(Exception ex) {
        throw new ZipException(ex.getMessage());
    }
  }
}
