/*
 * $Id: Ex4.java,v 1.1.1.1 2005/09/23 20:24:12 norman Exp $
 *
 * Copyright (c) 2005 by Brockmann Consult GmbH. All right reserved.
 * http://www.brockmann-consult.de
 */
package org.esa.beam.basics;

import org.esa.beam.framework.dataio.ProductIO;
import org.esa.beam.framework.dataio.ProductWriter;
import org.esa.beam.framework.datamodel.Band;
import org.esa.beam.framework.datamodel.Product;
import org.esa.beam.framework.datamodel.ProductData;
import org.esa.beam.util.logging.BeamLogManager;

import java.io.IOException;

/**
 * This exercise shows how to
 * <ol>
 * <li>obtain the input Product object from a file path</li>
 * <li>get two input bands reflec_7 and reflec_13</li>
 * <li>create a new output product object</li>
 * <li>create a new NDVI band and add it to the output product</li>
 * <li>write the product "skeleton" excluding pixel data in BEAM-DIMAP format</li>
 * <li>read pixel data from the two bands, compute NDVI pixel values, and write band data line-wise</li>
 * <li>get rid of the BEAM console logging</li>
 * </ol>
 */
public class Ex4 {
    /**
     * The program entry point.
     *
     * @param args must be of length 1. <code>args[0]</code> contains the file path to a MERIS Level-2 product
     */
    public static void main(String[] args) {
        // get rid of the console logging
        BeamLogManager.removeRootLoggerHandlers();

        // obtain the input Product object from a file path
        String inputFilePath = args[0];
        Product inputProduct = Ex1.readProduct(inputFilePath);

        int width = inputProduct.getSceneRasterWidth();
        int height = inputProduct.getSceneRasterHeight();

        // get two input bands reflec_7 and reflec_13
        Band lowerBand = getInputBand(inputProduct, "reflec_7");
        Band upperBand = getInputBand(inputProduct, "reflec_13");

        // create a new output product object
        Product outputProduct = new Product("product_ex4", "EX4", width, height);

        // create a new NDVI band and add it to the output product
        Band ndviBand = new Band("NDVI", ProductData.TYPE_FLOAT32, width, height);
        outputProduct.addBand(ndviBand);

        // write the product "skeleton" excluding pixel data in BEAM-DIMAP format
        String outputFilePath = "./" + outputProduct.getName() + ".dim";
        String outputFormatName = "BEAM-DIMAP";
        ProductWriter productWriter = ProductIO.getProductWriter(outputFormatName);
        outputProduct.setProductWriter(productWriter);
        try {
            productWriter.writeProductNodes(outputProduct, outputFilePath);
        } catch (IOException e) {
            System.err.printf("Error: failed to write product to %s: %s\n", outputFilePath, e.getMessage());
            System.exit(1);
        }

        // read pixel data from the two bands, compute NDVI pixel values, and write band data line-wise
        float[] lowerBandPixels = new float[width];
        float[] upperBandPixels = new float[width];
        float[] ndviPixels = new float[width];
        try {
            for (int y = 0; y < height; y++) {
                lowerBand.readPixels(0, y, width, 1, lowerBandPixels);
                upperBand.readPixels(0, y, width, 1, upperBandPixels);
                for (int x = 0; x < width; x++) {
                    // compute and assign the output pixel value (note the 'x' used as index)
                    ndviPixels[x] = computeNdviPixelValue(lowerBandPixels[x], upperBandPixels[x]);
                }
                ndviBand.writePixels(0, y, width, 1, ndviPixels);
            }
        } catch (IOException e) {
            System.err.printf("Error: failed to process pixel data: %s\n",
                              e.getMessage());
            System.exit(1);
        }

        // close product I/O and dispose the product objects
        inputProduct.dispose();
        outputProduct.dispose();
    }

    private static Band getInputBand(Product inputProduct, String bandName1) {
        Band upperBand = inputProduct.getBand(bandName1);
        if (upperBand == null) {
            System.err.printf("Error: band '%s' not found in product '%s'\n",
                              bandName1, inputProduct.getName());
            System.exit(1);
        }
        return upperBand;
    }

    private static float computeNdviPixelValue(float lower, float upper) {
        float ndvi = (upper - lower) / (upper + lower);
        if (ndvi < 0.0 || ndvi >= 0.8) {
            return -1; // invalid indicator
        }
        return ndvi;
    }
}

