//
// LociForm.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.data.bio;

import java.awt.Image;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.rmi.RemoteException;
import java.net.URL;
import java.util.Hashtable;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;
import loci.formats.*;
import loci.formats.gui.GUITools;
import visad.*;
import visad.data.*;
import visad.java2d.DisplayImplJ2D;
import visad.util.*;

/**
 * LociForm is the VisAD data adapter for images handled by the Bio-Formats
 * package (loci.formats). It works by wrapping a loci.formats.IFormatReader
 * and/or loci.formats.IFormatWriter object.
 */
public class LociForm extends Form implements FormBlockReader,
  FormFileInformer, FormProgressInformer, MetadataReader
{

  // -- Static fields --

  private static int formCount = 0;


  // -- Fields --

  /** Reader to use for open-related functions. */
  protected IFormatReader reader;

  /** Writer to use for save-related functions. */
  protected IFormatWriter writer;

  /** Percent complete for current operation. */
  protected double percent;

  /** File filters for reader formats. */
  protected FileFilter[] rFilters;

  /** File filters for writer formats. */
  protected FileFilter[] wFilters;


  // -- Constructor --

  /** Constructs a new LociForm that handles anything from loci.formats. */
  public LociForm() {
    this(new ImageReader(), new ImageWriter());
  }

  /** Constructs a new LociForm that handles the given reader. */
  public LociForm(IFormatReader reader) {
    this(reader, null);
  }

  /** Constructs a new LociForm that handles the given writer. */
  public LociForm(IFormatWriter writer) {
    this(null, writer);
  }

  /** Constructs a new LociForm that handles the given reader/writer pair. */
  public LociForm(IFormatReader reader, IFormatWriter writer) {
    super("LociForm" + formCount++);
    this.reader = reader;
    this.writer = writer;
  }


  // -- LociForm API methods --

  /** Gets the IFormatReader backing this form's reading capabilities. */
  public IFormatReader getReader() { return reader; }

  /** Gets the IFormatWriter backing this form's writing capabilities. */
  public IFormatWriter getWriter() { return writer; }

  /** Sets the frames per second to use when writing files. */
  public void setFrameRate(int fps) {
    if (writer == null) return;
    writer.setFramesPerSecond(fps);
  }

  /**
   * A utility method for test reading a file from the command line,
   * and displaying the results in a simple display.
   */
  public void testRead(String[] args) throws VisADException, IOException {
    if (reader == null) return;
    String className = getClass().getName();
    String format = reader.getFormat();
    if (args == null || args.length < 1) {
      System.out.println("To test read a file in " + format + " format, run:");
      System.out.println("  java " + className + " in_file");
      return;
    }
    String id = args[0];

    // check type
    System.out.print("Checking " + format + " format ");
    System.out.println(isThisType(id) ? "[yes]" : "[no]");

    // read pixels
    System.out.print("Reading " + id + " pixel data ");
    Data data = open(args[0]);
    System.out.println("[done]");
    System.out.println("MathType =\n" + data.getType());

    // extract types
    FunctionType ftype = (FunctionType) data.getType();
    RealTupleType domain = ftype.getDomain();
    RealType[] xy = domain.getRealComponents();
    RealType time = null;
    if (xy.length == 1) {
      // assume multiple images over time
      time = xy[0];
      ftype = (FunctionType) ftype.getRange();
      domain = ftype.getDomain();
      xy = domain.getRealComponents();
    }
    MathType range = ftype.getRange();
    RealType[] values = range instanceof RealType ?
      new RealType[] {(RealType) range} :
      ((RealTupleType) range).getRealComponents();

    // configure display
    DisplayImpl display = new DisplayImplJ2D("display");
    ScalarMap timeMap = null;
    if (time != null) {
      timeMap = new ScalarMap(time, Display.Animation);
      display.addMap(timeMap);
    }
    display.addMap(new ScalarMap(xy[0], Display.XAxis));
    display.addMap(new ScalarMap(xy[1], Display.YAxis));
    ScalarMap colorMap = null;
    if (values.length == 2 || values.length == 3) {
      // do separate mappings to Red, Green and Blue
      display.addMap(new ScalarMap(values[0], Display.Red));
      display.addMap(new ScalarMap(values[1], Display.Green));
      if (values.length == 3) {
        display.addMap(new ScalarMap(values[2], Display.Blue));
      }
    }
    else {
      // use the first component only
      colorMap = new ScalarMap(values[0], Display.RGB);
      display.addMap(colorMap);
    }
    DataReferenceImpl ref = new DataReferenceImpl("ref");
    ref.setData(data);
    display.addReference(ref);
    display.getGraphicsModeControl().setScaleEnable(true);

    // pop up frame
    JFrame frame = new JFrame(format + " Results");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JPanel p = new JPanel();
    frame.setContentPane(p);
    p.setLayout(new BorderLayout());
    p.add(display.getComponent());
    if (timeMap != null) {
      AnimationWidget aw = new AnimationWidget(timeMap);
      p.add(BorderLayout.SOUTH, aw);
    }
    if (colorMap != null) {
      RangeWidget rw = new RangeWidget(colorMap);
      LabeledColorWidget lcw = new LabeledColorWidget(colorMap);
      p.add(BorderLayout.NORTH, rw);
      p.add(BorderLayout.EAST, lcw);
    }
    frame.pack();
    frame.setLocation(300, 300);
    frame.setVisible(true);
  }

  /** Gets file filters for use with formats supported for reading. */
  public FileFilter[] getReaderFilters() {
    if (reader == null) return null;
    if (rFilters == null) rFilters = GUITools.buildFileFilters(reader);
    return rFilters;
  }

  /** Gets file filters for use with formats supported for writing. */
  public FileFilter[] getWriterFilters() {
    if (writer == null) return null;
    if (wFilters == null) wFilters = GUITools.buildFileFilters(writer);
    return wFilters;
  }


  // -- FormNode API methods --

  /**
   * Opens an existing image file from the given filename.
   *
   * @return VisAD Data object containing image data
   */
  public DataImpl open(String id)
    throws BadFormException, IOException, VisADException
  {
    percent = 0;
    int nImages = getBlockCount(id);
    FieldImpl[] fields = new FieldImpl[nImages];
    for (int i=0; i 

Ads help maintain this website.