package de.visone.nlpext.gui;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;

import de.visone.nlpext.util.Timer;

/**
 * Dialog displaying the progress of a process and its subprocesses.
 * 
 * @author <a href="mailto:endele@inf.uni-konstanz.de">Simon Endele</a>
 * @see de.visone.nlpext.gui.event.ProgressListener
 */
@SuppressWarnings("serial")
public class ProgressDialog extends JDialog implements ActionListener {
	private static final String EST_REMAIN_TIME = "estimated remaining time";
	private static final String FILE_PATTERN = "creating network from file \"%s\"...";
	private static final String CANCEL = "cancel";
	/** parameter for creating a window containing two progress bars. */
	public static final int STYLE_TWO_BARS = 0;
	/**
	 * parameter for creating a window containing a single indeterminate
	 * progress bar.
	 */
	public static final int STYLE_INDETERMINATE = 1;

	private static final int GAP = 5; // place between components
	private static final int PROGRESS_BAR_HEIGHT = 14; // height of progress
	// bars in pixels

	private JLabel fileLabel;
	public JLabel singleProgressLabel;
	public JLabel totalProgressLabel;
	private JLabel timeLabel;
	public JProgressBar singleProgressBar;
	public JProgressBar totalProgressBar;
	private JButton cancelButton;
	private Timer timer;
	private boolean isCanceled = false;

	public JProgressBar indeterminateProgressBar;

	public ProgressDialog(final Frame owner, final String title) {
		super(owner, false);
		setTitle(title);

	}

	/**
	 * Creates a window with the specified style.
	 * 
	 * @param owner
	 *            Frame this dialog will be modal to
	 * @param title
	 *            title of the dialog window
	 * @param thread
	 *            Thread which will be run while this dialog is opened
	 * @param style
	 *            one of <code>STYLE_TWO_BARS</code>,
	 *            <code>STYLE_INDETERMINATE</code>
	 */
	public ProgressDialog(final Frame owner, final String title, final int style) {
		this(owner, title);
		switch (style) {
		case STYLE_TWO_BARS:
			initTwo();
			break;
		case STYLE_INDETERMINATE:
			initOne();
			break;
		}
		setLocationRelativeTo(owner);
		timer = new Timer(true);
	}

	/** Initializes the window components. */
	private void initTwo() {
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(final WindowEvent e) {
				cancel();
			}
		});
		getContentPane().setLayout(new GridBagLayout());
		final GridBagConstraints c = new GridBagConstraints();
		c.insets = new Insets(GAP, GAP, GAP, GAP); // (top, left, bottom, right)

		fileLabel = new JLabel();
		singleProgressLabel = new JLabel(" ");
		totalProgressLabel = new JLabel(" ");
		singleProgressBar = createProgressBar();
		totalProgressBar = createProgressBar();
		timeLabel = new JLabel();
		cancelButton = new JButton(CANCEL);
		cancelButton.addActionListener(this);

		c.anchor = GridBagConstraints.WEST;
		c.insets.bottom = 0;
		c.weightx = 1.0;
		c.gridy = 1;
		getContentPane().add(singleProgressLabel, c);
		c.gridy = 3;
		getContentPane().add(totalProgressLabel, c);
		c.insets.bottom = GAP;
		c.gridy = 0;
		getContentPane().add(fileLabel, c);
		c.gridy = 5;
		getContentPane().add(timeLabel, c);
		c.anchor = GridBagConstraints.CENTER;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridy = 2;
		getContentPane().add(singleProgressBar, c);
		c.gridy = 4;
		getContentPane().add(totalProgressBar, c);
		c.fill = GridBagConstraints.NONE;
		c.gridy = 6;
		getContentPane().add(cancelButton, c);

		setFilename("example.txt");
		setRemainingTime(-1);

		pack();
		// cancelButton.paintImmediately(cancelButton.getVisibleRect());
		// setResizable(false);
	}

	private void initOne() {
		final JOptionPane pane = new JOptionPane(
				"loading parser. please wait...",
				JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION);

		// pane.setLayout(new GridBagLayout());
		// System.out.println(pane.getLayout());

		final GridBagConstraints c = new GridBagConstraints();
		c.insets = new Insets(GAP, GAP, GAP, GAP); // (top, left, bottom, right)
		c.anchor = GridBagConstraints.CENTER;

		// JLabel descriptionLabel = new JLabel();
		indeterminateProgressBar = new JProgressBar();
		indeterminateProgressBar.setPreferredSize(new Dimension(300,
				PROGRESS_BAR_HEIGHT));
		// indeterminateProgressBar.setIndeterminate(true);

		// indeterminateProgressBar.paintImmediately(indeterminateProgressBar.getVisibleRect());

		// c.gridy = 0; getContentPane().add(descriptionLabel, c);
		// c.gridy = 1;
		pane.add(indeterminateProgressBar/* , c */);
		getContentPane().add(pane);

		/*
		 * pane.setUI(new OptionPaneUI() { public boolean
		 * containsCustomComponents(JOptionPane op) { return true; } public void
		 * selectInitialValue(JOptionPane op) {
		 * 
		 * } } );
		 */

		pack();
		setResizable(false);
	}

	/*
	 * private void initOne() { getContentPane().setLayout(new GridBagLayout());
	 * 
	 * JComponent pane = JOptionPane("Blub", JOptionPane.INFORMATION_MESSAGE,
	 * JOptionPane.CANCEL_OPTION); getContentPane().add(pane);
	 * 
	 * GridBagConstraints c = new GridBagConstraints(); c.insets = new
	 * Insets(GAP, GAP, GAP, GAP); //(top, left, bottom, right) c.anchor =
	 * GridBagConstraints.CENTER;
	 * 
	 * //JLabel descriptionLabel = new JLabel(); indeterminateProgressBar = new
	 * JProgressBar(); indeterminateProgressBar.setPreferredSize(new
	 * Dimension(300, PROGRESS_BAR_HEIGHT));
	 * indeterminateProgressBar.setIndeterminate(true);
	 * 
	 * //c.gridy = 0; getContentPane().add(descriptionLabel, c); c.gridy = 1;
	 * getContentPane().add(indeterminateProgressBar, c);
	 * 
	 * pack(); setResizable(false); }
	 */

	private JProgressBar createProgressBar() {
		final JProgressBar pb = new JProgressBar();
		// pb.setPreferredSize(new Dimension(400, PROGRESS_BAR_HEIGHT));
		return pb;
	}

	@Override
	public void actionPerformed(final ActionEvent e) {
		if (e.getSource() == cancelButton) {
			cancel();
		}
	}

	private void cancel() {
		// System.out.println("ProgressDialog: exit");
		// setVisible(false);
		fileLabel.setText("Breaking up process..."); // ///////////////////////////////////////
		isCanceled = true;
	}

	public boolean isCanceled() {
		return isCanceled;
	}

	// ========== set-methods for ProgressBars, Labels ==========

	/** Sets the name of the file currently processed. */
	public void setFilename(final String filename) {
		fileLabel.setText(String.format(FILE_PATTERN, filename));
		// singleProgressBar.setString(String.format(getString("filePattern"),
		// filename));
	}

	/**
	 * Sets the remaining time. If <code>seconds</code> is less than 0 some kind
	 * of unknown time symbols will be displayed.
	 */
	public void setRemainingTime(final int seconds) {
		final String time = seconds < 0 ? "-" : String.format("%02d:%02d:%02d",
				seconds / 3600, seconds % 3600 / 60, seconds % 60);
		timeLabel.setText(EST_REMAIN_TIME + ": " + time);
	}

	/**
	 * Set the label text for the progress of a single element. E.g.
	 * "Parsing sentence x of y...".
	 */
	public void setSingleProgressLabelText(final String text) {
		singleProgressLabel.setText(text);
	}

	/**
	 * Set the label text for the total progress. E.g. "Parsing file x of y...".
	 */
	public void setTotalProgressLabelText(final String text) {
		totalProgressLabel.setText(text);
		// totalProgressLabel
		// .paintImmediately(totalProgressLabel.getVisibleRect());
	}

	/**
	 * Sets the progress of the upper ProgressBar for the progress of a single
	 * element.
	 * 
	 * @param progress
	 *            progress of the current element, should be greater or equal
	 *            0.0 and less or equal 1.0.
	 */
	public void setSingleProgress(final double progress) {
		setProgress(singleProgressBar, progress);
	}

	/**
	 * Sets the progress of the lower ProgressBar for the total progress.
	 * 
	 * @param progress
	 *            total progress, should be greater or equal 0.0 and less or
	 *            equal 1.0.
	 */
	public void setTotalProgress(final double progress) {
		setProgress(totalProgressBar, progress);
		setRemainingTime((int) (timer.getElapsedTime() / (1000 * progress) * (1.0 - progress)));
	}

	/** Sets the progress for a specified progress bar. */
	private void setProgress(final JProgressBar progressBar, double progress) {
		progress = Math.min(1.0, progress);
		progress = Math.max(0.0, progress);
		final int min = progressBar.getMinimum();
		final int max = progressBar.getMaximum();
		final int value = min + (int) ((max - min) * progress);
		progressBar.setValue(value);
	}

	/*
	 * public static void main(String[] args) { int i =
	 * Integer.parseInt(args[0]);
	 * System.out.println("Remaining time: "+String.format("%02d:%02d:%02d",
	 * i/3600, (i%3600/60), i%60)); }
	 */
}
