/**
   * This main method is used for testing. It starts ImageJ, loads a test image and starts the
   * plugin.
   *
   * <p>User interaction is necessary, as the plugin uses a GUI.
   *
   * <p><a href=
   * "https://github.com/imagej/minimal-ij1-plugin/blob/master/src/main/java/Process_Pixels.java"
   * >see minimal-ij1-plugin on GitHub</a>
   *
   * @param args
   */
  public static void main(final String[] args) {
    EFTEMj_Debug.setDebugLevel(EFTEMj_Debug.DEBUG_FULL);
    /*
     * start ImageJ
     */
    new ImageJ();

    String baseFolder = "C:/Temp/";
    final String os = System.getProperty("os.name").toLowerCase();
    if (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0 || os.indexOf("aix") > 0) {
      final String userHome = System.getProperty("user.home");
      baseFolder = userHome + "/Downloads/";
    }

    /*
     * Check if the test image is available. Otherwise prompt a message with
     * the download link.
     */
    final File testImage =
        new File(baseFolder + "20140106 SM125 -20%/20140106_SR-EELS_TestImage_small.tif");
    if (!testImage.exists()) {
      final String url = "http://eftemj.entrup.com.de/SR-EELS_TestImage.zip";
      /*
       * IJ.showMessage("Test image not found", "<html>" +
       * "Please download the file" + "<br />" + "<a href='" + url +
       * "'>SR-EELS_TestImage.zip</a> from" + "<br/>" + url + "<br />" +
       * "and extract it to 'C:\\temp\\'." + "</html>");
       */
      final GenericDialog gd = new GenericDialog("Test image not found");
      gd.addMessage(
          "Please download the file 'SR-EELS_TestImage.zip' and extract it to '"
              + baseFolder
              + "'.");
      gd.addMessage("Copy the following link, or click Ok to open it with your default browser.");
      gd.addStringField("", url, url.length());
      gd.showDialog();
      if (gd.wasOKed()) {
        try {
          final URI link = new URI(url);
          final Desktop desktop = Desktop.getDesktop();
          desktop.browse(link);
        } catch (final Exception exc) {
          IJ.showMessage("An Exception occured", exc.getMessage());
          return;
        }
      }
      return;
    }
    /*
     * open the test image
     */
    final ImagePlus image =
        IJ.openImage(baseFolder + "20140106 SM125 -20%/20140106_SR-EELS_TestImage_small.tif");
    image.show();

    /*
     * run the plugin
     */
    final Class<?> clazz = SR_EELS_CorrectionPlugin.class;
    IJ.runPlugIn(clazz.getName(), "");
  }
  /*
   * (non-Javadoc)
   *
   * @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
   */
  @Override
  public void run(final ImageProcessor ip) {
    /*
     * Each correction contains of implementations of the abstract classes
     * CoordinateCorrector and a IntensityCorrector that can be can be
     * combined as you want.
     *
     * By using getFunctionWidth() and getFunctionBorders() the
     * characterisation results are loaded and an implementation of the
     * Levenberg–Marquardt algorithm (LMA) is used to fit functions to the
     * discrete values.
     */
    IJ.showStatus("Preparing correction...");
    importer = new DataImporter(pathResults, false);
    final SR_EELS_Polynomial_2D widthFunction = getFunctionWidth();
    inputProcessor.setWidthFunction(widthFunction);
    final SR_EELS_Polynomial_2D borderFunction = getFunctionBorders();
    inputProcessor.setBorderFunction(borderFunction);
    /*
     * TODO: Add the used correction methods to the image title.
     */
    outputProcessor = widthFunction.createOutputImage();
    outputImage = new ImagePlus(title + "_corrected", outputProcessor);
    final Calibration cal = new Calibration(inputImp);
    cal.pixelHeight = widthFunction.getPixelHeight();
    outputImage.setCalibration(cal);
    final CoordinateCorrector coordinateCorrection =
        new FullCoordinateCorrection(inputProcessor, outputProcessor);
    final IntensityCorrector intensityCorrection =
        new SimpleIntensityCorrection(inputProcessor, coordinateCorrection);
    /*
     * Each line of the image is a step that is visualise by the progress
     * bar of ImageJ.
     */
    setupProgress(outputProcessor.getHeight());
    if (EFTEMj_Debug.getDebugLevel() == EFTEMj_Debug.DEBUG_FULL) {
      for (int x2 = 0; x2 < outputProcessor.getHeight(); x2++) {
        for (int x1 = 0; x1 < outputProcessor.getWidth(); x1++) {
          final float intensity = intensityCorrection.getIntensity(x1, x2);
          outputProcessor.setf(x1, x2, intensity);
        }
        updateProgress();
      }
    } else {
      /*
       * The ExecutorService is used to handle the multithreading. see
       * http://www.vogella.com/tutorials/JavaConcurrency/article.html#
       * threadpools
       */
      final ExecutorService executorService =
          Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
      for (int x2 = 0; x2 < outputProcessor.getHeight(); x2++) {
        final int x2Temp = x2;
        executorService.execute(
            new Runnable() {

              @Override
              public void run() {
                for (int x1 = 0; x1 < outputProcessor.getWidth(); x1++) {
                  final float intensity = intensityCorrection.getIntensity(x1, x2Temp);
                  outputProcessor.setf(x1, x2Temp, intensity);
                }
                updateProgress();
              }
            });
      }
      executorService.shutdown();
      try {
        executorService.awaitTermination(30, TimeUnit.MINUTES);
      } catch (final InterruptedException e) {
        e.printStackTrace();
      }
    }
  }