/**
   * Creates a set of HTML files (one for each size in {@link
   * GemIdentImageSets.ImageSetInterface.Size Size} with a global view (if the image set is a large
   * global image) where the thumbnails have colored borders where each cluster shares a common
   * color. After, each cluster's thumbnails are displayed without the global context. All
   * thumbnails link to the raw image.
   */
  private void CreateHTMLOutputAndOpen() {

    int tWidth = Thumbnails.tWidth / 2;
    int tHeight = Thumbnails.tHeight / 2;
    int numThumbPerRow = (int) Math.round(TableWidth / (double) tWidth);

    ArrayList<Set<String>> clusters = GetImageListsFromClusters();

    for (ImageSetInterface.Size size : ImageSetInterface.Size.values()) {
      int factor = 0;
      switch (size) {
        case XL:
          factor = 1;
          break;
        case L:
          factor = 2;
          break;
        case M:
          factor = 4;
          break;
        case S:
          factor = 8;
          break;
        case XS:
          factor = 16;
          break;
        case XXS:
          factor = 32;
          break;
      }

      PrintWriter out = null;
      try {
        out =
            new PrintWriter(
                new BufferedWriter(
                    new FileWriter(
                        Run.it.imageset.getFilenameWithHomePath(
                            Subsets + NumClusters + size + ".html"))));
      } catch (IOException e) {
        System.out.println(Subsets + NumClusters + ".html" + " cannot be created");
      }
      out.print("<HTML>");
      CreateHTMLHeader(out);
      if (!(Run.it.imageset instanceof NonGlobalImageSet))
        CreateHTMLForGlobal(out, factor, clusters, tWidth, tHeight);
      for (int c = 1; c <= NumClusters; c++)
        CreateHTMLCluster(out, clusters.get(c - 1), c, numThumbPerRow, tWidth, tHeight);
      out.print("</HTML>");
      out.close();
    }

    IOTools.RunProgramInOS(Subsets + NumClusters + "M.html");
  }
  /**
   * If the file containing the data information does exist, open the data from the {@link
   * #imageDataFile XML file}, otherwise, generate the data: first open the color information
   * ({@link StainMaker Mahalanobis Cubes}), then retrieve the list of project images ({@link
   * GemIdentTools.Thumbnails#GetImageList(String)}), then initialize data and the thread pool, then
   * thread a {@link ImageSetHeuristics.ImageInfoGatherer ImageInfoGatherer} to collect data for all
   * project images, and finally, it saves the data by serializing itself to the {@link
   * #imageDataFile XML file}. For discussion on the usefulness of this phenotype training helper,
   * consult section 3.2.3 of the manual.
   *
   * @see <a href="http://www.gemident.com/manual.html">the GemIdent manual</a>
   */
  public void run() {
    if (!IOTools.FileExists(imageDataFile)) {
      //			System.out.println("\nbegin image set heuristics");
      if (Run.it.imageset
          instanceof
          ImageSetInterfaceWithUserColors) { // this is ugly but conceptually it's the only way to
        // go I believe
        ((ImageSetInterfaceWithUserColors) Run.it.imageset).OpenMahalanobisCubes(null);
      }
      //			System.out.println("after Mahalanobis Cubes opened:"+Run.TimeElapsed(time_o)+"s");

      //			PrintFileHeader();
      String[] filenames = Thumbnails.GetImageList(Run.it.imageset.getHomedir());
      data = new HashMap<String, double[]>(filenames.length);

      postprocessPool = Executors.newFixedThreadPool(Run.it.num_threads);
      update = 100 / ((double) filenames.length);

      for (String filename : filenames) postprocessPool.execute(new ImageInfoGatherer(filename));
      postprocessPool.shutdown();
      try {
        postprocessPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // effectively infinity
      } catch (InterruptedException ignored) {
      }
      postprocessPool = null;

      IOTools.saveToXML(this, Run.it.imageset.getFilenameWithHomePath(imageDataFile));
      //			System.out.println("\nfinished image set heuristics\n\n\n\n");
    } else {
      progress.setVisible(false);
      ImageSetHeuristics open =
          (ImageSetHeuristics)
              IOTools.openFromXML(Run.it.imageset.getFilenameWithHomePath(imageDataFile));
      data = open.data;
    }
  }