/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2007, Geotools Project Managment Committee (PMC)
 *    (C) 2007, Geomatys
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation; either
 *    version 2.1 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
 *    Lesser General Public License for more details.
 */
package org.geotools.image.io.text;

import java.io.BufferedWriter;
import java.io.IOException;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageWriter;
import javax.imageio.ImageWriteParam;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.metadata.IIOMetadata;
import javax.media.jai.iterator.RectIter;

import org.geotools.image.ImageDimension;
import org.geotools.resources.Utilities;
import org.geotools.resources.i18n.Descriptions;
import org.geotools.resources.i18n.DescriptionKeys;


/**
 * An image encoder for matrix of floating-point numbers.
 *
 * @since 2.4
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/text/TextMatrixImageWriter.java $
 * @version $Id: TextMatrixImageWriter.java 27629 2007-10-26 09:59:20Z desruisseaux $
 * @author Martin Desruisseaux
 */
public class TextMatrixImageWriter extends TextImageWriter {
    /**
     * Amount of spaces to put between columns.
     */
    private static final int SEPARATOR_WIDTH = 1;

    /**
     * Constructs a new image writer.
     *
     * @param provider the provider that is invoking this constructor, or {@code null} if none.
     */
    protected TextMatrixImageWriter(final ImageWriterSpi provider) {
        super(provider);
    }

    /**
     * Appends a complete image stream containing a single image.
     *
     * @param streamMetadata The stream metadata (ignored in default implementation).
     * @param image The image or raster to be written.
     * @param parameters The write parameters, or null if the whole image will be written.
     */
    public void write(final IIOMetadata streamMetadata, final IIOImage image,
                      final ImageWriteParam parameters) throws IOException
    {
        processImageStarted();
        final BufferedWriter   out = getWriter(parameters);
        final String lineSeparator = getLineSeparator(parameters);
        final NumberFormat  format = createNumberFormat(image, parameters);
        final FieldPosition    pos = getExpectedFractionPosition(format);
        final int    fractionWidth = pos.getEndIndex() - pos.getBeginIndex();
        final int            width = pos.getEndIndex() + SEPARATOR_WIDTH;
        final StringBuffer  buffer = new StringBuffer(width);
        final RectIter    iterator = createRectIter(image, parameters);
        final ImageDimension  size = computeSize(image, parameters);
        final float  progressScale = 100f / size.getNumSampleValues();
        int numSampleValues = 0, nextProgress = 0;
        if (!iterator.finishedBands()) do {
            if (!iterator.finishedLines()) do {
                if (numSampleValues >= nextProgress) {
                    // Informs about progress only every 32 lines.
                    processImageProgress(progressScale * numSampleValues);
                    nextProgress = numSampleValues + 2000; // Reports after every 2000 numbers.
                }
                if (!iterator.finishedPixels()) do {
                    buffer.setLength(0);
                    String n = format.format(iterator.getSampleDouble(), buffer, pos).toString();
                    final int fractionOffset = Math.max(0, fractionWidth - (pos.getEndIndex() - pos.getBeginIndex()));
                    out.write(Utilities.spaces(width - n.length() - fractionOffset));
                    out.write(n);
                    out.write(Utilities.spaces(fractionOffset));
                } while (!iterator.nextPixelDone());
                out.write(lineSeparator);
                numSampleValues += size.width;
                iterator.startPixels();
            } while (!iterator.nextLineDone());
            out.write(lineSeparator); // Separate bands by a blank line.
            iterator.startLines();
        } while (!iterator.nextBandDone());
        out.flush();
        processImageComplete();
    }




    /**
     * Service provider interface (SPI) for {@link TextMatrixImageWriter}s.
     *
     * @since 2.4
     * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/text/TextMatrixImageWriter.java $
     * @version $Id: TextMatrixImageWriter.java 27629 2007-10-26 09:59:20Z desruisseaux $
     * @author Martin Desruisseaux
     */
    public static class Spi extends TextImageWriter.Spi {
        /**
         * The format names for the default {@link TextMatrixImageWriter} configuration.
         */
        private static final String[] NAMES = {"matrix"};

        /**
         * The mime types for the default {@link TextMatrixImageWriter} configuration.
         */
        private static final String[] MIME_TYPES = {"text/x-matrix"};

        /**
         * Constructs a default {@code TextMatrixImageWriter.Spi}. This constructor
         * provides the following defaults in addition to the defaults defined in the
         * {@linkplain TextImageWriter.Spi#Spi super-class constructor}:
         *
         * <ul>
         *   <li>{@link #names}           = {@code "matrix"}</li>
         *   <li>{@link #MIMETypes}       = {@code "text/x-matrix"}</li>
         *   <li>{@link #pluginClassName} = {@code "org.geotools.image.io.text.TextMatrixImageWriter"}</li>
         *   <li>{@link #vendorName}      = {@code "Geotools"}</li>
         * </ul>
         *
         * For efficienty reasons, the above fields are initialized to shared arrays. Subclasses
         * can assign new arrays, but should not modify the default array content.
         */
        public Spi() {
            names           = NAMES;
            MIMETypes       = MIME_TYPES;
            pluginClassName = "org.geotools.image.io.text.TextMatrixImageWriter";
            vendorName      = "Geotools";
            version         = "2.4";
        }

        /**
         * Returns a brief, human-readable description of this service provider
         * and its associated implementation. The resulting string should be
         * localized for the supplied locale, if possible.
         *
         * @param  locale A Locale for which the return value should be localized.
         * @return A String containing a description of this service provider.
         */
        public String getDescription(final Locale locale) {
            return Descriptions.getResources(locale).getString(DescriptionKeys.CODEC_MATRIX);
        }

        /**
         * Returns an instance of the {@code ImageWriter} implementation associated
         * with this service provider.
         *
         * @param  extension An optional extension object, which may be null.
         * @return An image writer instance.
         * @throws IOException if the attempt to instantiate the writer fails.
         */
        public ImageWriter createWriterInstance(final Object extension) throws IOException {
            return new TextMatrixImageWriter(this);
        }
    }
}
