/**
 *#########################################################################
 *
 * 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.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
//import org.greenstone.gatherer.collection.DownloadJob;
import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
import org.greenstone.gatherer.util.Utility;
import org.greenstone.gatherer.gui.*;

public class DownloadProgressBar
    extends JPanel 
    implements ActionListener {

    private boolean simple = false;

    private Dimension bar_size = new Dimension(520, 25);

    private Dimension MINIMUM_BUTTON_SIZE = new Dimension(100, 25);
    private  Dimension PROGRESS_BAR_SIZE = new Dimension(580,75);
    
    private int current_action;
    private int err_count;
    private int file_count;
    private int total_count;
    private int warning_count;

    private JLabel current_status;
    private JLabel main_status;
    private JLabel results_status;
	 
    private JPanel center_pane;
    private JPanel inner_pane;

    private JProgressBar progress;

    private long file_size;
    private long total_size;

    private String current_url;
    private String initial_url;

    private DownloadJob owner;

    public JButton stop_start_button;
    public JButton log_button;
    public JButton close_button;

    public DownloadProgressBar(DownloadJob owner, String initial_url, boolean simple) {
	this.owner = owner;
	this.current_url = null;
	this.err_count = 0;
	this.initial_url = initial_url;
	this.file_count = 0;
	this.file_size = 0;
	this.simple = simple;
	this.total_count = 0;
	this.total_size = 0;
	this.warning_count = 0;

	this.setLayout(new BorderLayout());
	this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));

	this.current_action = DownloadJob.STOPPED;

	inner_pane = new JPanel(new BorderLayout());
	inner_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));

	center_pane = new JPanel(new GridLayout(3,1));

	main_status = new JLabel();

	current_status = new JLabel();
		  
	results_status = new JLabel();

	progress = new JProgressBar();
	progress.setStringPainted(true);
	progress.setMinimum(0);
	progress.setMaximum(0);
	progress.setEnabled(false);
	progress.setString(Dictionary.get("Mirroring.DownloadJob.Waiting"));
	inner_pane.add(progress, BorderLayout.CENTER);

	center_pane.add(main_status);
	center_pane.add(current_status);
	center_pane.add(results_status);

	JPanel button_pane = new JPanel();

	stop_start_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Pause"),Dictionary.get("Mirroring.DownloadJob.Pause_Tooltip"));
	stop_start_button.addActionListener(this);
	stop_start_button.addActionListener(owner);
	stop_start_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
	stop_start_button.setMnemonic(KeyEvent.VK_P);
	stop_start_button.setEnabled(true);
	

	log_button = new GLIButton(Dictionary.get("Mirroring.DownloadJob.Log"),Dictionary.get("Mirroring.DownloadJob.Log_Tooltip"));
	log_button.addActionListener(owner);
	log_button.addActionListener(this);
	log_button.setEnabled(false);
	log_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
	log_button.setMnemonic(KeyEvent.VK_L);


	close_button =  new GLIButton(Dictionary.get("Mirroring.DownloadJob.Close"),Dictionary.get("Mirroring.DownloadJob.Close_Tooltip"));
	close_button.addActionListener(owner);
	close_button.addActionListener(this);
	close_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
	close_button.setMnemonic(KeyEvent.VK_C);
	close_button.setEnabled(true);


	// Layout - or at least some of it

	inner_pane.add(center_pane, BorderLayout.NORTH);

	button_pane.setLayout(new GridLayout(3,1));
	button_pane.add(stop_start_button);
	button_pane.add(log_button);
	button_pane.add(close_button);

	this.add(inner_pane, BorderLayout.CENTER);
	this.add(button_pane, BorderLayout.EAST);

	// Make the labels, etc update.
	refresh();
    }

    public void actionPerformed(ActionEvent event) {
	Object source = event.getSource();
	if(source == stop_start_button) {
	    // If we are running, stop.
	    if (current_action == DownloadJob.RUNNING) {
		current_action = DownloadJob.STOPPED;
                stop_start_button.setText(Dictionary.get("Mirroring.DownloadJob.Resume"));
                stop_start_button.setToolTipText(Dictionary.get("Mirroring.DownloadJob.Resume_Tooltip"));
	        
		progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Stopped"));
		progress.setIndeterminate(false);
	    } else {
		current_action = DownloadJob.RUNNING;
		// we are stopped, so restart
                stop_start_button.setText(Dictionary.get("Mirroring.DownloadJob.Pause"));
                stop_start_button.setToolTipText(Dictionary.get("Mirroring.DownloadJob.Pause_Tooltip"));
		progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Progress"));
		progress.setIndeterminate(true);
	    }
	}
	else if(source == close_button) {
	    // If we are running, stop.
	    if (current_action == DownloadJob.RUNNING) {
		current_action = DownloadJob.STOPPED;
             	progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Stopped"));
	
		progress.setIndeterminate(false);
	    }
	}
	else if(source == log_button) {
           
	    LogDialog dialog = new LogDialog(owner.getLogDocument());
	    dialog.setVisible(true);
	    dialog = null;
	}

	refresh();
    }

    /** This method is called when a new download is begun. The
     * details of the download are updated and a new JProgressBar
     * assigned to track the download.
     * @param url The url String of the file that is being downloaded.
     */
    public void addDownload(String url) {
	current_url = url;
	file_size = 0;
	refresh();
    }

    /** When the download of the current url is completed, this method
     * is called to enlighten the DownloadProgressBar of this fact.
     */
    public void downloadComplete() {
	current_url = null;
	file_count++;
	if(total_count < (file_count + err_count + warning_count)) {
	    total_count = (file_count + err_count + warning_count);
	}
	progress.setValue(progress.getMaximum());
	//Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Complete");
	refresh();
    }

    public void downloadFailed() {
	err_count++;
	if(total_count < (file_count + err_count + warning_count)) {
	    total_count = (file_count + err_count + warning_count);
	}
	refresh();
    }

    public void downloadWarning() {
	warning_count++;
	if(total_count < (file_count + err_count + warning_count)) {
	    total_count = (file_count + err_count + warning_count);
	}
	refresh();
    }

    public void setTotalDownload(int total_download) {
	total_count = total_download;
	refresh();
    }

    public Dimension getPreferredSize() {
	return PROGRESS_BAR_SIZE;
    }

    public void increaseFileCount() {
	file_count++;
	refresh();
    }

    public void increaseFileCount(int amount) {
	file_count += amount;
	refresh();
    }

    public void resetFileCount() {
	file_count = 0;
	refresh();
    }

    /** When a mirroring task is first initiated this function is called
     * to set initial values for the variables if necessary and to 
     * fiddle visual components such as the tool tip etc.
     * @param reset A Boolean specifying whether the variables should be
     * reset to zero.
     */
    public void mirrorBegun(boolean reset, boolean simple) {
	if(reset) {
	    this.file_count = 0;
	    this.file_size = 0;
	    this.total_count = 0;
	    this.total_size = 0;
	    this.err_count = 0;
	    this.warning_count = 0;
	}
	current_action = DownloadJob.RUNNING;
	stop_start_button.setEnabled(true);
	log_button.setEnabled(true);
	if(simple) {
	    progress.setIndeterminate(true);
	    progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Progress"));
	}
    }	

    /** Once a mirroring task is complete, is the DownloadJob returns from the
     * native call but the status is still running, then this method
     * is called to once again tinker with the pritty visual 
     * components.
     */
    public void mirrorComplete() {
	current_action = DownloadJob.COMPLETE;
	current_url = null;
	if(simple) {
	    progress.setIndeterminate(false);
	}
	progress.setValue(progress.getMaximum());
	progress.setString(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));

	stop_start_button.setEnabled(false);
	this.updateUI();
    }

    /** When called this method updates the DownloadProgressBar to reflect
     * the ammount of the current file downloaded.
     */
    public void updateProgress(long current, long expected) {
	file_size = file_size + current;
	if(!progress.isIndeterminate()) {
	    // If current is zero, then this is the 'precall' before the
	    // downloading actually starts.
	    if(current == 0) {
		// Remove the old progress bar, then deallocate it.
		inner_pane.remove(progress);
		progress = null;
		if(expected == 0) {
		    // We don't have a content length. This bar will go from 0 to 100 only!
		    progress = new JProgressBar(0, 100);
		}
		else {
		    // Assign a new progress bar of length expected content length.
		    progress = new JProgressBar(0, (new Long(expected)).intValue());
		}
		progress.setEnabled(true);
		// Add the new progress bar.
		inner_pane.add(progress, BorderLayout.CENTER);
		inner_pane.updateUI();
	    }
	    // Otherwise if expected is not zero move the progress bar and
	    // update percent complete.
	    else if (expected != 0) {
		progress.setValue((new Long(file_size)).intValue());
		int p_c = (new Double(progress.getPercentComplete() * 100)).intValue();
		progress.setString(p_c + "%");
		progress.setStringPainted(true);
	    }
	    // Finally, in the case we have no content length, we'll instead
	    // write the current number of bytes downloaded again.
	    else {
		progress.setString(file_size + " b");
		progress.setStringPainted(true);
	    }
	}
	refresh();
    }

    /** Causes the two labels associated with this DownloadProgressBar object to
     * update, thus reflecting the progression of the download. This 
     * method is called by any of the other public setter methods in this 
     * class.
     */
    private void refresh() {
	// Refresh the contents of main label.
	String args1[] = new String[1];
	args1[0] = initial_url.toString();
	main_status.setText(Dictionary.get("Mirroring.DownloadJob.Downloading", args1));

	if (current_url != null) {
	    // Refresh the current label contents.
	    String args2[] = new String[1];
	    args2[0] = current_url;
	    current_status.setText(Dictionary.get("Mirroring.DownloadJob.Downloading", args2));
	}
	else if (current_action == DownloadJob.STOPPED || current_action == DownloadJob.PAUSED) {
	    current_status.setText(Dictionary.get("Mirroring.DownloadJob.Waiting_User"));
	}
	else {
	    current_status.setText(Dictionary.get("Mirroring.DownloadJob.Download_Complete"));
	}

	// Refresh the contents of results label
	String args3[] = new String[4]; 
	args3[0] = file_count + "";
	args3[1] = total_count + "";
	args3[2] = warning_count + "";
	args3[3] = err_count + "";
	results_status.setText(Dictionary.get("Mirroring.DownloadJob.Status", args3));

	this.updateUI();
    }

    static final private Dimension DIALOG_SIZE = new Dimension(640,480);

    private class LogDialog
	extends JDialog {
	
	public LogDialog(AppendLineOnlyFileDocument document) {
	    super(Gatherer.g_man, Dictionary.get("Mirroring.DownloadJob.Log_Title"));
	    setSize(DIALOG_SIZE);
	    JPanel content_pane = (JPanel) getContentPane();
	    JTextArea text_area = new JTextArea(document);
	    JButton button = new GLIButton(Dictionary.get("General.Close"));
	    // Connection
	    button.addActionListener(new CloseActionListener());
	    // Layout
	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
	    content_pane.setLayout(new BorderLayout());
	    content_pane.add(new JScrollPane(text_area), BorderLayout.CENTER);
	    content_pane.add(button, BorderLayout.SOUTH);
	}

	private class CloseActionListener
	    implements ActionListener {
	    public void actionPerformed(ActionEvent event) {
		LogDialog.this.dispose();
	    }
	}
    }
}
