/*
 * ThreadedTaskPanel.java 29 sept. 2008
 *
 * Sweet Home 3D, Copyright (c) 2008 Emmanuel PUYBARET / eTeks <info@eteks.com>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package com.eteks.sweethome3d.swing;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.viewcontroller.ThreadedTaskController;
import com.eteks.sweethome3d.viewcontroller.ThreadedTaskView;
import com.eteks.sweethome3d.viewcontroller.View;

/**
 * A MVC view of a threaded task.
 * @author Emmanuel Puybaret
 */
public class ThreadedTaskPanel extends JPanel implements ThreadedTaskView {
  private final UserPreferences        preferences;
  private final ThreadedTaskController controller;
  private JLabel                       taskLabel;
  private JProgressBar                 taskProgressBar;
  private JDialog                      dialog;
  private boolean                      taskRunning;

  public ThreadedTaskPanel(String taskMessage,
                           UserPreferences preferences,
                           ThreadedTaskController controller) {
    super(new BorderLayout(5, (int)(5 * SwingTools.getResolutionScale())));
    this.preferences = preferences;
    this.controller = controller;
    createComponents(taskMessage);
    layoutComponents();
  }

  /**
   * Creates and initializes components.
   */
  private void createComponents(String taskMessage) {
    this.taskLabel = new JLabel(taskMessage);
    this.taskProgressBar = new JProgressBar();
    this.taskProgressBar.setIndeterminate(true);
  }

  /**
   * Layouts panel components in panel with their labels.
   */
  private void layoutComponents() {
    add(this.taskLabel, BorderLayout.NORTH);
    add(this.taskProgressBar, BorderLayout.SOUTH);
  }

  /**
   * Sets the status of the progress bar shown by this panel as indeterminate.
   * This method may be called from an other thread than EDT.
   */
  public void setIndeterminateProgress() {
    if (EventQueue.isDispatchThread()) {
      this.taskProgressBar.setIndeterminate(true);
    } else {
      // Ensure modifications are done in EDT
      invokeLater(new Runnable() {
          public void run() {
            setIndeterminateProgress();
          }
        });
    }
  }

  /**
   * Sets the current value of the progress bar shown by this panel.
   * This method may be called from an other thread than EDT.
   */
  public void setProgress(final int value,
                          final int minimum,
                          final int maximum) {
    if (EventQueue.isDispatchThread()) {
      this.taskProgressBar.setIndeterminate(false);
      this.taskProgressBar.setValue(value);
      this.taskProgressBar.setMinimum(minimum);
      this.taskProgressBar.setMaximum(maximum);
    } else {
      // Ensure modifications are done in EDT
      invokeLater(new Runnable() {
          public void run() {
            setProgress(value, minimum, maximum);
          }
        });
    }
  }

  /**
   * Executes <code>runnable</code> asynchronously in the Event Dispatch Thread.
   * Caution !!! This method may be called from an other thread than EDT.
   */
  public void invokeLater(Runnable runnable) {
    EventQueue.invokeLater(runnable);
  }

  /**
   * Sets the running status of the threaded task.
   * If <code>taskRunning</code> is <code>true</code>, a waiting dialog will be shown.
   */
  public void setTaskRunning(boolean taskRunning, View executingView) {
    this.taskRunning = taskRunning;
    if (taskRunning && this.dialog == null) {
      String dialogTitle = this.preferences.getLocalizedString(
          ThreadedTaskPanel.class, "threadedTask.title");
      final JButton cancelButton = new JButton(this.preferences.getLocalizedString(
          ThreadedTaskPanel.class, "cancelButton.text"));

      final JOptionPane optionPane = new JOptionPane(this, JOptionPane.PLAIN_MESSAGE,
          JOptionPane.DEFAULT_OPTION, null, new Object [] {cancelButton});
      cancelButton.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent ev) {
            optionPane.setValue(cancelButton);
          }
        });
      this.dialog = optionPane.createDialog(SwingUtilities.getRootPane((JComponent)executingView), dialogTitle);

      // Wait 200 ms before showing dialog to avoid displaying it
      // when the task doesn't last so long
      new Timer(200, new ActionListener() {
          public void actionPerformed(ActionEvent ev) {
            ((Timer)ev.getSource()).stop();
            if (controller.isTaskRunning()) {
              dialog.setVisible(true);

              dialog.dispose();
              if (ThreadedTaskPanel.this.taskRunning
                  && (cancelButton == optionPane.getValue()
                      || new Integer(JOptionPane.CLOSED_OPTION).equals(optionPane.getValue()))) {
                dialog = null;
                controller.cancelTask();
              }
            }
          }
        }).start();
    } else if (!taskRunning && this.dialog != null) {
      this.dialog.setVisible(false);
    }
  }
}
