package com.srbenoit.microscopy;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.logging.Level;
import javax.media.MediaLocator;
import com.srbenoit.filter.AbstractFilter;
import com.srbenoit.filter.FilterException;
import com.srbenoit.filter.FilterInput;
import com.srbenoit.filter.FilterTreeExecutor;
import com.srbenoit.filter.Pipe;
import com.srbenoit.filter.items.ImageArrayPipeItem;
import com.srbenoit.media.movie.MakeMovie;
import com.srbenoit.media.movie.MovieMakingException;

/**
 * A filter that generates QuickTime movies for each X series in an image array.
 */
public class QuicktimeBuilderFilter extends AbstractFilter {

    /** version number for serialization */
    private static final long serialVersionUID = 9105886485480586659L;

    /**
     * Constructs a new <code>QuicktimeBuilderFilter</code>.
     */
    public QuicktimeBuilderFilter() {

        super("QuickTime Builder", QuicktimeBuilderFilter.class.getName());

        this.inputs.add(new FilterInput(ImageArrayPipeItem.class, "Movie frames"));
        makeRenderer();
    }

    /**
     * Duplicates the filter including all of its settings, but returns an independent object.
     *
     * @return  the duplicated object
     */
    @Override public AbstractFilter duplicate() {

        return new QuicktimeBuilderFilter();
    }

    /**
     * Performs the filter operation.
     *
     * @param   executor  the <code>FilterTreeExecutor</code> that is executing the filter
     * @param   pipe      a pipe containing the input data items
     * @throws  FilterException  if the filter cannot complete
     */
    @Override public void filter(final FilterTreeExecutor executor, final Pipe pipe)
        throws FilterException {

        ImageArrayPipeItem images;

        validateInputs(pipe);
        executor.indicateProgress(1);

        images = (ImageArrayPipeItem) pipe.get(this.inputs.get(0).getKey());
        executor.indicateProgress(2);

        runFilter(executor, pipe, images);

        // No need to save - we don't add anything to the pipe

        executor.indicateProgress(100);
    }

    /**
     * Runs the filter, reading the source Metamorph TIF files and extracting an array of images,
     * the first dimension of which is time, and the second dimension of which is z plane.
     *
     * @param  executor  the <code>FilterTreeExecutor</code> that is executing the filter
     * @param  pipe      a pipe containing the input data items
     * @param  images    the images to process
     */
    private void runFilter(final FilterTreeExecutor executor, final Pipe pipe,
        final ImageArrayPipeItem images) {

        int numMovies;
        int numFrames;
        BufferedImage[] frames;
        int count;
        File file;
        MediaLocator loc;
        MakeMovie maker;

        numFrames = images.getXSize();
        numMovies = images.getYSize();
        maker = new MakeMovie();

        frames = new BufferedImage[numFrames];

        for (int i = 0; i < numMovies; i++) {

            if (executor.isCancelled()) {
                break;
            }

            executor.indicateProgress(5 + (i * 70 / numMovies));
            count = 0;

            for (int j = 0; j < numFrames; j++) {
                frames[j] = images.getImage(j, i);

                if (frames[j] == null) {
                    break;
                }

                count++;
            }

            if (numMovies > 1) {
                file = new File(pipe.getDir(), // NOPMD SRB
                        this.getInputFormat(0).getKey() + "_movie_plane_" + (i + 1) + ".mov");
            } else {
                file = new File(pipe.getDir(), // NOPMD SRB
                        this.getInputFormat(0).getKey() + "_movie.mov");
            }

            loc = MakeMovie.createMediaLocator("file:" + file.getAbsolutePath());

            if (count > 0) {

                try {
                    maker.doItBuffered(frames[0].getWidth(), frames[0].getHeight(), count, frames,
                        loc);
                } catch (MovieMakingException ex) {
                    LOG.log(Level.WARNING, "Exception creating movie", ex);
                }
            }
        }
    }

    /**
     * Generates the string representation of the filter.
     *
     * @return  the string representation
     */
    @Override public String toString() {

        return "QuicTimeBuilderFilter";
    }
}
