/**
 *#########################################################################
 *
 * A component of the Gatherer application, part of the Greenstone digital
 * library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * <BR><BR>
 *
 * Author: John Thompson, Greenstone Digital Library, University of Waikato
 *
 * <BR><BR>
 *
 * Copyright (C) 1999 New Zealand Digital Library Project
 *
 * <BR><BR>
 *
 * 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.
 *
 * <BR><BR>
 *
 * 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.
 *
 * <BR><BR>
 *
 * 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.download;

import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import org.greenstone.gatherer.*;

/** This class provides access to the functionality of the WGet program, either by calling it via a shell script or by the JNI. It maintains a queue of pending jobs, and the component for showing these tasks to the user.
 * @author John Thompson, Greenstone Digital Library, University of Waikato
 * @version 2.3
 */
public class DownloadScrollPane
    extends Thread {
    
    /** <i>true</i> if there is a task currently being carried out, <i>false</i> otherwise. */
    private boolean busy = false;
    /** <i>true</i> if verbose debug messages should be displayed, <i>false</i> otherwise. */
    private boolean debug = false;
    /** <i>true</i> if successfully completed tasks should be automatically removed from the job queue. */
    private boolean remove_complete_jobs = true;

    private JPanel filler_pane = null;
    /** The panel that the task list will be shown in. */
    private JPanel list_pane;
    /** The job currently underway. */
    private DownloadJob job;
    /** A scroll pane which will be used to display the list of pending tasks. */
    private JScrollPane list_scroll;
    /** A queue of download tasks. */
    private Vector job_queue;
    static final private boolean simple = true;
    
    public DownloadScrollPane() {
	job = null;
	job_queue = new Vector();
	filler_pane = new JPanel();
	list_pane = new JPanel();
	list_pane.setLayout(new BoxLayout(list_pane, BoxLayout.Y_AXIS));
	list_scroll = new JScrollPane(list_pane);
    }

    public void deleteDownloadJob(DownloadJob delete_me) {
	if (delete_me == job) {
	    while(busy) {
	    }
	    job = null;
	}
	if (delete_me.hasSignalledStop()) {
	    list_pane.remove(delete_me.getProgressBar());
	    job_queue.remove(delete_me);
	    list_pane.remove(filler_pane);
	    if(job_queue.size() > 0) {
		Dimension progress_bar_size = delete_me.getProgressBar().getPreferredSize();
		Dimension list_pane_size = list_pane.getSize();
		int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
		progress_bar_size = null;
		if(height > 0) {
		    filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
		    list_pane.add(filler_pane);
		}
		list_pane_size = null;
	    }
	    list_pane.updateUI();
	}
	else {
	    DebugStream.println("Somehow we're trying to delete a job that is still running.");
	}
    }

    public synchronized void downloadComplete() {
	job.downloadComplete();
    }

    public synchronized void downloadFailed() {
	job.downloadFailed();
    }

    public synchronized void downloadWarning() {
	job.downloadWarning();
    }

    public JScrollPane getDownloadJobList() {
	return list_scroll;
    }

    public synchronized boolean hasSignalledStop() {
	return job.hasSignalledStop();
    }

    public void newDownloadJob(Download download, String mode, String proxy_url) {
	// Create the job and fill in the details from gatherer.config.

	DebugStream.println("About to create a new job");


        DownloadJob new_job = new DownloadJob(download, Configuration.proxy_pass, Configuration.proxy_user, this, mode, proxy_url);
	// Tell it to run as soon as possible

      

	new_job.setState(DownloadJob.RUNNING);
	
	// Add to job_queue job list.
	job_queue.add(new_job);

	// Now add it to the visual component, job list.

	list_pane.remove(filler_pane);

	Dimension progress_bar_size = new_job.getProgressBar().getPreferredSize();

	Dimension list_pane_size = list_pane.getSize();

	int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);

	progress_bar_size = null;

	list_pane.add(new_job.getProgressBar());

	if(height > 0) {
	    filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
	    list_pane.add(filler_pane);
	}

	list_pane_size = null;
	//list_pane.setAlignmentX(Component.LEFT_ALIGNMENT);
	list_pane.updateUI();
	new_job = null;
	synchronized(this) {
	    notify(); // Just incase its sleeping.
	}
    }
    
    public synchronized void updateProgress(long current, long expected) {
	job.updateProgress(current, expected);
    }
    
    /* There may be times when the download thread is sleeping, but the
     * user has indicated that a previously paused job should now begin
     * again. The flag within the job will change, so we tell the thread
     * to start again.
     */
    public void resumeThread() {
	synchronized(this) {
	    notify(); // Just incase its sleeping.
	}
    }
    
    public void run() {
	while(true) {
	    if(job_queue.size() > 0) {
		int index = 0;
		while(job_queue.size() > 0 && index < job_queue.size()) {
		    job = (DownloadJob) job_queue.get(index);
		    if(job.getState() == DownloadJob.RUNNING) {
			DebugStream.println("DownloadJob " + job.toString() + " Begun.");
			busy = true;
			job.callDownload();
			busy = false;
			DebugStream.println("DownloadJob " + job.toString() + " complete.");
			job = null;
		    }
		    index++;
		}
		try {
		    synchronized(this) {
			DebugStream.println("WGet thread is waiting for DownloadJobs.");
			wait();
		    }
		} catch (InterruptedException e) {
		    // Time to get going again.
		}
	    }
	    else {
		try {
		    synchronized(this) {
			DebugStream.println("WGet thread is waiting for DownloadJobs.");
			wait();
		    }
		} catch (InterruptedException e) {
		    // Time to get going again.
		}
	    }
	}
    }
}
