/**
 *#########################################################################
 *
 * A component of the Greenstone Librarian Interface application, part of 
 * the Greenstone digital library suite from the New Zealand Digital 
 * Library Project at the University of Waikato, New Zealand.
 *
 * Author: Michael Dewsnip, NZDL Project, University of Waikato
 *
 * 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.net.*;
import java.util.*;
import java.util.zip.*;
import javax.swing.*;
import java.io.ByteArrayOutputStream;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.FedoraInfo;
import org.greenstone.gatherer.GAuthenticator;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.collection.CollectionManager;
import org.greenstone.gatherer.feedback.Base64;
import org.greenstone.gatherer.shell.GShell;
import org.greenstone.gatherer.util.UnzipTools;
import org.greenstone.gatherer.util.Utility;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.*;
import org.apache.commons.httpclient.params.*;
import org.apache.commons.httpclient.HttpStatus;


// Code moved here from RemoteGreenstoneServer.java
// ----------------------------------------------------------------------------------------------------
//   ACTIONS
// ----------------------------------------------------------------------------------------------------
/** RemoteGreenstoneServer Actions that can go into the remote GS server's  ActionQueue.
 * Contains many package access inner classes that are Actions.   
*/
public abstract class RemoteGreenstoneServerAction
{
    public String action_output = null;
    public boolean processed = false;
    public boolean processed_successfully;
    
    protected RemoteGreenstoneServer remote = null;
    protected RemoteGreenstoneServer.ProgressBar progress_bar = null;

    public RemoteGreenstoneServerAction() {
	remote = Gatherer.remoteGreenstoneServer;
	progress_bar = remote.getProgressBar();
    }

    abstract public void perform()
	throws Exception;

    /*
      protected String sendCommandToServer(String gliserver_args, GShell shell) 
      throws Exception
      {
      return Gatherer.remoteGreenstoneServer.sendCommandToServer(gliserver_args, shell);
      }
      
      protected void setAction(String action) {
      Gatherer.remoteGreenstoneServer.progress_bar.setAction(action);
    }*/
    
    static class ActionCancelledException
	extends Exception
    {
    }

    /**
     * --------------------------------------------------------------------------------------------
     *    DELETE COLLECTION
     * --------------------------------------------------------------------------------------------
     */
    static class DeleteCollectionAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;

	public DeleteCollectionAction(String collection_name)
	{
	    this.collection_name = collection_name;
	}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Deleting collection " + collection_name + "...");

	    String delete_collection_command = "cmd=delete-collection";
	    delete_collection_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    action_output = remote.sendCommandToServer(delete_collection_command, null);
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    DELETE COLLECTION FILE
     * --------------------------------------------------------------------------------------------
     */
    static class DeleteCollectionFileAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File collection_file;

	public DeleteCollectionFileAction(String collection_name, File collection_file)
	{
	    this.collection_name = collection_name;
	    this.collection_file = collection_file;
	}

	public void perform()
	    throws Exception
	{
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String collection_file_relative_path = remote.getPathRelativeToDirectory(collection_file, collection_directory_path);
	    collection_file_relative_path = collection_file_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    progress_bar.setAction("Deleting collection file " + collection_file_relative_path + "...");

	    String delete_collection_file_command = "cmd=delete-collection-file";
	    delete_collection_file_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    delete_collection_file_command += "&file=" + Base64.encodeBytesInSingleLine(collection_file_relative_path.getBytes());
	    action_output = remote.sendCommandToServer(delete_collection_file_command, null);
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    DOWNLOAD COLLECTION
     * --------------------------------------------------------------------------------------------
     */
    static class DownloadCollectionAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;

	public DownloadCollectionAction(String collection_name)
	{
	    this.collection_name = collection_name;
	}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Downloading remote collection " + collection_name + "...");

	    String download_collection_command = "cmd=download-collection";
	    download_collection_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    download_collection_command += "&lr=" + remote.lang_region;
	    String zip_file_path = Gatherer.getCollectDirectoryPath() + collection_name + ".zip";
	    action_output = remote.downloadFile(download_collection_command, zip_file_path);

	    // Delete the existing (local) collection directory
	    Utility.delete(new File(CollectionManager.getCollectionDirectoryPath(collection_name)));

	    // Unzip the collection just downloaded
	    UnzipTools.unzipFile(zip_file_path, Gatherer.getCollectDirectoryPath());
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    DOWNLOAD COLLECTION ARCHIVES
     * --------------------------------------------------------------------------------------------
     */
    static class DownloadCollectionArchivesAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;

	public DownloadCollectionArchivesAction(String collection_name)
	{
	    this.collection_name = collection_name;
	}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Downloading collection archives for " + collection_name + "...");

	    String download_collection_archives_command = "cmd=download-collection-archives";
	    download_collection_archives_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    download_collection_archives_command += "&lr=" + remote.lang_region;
	    String zip_file_path = Gatherer.getCollectDirectoryPath() + collection_name + "-archives.zip";
	    action_output = remote.downloadFile(download_collection_archives_command, zip_file_path);

	    // Delete the existing (local) collection archives
	    Utility.delete(new File(CollectionManager.getLoadedCollectionArchivesDirectoryPath()));

	    // Unzip the collection archives just downloaded
	    UnzipTools.unzipFile(zip_file_path, Gatherer.getCollectDirectoryPath());
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    DOWNLOAD COLLECTION CONFIGURATIONS
     * --------------------------------------------------------------------------------------------
     */
    static class DownloadCollectionConfigurationsAction
	extends RemoteGreenstoneServerAction
    {
	public DownloadCollectionConfigurationsAction()
	{
	}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Downloading collection configurations...");

	    // Delete the existing (local) collect directory
	    Utility.delete(new File(Gatherer.getCollectDirectoryPath()));
	    new File(Gatherer.getCollectDirectoryPath()).mkdirs();

	    String download_collection_configurations_command = "cmd=download-collection-configurations";
	    download_collection_configurations_command += "&lr=" + remote.lang_region;
	    String zip_file_path = Gatherer.getCollectDirectoryPath() + "collections.zip";

	    // In the case of GS3, one of the causes the following may throw an exception is because
	    // there was no such site by the name stored in configRemote.xml under general.site_name
	    // from the previous client-gli connection session.
	    // The previous session may have connected to a different remote GS for instance,
	    // or it's a since deleted site.
	    // Need to handle this exception here if it happens the first time, else client-GLI will
	    // never open, but keep closing with the error msg that the collect directory within the
	    // unknown site does not exist, unless and until general.site_name's value is removed by
	    // hand from configRemote.xml.
	    try {
		action_output = remote.downloadFile(download_collection_configurations_command, zip_file_path);
		
	    } catch(Exception e) {
		if(!Gatherer.GS3) {
		    throw(e); // rethrow, as no site in GS2
		}
		
		if(e.getMessage().contains("Directory") && e.getMessage().contains("does not exist")) {
		    System.err.println("*** Warning: The stored GS3 site '" + Configuration.site_name
				       + "' from the previous session did not exist.");
		    System.err.println("    Swapping to known site and attempting to download"
				       + " its collection configurations.");
		    
		    // The result of cmd=get-site-names store by servlet_config before
		    // download-collection-configurations gets called.
		    ArrayList sites = Gatherer.servlet_config.getSites();
		    // Let's go with the first if there is one, else rethrow
		    if(sites.size() > 0) {

			// Use a known site and one of its servlets this time.
			String site = (String)sites.get(0);
			String servlet = (String)Gatherer.servlet_config.getServletsForSite(site).get(0);
			Configuration.setSiteAndServlet(site, servlet); // these values will into configRemote.xml

			// Now try downloading coll configurations again, for a known site this time
			action_output = remote.downloadFile(download_collection_configurations_command, zip_file_path);
			
		    }
		    else {
			throw(e);
		    }
		} else {
		    throw(e);
		}

	    }

	    // if we made it here, we downloaded the collection configs zip for an extant site
	    // and can continue.
	    // Unzip the collection configurations just downloaded
	    UnzipTools.unzipFile(zip_file_path, Gatherer.getCollectDirectoryPath());

	}
    }

     /**
     * --------------------------------------------------------------------------------------------
     *    DISCOVERING WHAT VERSION THE REMOTE GREENSTONE SERVER IS (2 or 3)
     * --------------------------------------------------------------------------------------------
     */

    static class VersionAction
	extends RemoteGreenstoneServerAction
    {
	public void perform()
	    throws Exception
	{
	    action_output = remote.sendCommandToServer("cmd=greenstone-server-version", null);
	}	
    }

    static class LibraryURLSuffixAction
	extends RemoteGreenstoneServerAction
    {
	public void perform()
	    throws Exception
	{
	    action_output = remote.sendCommandToServer("cmd=get-library-url-suffix", null);
	}	
    }
    
    /**
     * --------------------------------------------------------------------------------------------
     *    CHECKING IF A FILE/FOLDER EXISTS ON SERVER SIDE
     * --------------------------------------------------------------------------------------------
     */
    static class ExistsAction 
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File collection_file;
	
	public ExistsAction(String collection_name, File collection_file)
	{
	    this.collection_name = collection_name;
	    this.collection_file = collection_file;
	}
	
	public void perform()
	    throws Exception
	{
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String collection_file_relative_path = remote.getPathRelativeToDirectory(collection_file, collection_directory_path);
	    collection_file_relative_path = collection_file_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    File file = new File(collection_directory_path, collection_file_relative_path);

	    String file_exists_command = "cmd=file-exists";
	    file_exists_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    // base64 encode the filename to preserve special characters
	    file_exists_command += "&file=" + Base64.encodeBytesInSingleLine(collection_file_relative_path.getBytes());

	    // returns either "File <filename> exists" or "File <filename> does not exist"
	    // for the file/folder collection_file
	    action_output = remote.sendCommandToServer(file_exists_command, null);
	}	
    }
    

    /**
     * --------------------------------------------------------------------------------------------
     *    DOWNLOAD COLLECTION FILE
     * --------------------------------------------------------------------------------------------
     */
    static class DownloadCollectionFileAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File collection_file;

	public DownloadCollectionFileAction(String collection_name, File collection_file)
	{
	    this.collection_name = collection_name;
	    this.collection_file = collection_file;
	}

	public void perform()
	    throws Exception
	{
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String collection_file_relative_path = remote.getPathRelativeToDirectory(collection_file, collection_directory_path);
	    collection_file_relative_path = collection_file_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    progress_bar.setAction("Downloading collection file " + collection_file_relative_path + "...");

	    String download_collection_file_command = "cmd=download-collection-file";
	    download_collection_file_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    download_collection_file_command += "&file=" + URLEncoder.encode(collection_file_relative_path, "UTF-8");
	    download_collection_file_command += "&lr=" + remote.lang_region;

	    // String zip_file_name = collection_name + "-" + collection_file.getName() + ".zip";
	    // String zip_file_path = collection_directory_path + zip_file_name;	    
	    String zip_file_path = Gatherer.getCollectDirectoryPath() + collection_name + "-" + collection_file.getName() + ".zip"; // collect/(colgroup/)coltail/colfile.zip
	    action_output = remote.downloadFile(download_collection_file_command, zip_file_path);

	    // Unzip the collection file just downloaded
	    UnzipTools.unzipFile(zip_file_path, collection_directory_path);
	}
    }

    /**
     * --------------------------------------------------------------------------------------------
     *    DOWNLOAD web.xml FILE --for a remote GS3
     * --------------------------------------------------------------------------------------------
     */
    static class DownloadWebXMLFileAction
	extends RemoteGreenstoneServerAction
    {
	public DownloadWebXMLFileAction()
	{}

	public void perform()
	    throws Exception
	{
	    String web_xml_directory_path=(Configuration.gli_user_directory_path);
	    String download_web_xml_file_command = "cmd=download-web-xml-file";
	    download_web_xml_file_command += "&file=" + URLEncoder.encode("web.xml", "UTF-8");
	    download_web_xml_file_command += "&lr=" + remote.lang_region;
	    String zip_file_name = "web-xml.zip";
	    String zip_file_path = web_xml_directory_path + zip_file_name;
	    action_output = remote.downloadFile(download_web_xml_file_command, zip_file_path);

	    // Unzip the web.xml file just downloaded
	    UnzipTools.unzipFile(zip_file_path,web_xml_directory_path);
	}
    }

    /**
     * --------------------------------------------------------------------------------------------
     *    GET SCRIPT OPTIONS
     * --------------------------------------------------------------------------------------------
     */
    static class GetScriptOptionsAction
	extends RemoteGreenstoneServerAction
    {
	private String script_name;
	private String script_arguments;

	public GetScriptOptionsAction(String script_name, String script_arguments)
	{
	    this.script_name = script_name;
	    this.script_arguments = script_arguments;
		// classinfo.pl script  has a "collection" argument. Convert any colgroup/coltail to colgroup|coltail:
		// (Note that this may be the only method here that does not url encode the collection name before sendit it to the server)
		this.script_arguments = script_arguments.replace(File.separatorChar, '|'); 
	}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Getting options for " + script_name + "...");

	    String get_script_options_command = "cmd=get-script-options";
	    get_script_options_command += "&script=" + script_name;
	    get_script_options_command += "&xml=";
	    get_script_options_command += "&language=" + Configuration.getLanguage();
	    get_script_options_command += script_arguments;
	    action_output = remote.sendCommandToServer(get_script_options_command, null);
	}
    }

    /**
     * --------------------------------------------------------------------------------------------
     *    GET ALL NAMES OF SITES // for a remote GS3 
     * --------------------------------------------------------------------------------------------
     */
    static class GetSiteNamesAction
	extends RemoteGreenstoneServerAction
    {
	public GetSiteNamesAction()
	{}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Getting names of sites ...");

	    String get_script_options_command = "cmd=get-site-names";
	    action_output = remote.sendCommandToServer(get_script_options_command, null);
	}
    }

    /**
     * --------------------------------------------------------------------------------------------
     *    GET DEFAULT SERVLET PATH // for a remote GS3 
     * --------------------------------------------------------------------------------------------
     */
    static class GetDefaultServletPathAction
	extends RemoteGreenstoneServerAction
    {
	public GetDefaultServletPathAction()
	{}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Getting default servlet ...");

	    String get_script_options_command = "cmd=get-default-servlet-path";
	    action_output = remote.sendCommandToServer(get_script_options_command, null);
	}
    }

    /**
     * --------------------------------------------------------------------------------------------
     *    MOVE COLLECTION FILE
     * --------------------------------------------------------------------------------------------
     */
    static class MoveCollectionFileAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File source_collection_file;
	private File target_collection_file;

	public MoveCollectionFileAction(String collection_name, File source_collection_file, File target_collection_file)
	{
	    this.collection_name = collection_name;
	    this.source_collection_file = source_collection_file;
	    this.target_collection_file = target_collection_file;
	}

	public void perform()
	    throws Exception
	{
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String source_collection_file_relative_path = remote.getPathRelativeToDirectory(
                                                          source_collection_file, collection_directory_path);
	    source_collection_file_relative_path = source_collection_file_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    String target_collection_file_relative_path = remote.getPathRelativeToDirectory(
                                                          target_collection_file, collection_directory_path);
	    target_collection_file_relative_path = target_collection_file_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    progress_bar.setAction("Moving file " + source_collection_file_relative_path + " -> " + target_collection_file_relative_path + "...");

	    String move_collection_file_command = "cmd=move-collection-file";
	    move_collection_file_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    move_collection_file_command += "&source=" + Base64.encodeBytesInSingleLine(source_collection_file_relative_path.getBytes());
	    move_collection_file_command += "&target=" + Base64.encodeBytesInSingleLine(target_collection_file_relative_path.getBytes());
	    //move_collection_file_command += "&source=" + URLEncoder.encode(source_collection_file_relative_path, "UTF-8");
	    //move_collection_file_command += "&target=" + URLEncoder.encode(target_collection_file_relative_path, "UTF-8");
	    action_output = remote.sendCommandToServer(move_collection_file_command, null);
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    NEW COLLECTION DIRECTORY
     * --------------------------------------------------------------------------------------------
     */
    static class NewCollectionDirectoryAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File new_collection_directory;

	public NewCollectionDirectoryAction(String collection_name, File new_collection_directory)
	{
	    this.collection_name = collection_name;
	    this.new_collection_directory = new_collection_directory;
	}

	public void perform()
	    throws Exception
	{
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String new_collection_directory_relative_path = remote.getPathRelativeToDirectory(
                                                            new_collection_directory, collection_directory_path);
	    new_collection_directory_relative_path = new_collection_directory_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    progress_bar.setAction("Creating new directory " + new_collection_directory_relative_path + "...");

	    String new_collection_directory_command = "cmd=new-collection-directory";
	    new_collection_directory_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    new_collection_directory_command += "&directory=" + URLEncoder.encode(new_collection_directory_relative_path, "UTF-8");
	    action_output = remote.sendCommandToServer(new_collection_directory_command, null);
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    RUN SCRIPT
     * --------------------------------------------------------------------------------------------
     */
    static class RunScriptAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private String script_name;
	private String script_arguments;
	private GShell shell;

	public RunScriptAction(String collection_name, String script_name, String script_arguments, GShell shell)
	{
	    this.collection_name = collection_name;
	    this.script_name = script_name;
	    this.script_arguments = script_arguments;
	    this.shell = shell;
	}

	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Running " + script_name + "...");

	    String run_script_command = "cmd=run-script";
	    run_script_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    run_script_command += "&script=" + script_name;
	    run_script_command += "&language=" + Configuration.getLanguage();
	    run_script_command += script_arguments;
	    action_output = remote.sendCommandToServer(run_script_command, shell);
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    UPLOAD COLLECTION FILE
     * --------------------------------------------------------------------------------------------
     */
    static class UploadCollectionFilesAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File[] collection_files;


	public UploadCollectionFilesAction(String collection_name, File[] collection_files)
	{
	    this.collection_name = collection_name;
	    this.collection_files = collection_files;
	}


	public void perform()
	    throws Exception
	{
	    progress_bar.setAction("Uploading collection files...");

	    // Determine the file paths relative to the collection directory
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String[] collection_file_relative_paths = new String[collection_files.length];
	    for (int i = 0; i < collection_files.length; i++) {
		collection_file_relative_paths[i] = remote.getPathRelativeToDirectory(collection_files[i], collection_directory_path);
	    }

	    // Zip up the files to send to the server
	    //String zip_file_name = collection_name + "-" + System.currentTimeMillis() + ".zip";
            //String zip_file_path = collection_directory_path + zip_file_name;
	    String zip_file_path = collection_directory_path; // collect/(colgroup/)coltail/
	    String zip_file_name = new File(zip_file_path).getName() + "-" + System.currentTimeMillis() + ".zip"; // <collection_tail_name>-<time>.zip
	    zip_file_path += zip_file_name; // collect/(colgroup/)coltail/coltail-time.zip
	    ZipTools.zipFiles(zip_file_path, collection_directory_path, collection_file_relative_paths);
	    
	    // Upload the zip file
	    String upload_collection_file_command = "cmd=upload-collection-file";
	    upload_collection_file_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    upload_collection_file_command += "&file=" + URLEncoder.encode(zip_file_name, "UTF-8");
	    upload_collection_file_command += "&directory=";
	    upload_collection_file_command += "&zip=true";
	    upload_collection_file_command += "&lr=" + remote.lang_region;
	    action_output = remote.uploadFile(upload_collection_file_command, zip_file_path);
	}
    }


    /**
     * --------------------------------------------------------------------------------------------
     *    UPLOAD FILES INTO COLLECTION
     * --------------------------------------------------------------------------------------------
     */
    static class UploadFilesIntoCollectionAction
	extends RemoteGreenstoneServerAction
    {
	private String collection_name;
	private File[] source_files;
	private File target_collection_directory;


	public UploadFilesIntoCollectionAction(String collection_name, File[] source_files, File target_collection_directory)
	{
	    this.collection_name = collection_name;
	    this.source_files = source_files;
	    this.target_collection_directory = target_collection_directory;
	}


	public void perform()
	    throws Exception
	{
	    String collection_directory_path = CollectionManager.getCollectionDirectoryPath(collection_name);
	    String target_collection_directory_relative_path = remote.getPathRelativeToDirectory(
                                                               target_collection_directory, collection_directory_path);
	    target_collection_directory_relative_path = target_collection_directory_relative_path.replaceAll((Utility.isWindows() ? "\\\\" : "\\/"), "|");
	    progress_bar.setAction("Uploading files into collection...");
	   
	    //String zip_file_name = collection_name + "-" + System.currentTimeMillis() + ".zip";
	    //String zip_file_path = Gatherer.getCollectDirectoryPath() + zip_file_name;
	    String zip_file_path = Gatherer.getCollectDirectoryPath() 
		+ collection_name + "-" + System.currentTimeMillis() + ".zip"; // "collect/(colgroup/)collection_tail_name-<time>.zip"
	    String zip_file_name = new File(zip_file_path).getName(); // "collection_tail_name-<time>.zip"
	    DebugStream.println("Zip file path: " + zip_file_path);

	    String base_directory_path = source_files[0].getParentFile().getAbsolutePath();
	    DebugStream.println("Base directory path: " + base_directory_path);
	    String[] source_file_relative_paths = new String[source_files.length];
	    for (int i = 0; i < source_files.length; i++) {
		DebugStream.println("Source file path: " + source_files[i]);
		source_file_relative_paths[i] = remote.getPathRelativeToDirectory(source_files[i], base_directory_path);
	    }
	    
	    ZipTools.zipFiles(zip_file_path, base_directory_path, source_file_relative_paths);

	    String upload_collection_file_command = "cmd=upload-collection-file";
	    upload_collection_file_command += "&c=" + URLEncoder.encode(collection_name.replace(File.separatorChar, '|'), "UTF-8");
	    upload_collection_file_command += "&file=" + URLEncoder.encode(zip_file_name, "UTF-8");
	    upload_collection_file_command += "&directory=" + URLEncoder.encode(target_collection_directory_relative_path, "UTF-8");
	    upload_collection_file_command += "&zip=true";
	    upload_collection_file_command += "&lr=" + remote.lang_region;
	    action_output = remote.uploadFile(upload_collection_file_command, zip_file_path);
	}
    }
}
