CSIP_NASS_GeoTIFF.java [src/java/methods] Revision: default  Date:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package methods;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier;
import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
import csip.SessionLogger;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import lamps.CSIP_Const;
import lamps.utils.Partition;
import methods.objects.ERU;
import methods.objects.Nass_accurcies;
import methods.objects.Nass_area_reclassify;
import methods.objects.Nass_results;
import org.geotools.coverage.grid.GridCoordinates2D;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
import org.geotools.coverage.processing.operation.Crop;
import org.geotools.data.DataStore;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.factory.Hints;
import org.geotools.feature.FeatureCollection;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.gce.geotiff.GeoTiffWriteParams;
import org.geotools.gce.geotiff.GeoTiffWriter;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

/**
 *
 * @author hokipka
 */
public class CSIP_NASS_GeoTIFF {

    public static boolean Chop_all_raster_irrigation_data(File dataDir, File outputDir, List<Geometry> envelope, PrintWriter w_log) throws MalformedURLException, IllegalArgumentException, IOException {

        boolean back = true;

        //getting a format
        final GeoTiffFormat format = new GeoTiffFormat();

        //getting the write parameters
        final GeoTiffWriteParams wp = new GeoTiffWriteParams();

        //setting compression to LZW
        wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
        wp.setCompressionType("LZW");
        wp.setCompressionQuality(0.75F);

        //setting the tile size to 256X256
        wp.setTilingMode(GeoToolsWriteParams.MODE_EXPLICIT);
        wp.setTiling(256, 256);

        //setting the write parameters for this geotiff
        final ParameterValueGroup params = format.getWriteParameters();
        params.parameter(AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString()).setValue(wp);

        Crop ImageCrop = new Crop();
        //ZonalStats Zonal = new ZonalStats();

        ParameterValueGroup CropParameterValueGroup = ImageCrop.getParameters();

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        File[] geotiff = {new File(dataDir, CSIP_Const.Irrigation2002), new File(dataDir, CSIP_Const.Irrigation2007), new File(dataDir, CSIP_Const.Irrigation2012), new File(dataDir, CSIP_Const.Irrigation2017)};

        LinearRing lr = null;
        double min_size = 1500;

        Geometry targetGeometry = envelope.get(0);

        int irri_year = 2;

        for (File geotiff1 : geotiff) {

            GridCoverage2DReader reader = new GeoTiffReader(geotiff1.toURI().toURL(), new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));
            GridCoverage2D gcsaga = (GridCoverage2D) reader.read(null);

            AffineTransform gridToCRS_gcsaga = (AffineTransform) gcsaga.getGridGeometry().getGridToCRS2D();
            double cs = org.geotools.referencing.operation.matrix.XAffineTransform.getScaleX0(gridToCRS_gcsaga);

            CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem();
            reader.dispose();
            Hints hints = new Hints();
            hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);

            if (!targetGeometry.isValid()) {
                targetGeometry = targetGeometry.convexHull();
            }
            int last_coo = targetGeometry.getCoordinates().length - 1;
            if (!targetGeometry.getCoordinates()[0].equals(targetGeometry.getCoordinates()[last_coo])) {
                targetGeometry = targetGeometry.convexHull();
            }
            lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
            if (!lr.isValid()) {
                targetGeometry = targetGeometry.convexHull();
                lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
            }
            Polygon crop_poly = new Polygon(lr, null, geometryFactory);
            crop_poly = (Polygon) crop_poly.buffer(1000);

            if (cs > 30) {
                min_size = 4000;
            }
            if (cs < 50) {
                min_size = 2000;
            }
            if (crop_poly.getArea() < min_size) {
                int bb = 1;
                while (crop_poly.getArea() < min_size) {
                    crop_poly = (Polygon) crop_poly.buffer(bb++);
                }
            }

            Polygon simpleP = (Polygon) TopologyPreservingSimplifier.simplify(crop_poly, 1);
            CropParameterValueGroup.parameter("Source").setValue(gcsaga);
            CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
            boolean success = false;
            double sizer = 1000;
            try {
                GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                success = true;
                throw new Exception();
            } catch (Exception e) {

            } finally {
                if (!success) {
                    while (!success) {
                        crop_poly = (Polygon) crop_poly.buffer(sizer);
                        sizer = sizer + 1000;
                        simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 1);
                        CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                        try {
                            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                            success = true;
                            throw new Exception();
                        } catch (Exception e) {
                        } finally {

                        }
                    }
                    crop_poly = (Polygon) crop_poly.buffer(sizer);
                    simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 1);
                    CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                }
            }

            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);

            GridCoverageWriter writer = null;
            final File writeFile = new File(outputDir, "irri" + irri_year + "_50lzw.tif");
            writer = format.getWriter(writeFile);
            writer.write(gcCrop, (GeneralParameterValue[]) params.values().toArray(new GeneralParameterValue[1]));
            writer.dispose();

            irri_year += 5;
        }

        return back;
    }

    public static boolean Chop_all_raster_nass_data(File dataDir, File outputDir, List<Geometry> envelope, List<String> years, PrintWriter w_log) throws IllegalArgumentException, IOException {

        boolean back = true;

        Geometry targetGeometry = envelope.get(0);
        LinearRing lr = null;
        double min_size = 1500;

        //getting a format
        final GeoTiffFormat format = new GeoTiffFormat();

        //getting the write parameters
        final GeoTiffWriteParams wp = new GeoTiffWriteParams();

        //setting compression to LZW
        wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
        wp.setCompressionType("LZW");
        wp.setCompressionQuality(0.75F);

        //setting the tile size to 256X256
        wp.setTilingMode(GeoToolsWriteParams.MODE_EXPLICIT);
        wp.setTiling(256, 256);

        //setting the write parameters for this geotiff
        final ParameterValueGroup params = format.getWriteParameters();
        params.parameter(AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString()).setValue(wp);

        Crop ImageCrop = new Crop();

        ParameterValueGroup CropParameterValueGroup = ImageCrop.getParameters();

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);

        //done irrigation GeoTIFF cropping
        for (String year : years) {

            File NASS_file = new File(dataDir, "NASS_" + year + ".tif");
            w_log.println("   Processing year: " + year);
            w_log.flush();
            GridCoverage2DReader reader = new GeoTiffReader(NASS_file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));

            final GridCoverage2D gc = (GridCoverage2D) reader.read(null);

            AffineTransform gridToCRS_gcsaga = (AffineTransform) gc.getGridGeometry().getGridToCRS2D();
            double cs = org.geotools.referencing.operation.matrix.XAffineTransform.getScaleX0(gridToCRS_gcsaga);

            CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem();
            reader.dispose();
            Hints hints = new Hints();
            hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);

            if (!targetGeometry.isValid()) {
                targetGeometry = targetGeometry.convexHull();
            }
            int last_coo = targetGeometry.getCoordinates().length - 1;
            if (!targetGeometry.getCoordinates()[0].equals(targetGeometry.getCoordinates()[last_coo])) {
                targetGeometry = targetGeometry.convexHull();
            }
            lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
            if (!lr.isValid()) {
                targetGeometry = targetGeometry.convexHull();
                lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
            }
            Polygon crop_poly = new Polygon(lr, null, geometryFactory);
            crop_poly = (Polygon) crop_poly.buffer(1000);

            if (cs > 30) {
                min_size = 4000;
            }
            if (cs < 50) {
                min_size = 2000;
            }
            if (crop_poly.getArea() < min_size) {
                int bb = 1;
                while (crop_poly.getArea() < min_size) {
                    crop_poly = (Polygon) crop_poly.buffer(bb++);
                }
            }
            Polygon simpleP = (Polygon) TopologyPreservingSimplifier.simplify(crop_poly, 1);
            CropParameterValueGroup.parameter("SOURCE").setValue(gc);
            CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
            boolean success = false;
            double sizer = 1000;
            try {
                GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                success = true;
                throw new Exception();
            } catch (Exception e) {
            } finally {
                if (!success) {
                    while (!success) {
                        crop_poly = (Polygon) crop_poly.buffer(sizer);
                        sizer = sizer + 1000;
                        simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 1);
                        CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                        try {
                            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                            success = true;
                            throw new Exception();
                        } catch (Exception e) {
                        } finally {

                        }
                    }
                    crop_poly = (Polygon) crop_poly.buffer(sizer);
                    simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 1);
                    CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                }
            }

            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);

            GridCoverageWriter writer = null;
            final File writeFile = new File(outputDir, "NASS_" + year + ".tif");
            writer = format.getWriter(writeFile);
            writer.write(gcCrop, (GeneralParameterValue[]) params.values().toArray(new GeneralParameterValue[1]));
            writer.dispose();

        }
        return back;
    }

    /**
     * @param CDL_years
     * @param Input_Geometries
     * @param map
     * @param dataDir
     * @param outputDir
     * @param geotiffs
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static ArrayList<Nass_results> ConcurrentGeoTIFF_Clipping(List<String> CDL_years, List<Geometry> Input_Geometries, HashMap<Integer, String> map, File dataDir, File outputDir, boolean geotiffs, int start_id, SessionLogger LOG) throws InterruptedException, ExecutionException {

        final int threadNum = Partition.getThreadCount(Input_Geometries.size());
        final int startID = start_id;
        final int first = 0;
        final int last = CDL_years.size() - 1;
        final List<String> years = CDL_years;
        final HashMap<Integer, String> fmap = map;
        final List<Geometry> fG = Input_Geometries;
        final SessionLogger fSL = LOG;
        final File oD = outputDir;
        final File dD = dataDir;
        final boolean fgeotiffs = geotiffs;

        final int p = (last + 1) / threadNum;
        int s = (last + 1) - p * threadNum;
        ArrayList<Nass_results> result_list = new ArrayList<>();

        // Prepare to execute and store the Futures
        ExecutorService executor = Executors.newFixedThreadPool(threadNum);
        List<FutureTask<ArrayList<Nass_results>>> taskList = new ArrayList<>();
        for (int j = 0; j < threadNum; j++) {
            final int ii = j;
            FutureTask<ArrayList<Nass_results>> futureTask_1 = new FutureTask<>(new Callable<ArrayList<Nass_results>>() {
                int inlast = (ii == threadNum - 1 ? last : p + (ii * p));
                int infirst = (ii == 0 ? first : (p * ii) + 1);

                @Override
                public ArrayList<Nass_results> call() throws Exception {
                    return CSIP_NASS_GeoTIFF.NASS_GeoTIFF_clipping(infirst, inlast, fmap, years, fG, dD, oD, fgeotiffs, startID, fSL);
                }
            });
            taskList.add(futureTask_1);
            executor.execute(futureTask_1);
        }

        // Wait until all results are available and combine them at the same time
        for (int j = 0; j < threadNum; j++) {
            FutureTask<ArrayList<Nass_results>> futureTask = taskList.get(j);
            for (int i = 0; i < futureTask.get().size(); i++) {
                result_list.add(futureTask.get().get(i));
            }
        }
        executor.shutdown();
        return result_list;
    }

    /**
     *
     * @param dataDir
     * @param Input_Geometries
     * @param LOG
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     * @throws java.net.MalformedURLException
     * @throws java.io.IOException
     */
    public static HashMap<Integer, ArrayList<HashMap<Integer, Double>>> ConcurrentIrrigation_Overlay(File dataDir, List<Geometry> Input_Geometries, int start_id, String start_year, SessionLogger LOG)
            throws InterruptedException, ExecutionException, MalformedURLException, IllegalArgumentException, IOException {

        //final int threadNum = CSIP_Const.Number_of_Irrigation_tifs;
        String[] years_org = new String[]{"2002", "2007", "2012", "2017"};

        List<String> yearList = new ArrayList<>();

        for (String years_org1 : years_org) {
            if (Integer.parseInt(years_org1) + 1 >= Integer.parseInt(start_year)) {
                yearList.add(years_org1);
            }
        }

        String[] years_array = new String[yearList.size()];
        final String[] years = yearList.toArray(years_array);

        HashMap<Integer, ArrayList<HashMap<Integer, Double>>> result_map = new HashMap<>();

        final int threadNum = Partition.getThreadCount(Input_Geometries.size());;
        final int stID = start_id;
        final int first = 0;
        final int last = Input_Geometries.size() - 1;
        final int p = (last + 1) / threadNum;
        int s = (last + 1) - p * threadNum;

        final File dD = dataDir;
        final List<Geometry> fG = Input_Geometries;
        int years_size = years.length;

        for (int i = 0, year_size = years_size; i < year_size; i++) {
            final int pos = i;
            long start_time = System.currentTimeMillis();
            //w_log.println("  year: " + years[pos]);
            LOG.info("  year: " + years[pos]);
            //w_log.flush();
            // Prepare to execute and store the Futures
            ExecutorService executor = Executors.newFixedThreadPool(threadNum);
            List<FutureTask<HashMap<Integer, Double>>> taskList = new ArrayList<>();
            for (int j = 0; j < threadNum; j++) {
                final int ii = j;
                FutureTask<HashMap<Integer, Double>> futureTask_1 = new FutureTask<>(new Callable<HashMap<Integer, Double>>() {
                    int inlast = (ii == threadNum - 1 ? last : p + (ii * p));
                    int infirst = (ii == 0 ? first : (p * ii) + 1);

                    @Override
                    public HashMap<Integer, Double> call() throws Exception {
                        return CSIP_NASS_GeoTIFF.IRRIGATION_clip_analysis(infirst, inlast, pos, dD, fG, stID, years[pos]);
                    }
                });
                taskList.add(futureTask_1);
                executor.execute(futureTask_1);
            }

            // Wait until all results are available and combine them at the same time
            for (int j = 0; j < threadNum; j++) {
                FutureTask<HashMap<Integer, Double>> futureTask = taskList.get(j);
                Set<Integer> set = futureTask.get().keySet();
                for (int u : set) {
                    HashMap<Integer, Double> year_irri_map = new HashMap<>();
                    ArrayList<HashMap<Integer, Double>> arr_hash = new ArrayList<>();
                    if (result_map.get(u) == null) {
                        year_irri_map.put(Integer.parseInt(years[pos]), futureTask.get().get(u));
                        arr_hash.add(year_irri_map);
                        result_map.put(u, arr_hash);
                        //LOG.info(" empty : " + u + " " + years[pos] + " " + futureTask.get().get(u));
                    } else {
                        year_irri_map.put(Integer.parseInt(years[pos]), futureTask.get().get(u));
                        arr_hash = result_map.get(u);
                        arr_hash.add(year_irri_map);
                        result_map.put(u, arr_hash);
                        //LOG.info(" not! empty : " + u + " " + years[pos] + " " + futureTask.get().get(u));
                    }
                }
            }
            executor.shutdown();
            long end_time = System.currentTimeMillis();
            double difference = (end_time - start_time) / 1000;
            LOG.info(" Irrigation raster duration: " + difference + " s");
        }
        return result_map;
    }

    /**
     *
     * @param dataDir
     * @param st
     * @return
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public static List<String> NASS_CDL_YEARS_CHECK(File dataDir, List<String> st) throws ClassNotFoundException, SQLException {
        Class.forName("org.h2.Driver");
        List<String> years;
        int smallest = 9000;
        try (Connection conn = DriverManager.getConnection("jdbc:h2:file:" + dataDir.getPath() + CSIP_Const.LocalDB, "sa", "");
                Statement state = conn.createStatement()) {
            years = new ArrayList<>();
            for (int x = 0; x < st.size(); x++) {
                String queryString = "select * from \"PUBLIC\".CDL_YEARS where acr='" + st.get(x) + "'";
                ResultSet result = state.executeQuery(queryString);
                while (result.next()) {
                    for (String str : CSIP_Const.CDL_years) {
                        if (Integer.parseInt(result.getString(str)) > 0 && !years.contains(str)) {
                            years.add(str);
                            if (Integer.parseInt(str) < smallest) {
                                smallest = Integer.parseInt(str);
                            }
                        }
                    }
                }
            }
            state.close();
            conn.close();
        }
        int counter = 0;
        int full = CSIP_Const.currentNASSyear - smallest;
        if (years.size() != full) {
            years.clear();
            years.add("" + smallest);
            while (full > counter) {
                counter++;
                years.add("" + (smallest + counter));
            }
        }
        return years;
    }

    /**
     *
     * @param shapefile
     * @return
     * @throws IOException
     */
    protected static FeatureCollection featureCollectionFromShapefile(URL shapefile) throws IOException {
        DataStore dataStore = new ShapefileDataStore(shapefile);
        FeatureSource featureSource = dataStore.getFeatureSource(dataStore.getTypeNames()[0]);
        return featureSource.getFeatures();
    }

    static {
        System.setProperty("com.sun.media.jai.disableMediaLib", "true");
    }

    public static class accuComparator implements Comparator<Nass_area_reclassify> {

        @Override
        public int compare(Nass_area_reclassify o1, Nass_area_reclassify o2) {
            return Double.compare(o1.getaccu(), o2.getaccu());
        }
    }

    public static class areaComparator implements Comparator<Nass_area_reclassify> {

        @Override
        public int compare(Nass_area_reclassify o1, Nass_area_reclassify o2) {
            return Double.compare(o2.getnewArea(), o1.getnewArea());
        }
    }

    /**
     *
     * @param dataDir
     * @return
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public static HashMap<Integer, String> DB_Query_NASS_Raster_IDs(File dataDir) throws ClassNotFoundException, SQLException {

        HashMap<Integer, String> map = new HashMap<>();
        Class.forName("org.h2.Driver");
        try (Connection conn = DriverManager.getConnection("jdbc:h2:file:" + dataDir.getPath() + CSIP_Const.LocalDB, "sa", "");
                Statement state = conn.createStatement()) {
            String queryString = "select * from \"PUBLIC\".RASTER_LINK order by GRID_VALUE";
            ResultSet result = state.executeQuery(queryString);
            while (result.next()) {
                map.put(Integer.parseInt(result.getString("GRID_VALUE")), result.getString("NASS_NAME"));
            }
            state.close();
            conn.close();
        }
        return map;
    }

    /**
     *
     * @param dataDir
     * @param allcrops
     * @param states
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public static HashMap<String, ArrayList<Nass_accurcies>> DB_nassaccu(File dataDir, ArrayList<String> allcrops, List<String> states) throws IOException, ClassNotFoundException, SQLException {

        HashMap<String, ArrayList<Nass_accurcies>> prep_map = new HashMap<>();

        int[] ac_intarray = new int[CSIP_Const.ACC_years.length];
        double[] ac = new double[CSIP_Const.ACC_years.length];

        int ff = 0;
        for (String str : CSIP_Const.ACC_years) {
            ac_intarray[ff] = Integer.parseInt(str);
            ac[ff] = 0.0;
            ff++;
        }

        for (int i = 0; i < allcrops.size(); i++) {
            ArrayList<Nass_accurcies> list = new ArrayList();
            for (int j = 0; j < states.size(); j++) {
                list.add(new Nass_accurcies(states.get(j), ac, ac_intarray));
            }
            prep_map.put(allcrops.get(i), list);
        }

        HashMap<String, ArrayList<Nass_accurcies>> map = new HashMap<>();

        Class.forName("org.h2.Driver");
        try (Connection conn = DriverManager.getConnection("jdbc:h2:file:" + dataDir.getPath() + CSIP_Const.LocalDB, "sa", "")) {
            try (Statement state = conn.createStatement()) {

                for (String crop : allcrops) {
                    ArrayList<Nass_accurcies> list = new ArrayList<>();
                    for (String stateoutlist : states) {
                        double nass_accuracy[] = new double[CSIP_Const.ACC_years.length];
                        int nass_accu_years[] = new int[CSIP_Const.ACC_years.length];
                        int rr = 0;
                        for (String accyear : CSIP_Const.ACC_years) {
                            String queryString = "select " + stateoutlist + " from \"PUBLIC\".ACCURACY" + accyear + " where cropname='" + crop + "'";
                            ResultSet result = state.executeQuery(queryString);
                            while (result.next()) {
                                if (!result.getString(stateoutlist).equals("-")) {
                                    nass_accuracy[rr] = Double.parseDouble(result.getString(stateoutlist));
                                } else {
                                    nass_accuracy[rr] = 0.0;
                                }
                                nass_accu_years[rr] = Integer.parseInt(accyear);
                            }
                            rr++;
                        }
                        list.add(new Nass_accurcies(stateoutlist, nass_accuracy, nass_accu_years));
                    }
                    if (map.put(crop, list) != null) {
                        throw new IllegalArgumentException("Duplicate name: " + crop);
                    }
                }
                state.close();
            }
            conn.close();
        }

        //TODO have to be much more HashMappy ;-)
        Set<String> set = map.keySet();
        for (String u : set) {
            if (prep_map.get(u) == null) {
                prep_map.put(u, map.get(u));
            } else {
                ArrayList<Nass_accurcies> list_available = map.get(u);
                ArrayList<Nass_accurcies> list_not = prep_map.get(u);
                for (int i = 0; i < list_available.size(); i++) {
                    String av_state = list_available.get(i).getstate();
                    for (int j = 0; j < list_not.size(); j++) {
                        if (av_state.equals(list_not.get(i).getstate())) {
                            prep_map.put(u, map.get(u));
                            break;
                        }
                    }
                }
            }
        }
        map.clear();

        return prep_map;
    }

    /**
     *
     * @param first
     * @param last
     * @param pos
     * @param dataDir
     * @param Input_Geometries
     * @param ye
     * @return
     * @throws MalformedURLException
     * @throws IllegalArgumentException
     * @throws IOException
     */
    public static HashMap<Integer, Double> IRRIGATION_clip_analysis(int first, int last, int pos, File dataDir, List<Geometry> Input_Geometries, int stID, String ye) throws MalformedURLException, IllegalArgumentException, IOException {
        HashMap<Integer, Double> map = new HashMap<>();

        Crop ImageCrop = new Crop();

        ParameterValueGroup CropParameterValueGroup = ImageCrop.getParameters();

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        File[] geotiff = {new File(dataDir, CSIP_Const.Irrigation2002), new File(dataDir, CSIP_Const.Irrigation2007), new File(dataDir, CSIP_Const.Irrigation2012), new File(dataDir, CSIP_Const.Irrigation2017)};

        GridCoverage2DReader reader = new GeoTiffReader(geotiff[pos].toURI().toURL(), new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));
        GridCoverage2D gcsaga = (GridCoverage2D) reader.read(null);

        AffineTransform gridToCRS_gcsaga = (AffineTransform) gcsaga.getGridGeometry().getGridToCRS2D();
        double cs = org.geotools.referencing.operation.matrix.XAffineTransform.getScaleX0(gridToCRS_gcsaga);

        final Hints hints = new Hints();
        CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem();
        reader.dispose();
        hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);

        for (int j = first; j <= last; j++) {

            Geometry targetGeometry = Input_Geometries.get(j);

            if (!targetGeometry.isValid()) {
                targetGeometry = targetGeometry.convexHull();
            }

            int last_coo = targetGeometry.getCoordinates().length - 1;
            if (!targetGeometry.getCoordinates()[0].equals(targetGeometry.getCoordinates()[last_coo])) {
                targetGeometry = targetGeometry.convexHull();
            }

            LinearRing lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());

            if (!lr.isValid()) {
                targetGeometry = targetGeometry.convexHull();
                lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
            }

            Polygon crop_poly = new Polygon(lr, null, geometryFactory);

            double min_size = 1500;
            if (cs > 30) {
                min_size = 4000;
            }
            if (cs < 50) {
                min_size = 2000;
            }
            if (crop_poly.getArea() < min_size) {
                int bb = 1;
                while (crop_poly.getArea() < min_size) {
                    crop_poly = (Polygon) crop_poly.buffer(bb++);
                }
            }

            Polygon simpleP = (Polygon) TopologyPreservingSimplifier.simplify(crop_poly, 1);

            CropParameterValueGroup.parameter("SOURCE").setValue(gcsaga);
            CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);

            boolean success = false;
            double sizer = 0.1;

            try {
                GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                success = true;
                throw new Exception();
            } catch (Exception e) {
            } finally {
                if (!success) {
                    //System.out.println(j + "   No Irrigation overlay possible !!!!!!!!!!!!!!!!");
                    while (!success) {
                        crop_poly = (Polygon) crop_poly.buffer(sizer);
                        sizer = sizer + 0.1;
                        simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 0.1);
                        CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                        try {
                            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                            success = true;
                            throw new Exception();
                        } catch (Exception e) {
                        } finally {

                        }
                    }
                    crop_poly = (Polygon) crop_poly.buffer(sizer);
                    simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 0.1);
                    CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                }
            }

            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
            int values = 0;

            GridGeometry2D gg = gcCrop.getGridGeometry();
            double data[] = new double[1];
            Rectangle gridBoundss = gg.getGridRange2D().getBounds();
            for (int y1 = gridBoundss.y, ny = 0; ny < gridBoundss.height; y1++, ny++) {
                for (int x = gridBoundss.x, nx = 0; nx < gridBoundss.width; x++, nx++) {
                    GridCoordinates2D gridCoord = new GridCoordinates2D(x, y1);
                    gcCrop.evaluate(gridCoord, data);
                    if (data[0] == 1) {
                        values++;
                    }
                }
            }

            if (values > 0) {
                double irri_size = values * (cs * cs);
                double frac_irri = (irri_size / simpleP.getArea()) * 100;
                if (frac_irri > 0.999) {
                    int ID = j + stID;
                    map.put(ID, frac_irri);
                }
            }
        }
        return map;
    }

    /**
     *
     * @param dataDir
     * @param CDLdataDir
     * @param years
     * @param outputDir
     * @param Input_Geometries
     * @param hrus
     * @param unique_states
     * @param geotiffs
     * @param LOG
     * @return
     * @throws IOException
     * @throws URISyntaxException
     * @throws ClassNotFoundException
     * @throws SQLException
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static HashMap<Integer, ArrayList<Nass_results>> NASSGeoTIFF_clip_analysis(File dataDir, File CDLdataDir, File outputDir, List<String> years, List<Geometry> Input_Geometries, List<ERU> hrus, List<String> unique_states, boolean geotiffs, SessionLogger LOG) throws IOException, URISyntaxException, ClassNotFoundException, SQLException, InterruptedException, ExecutionException {

        LOG.info(" ");
        LOG.info("GeoTIFFs clip & analysis....");
        LOG.info(" ERUs " + hrus.size() + "  and " + years.size() + " years");

        HashMap<Integer, String> NASS_map = new HashMap<>();
        NASS_map = CSIP_NASS_GeoTIFF.DB_Query_NASS_Raster_IDs(dataDir);

        ArrayList<Nass_results> cropslist = new ArrayList<>();
        cropslist = CSIP_NASS_GeoTIFF.ConcurrentGeoTIFF_Clipping(years, Input_Geometries, NASS_map, CDLdataDir, outputDir, geotiffs, hrus.get(0).ID, LOG);

        LOG.info("  Done GeoTIFF Clipping");

        ArrayList<String> all_crops = new ArrayList<>();

        for (ERU hru : hrus) {
            List<String> NASS_print_list = new ArrayList<>();
            for (int v = 0, nasslist_size = cropslist.size(); v < nasslist_size; v++) {
                if (hru.ID == cropslist.get(v).getID()) {
                    for (int k = 0; k < cropslist.get(v).getcrop_nass_names().length; k++) {
                        if (!all_crops.contains(cropslist.get(v).getcrop_nass_names()[k])) {
                            all_crops.add(cropslist.get(v).getcrop_nass_names()[k]);
                        }
                        NASS_print_list.add("," + cropslist.get(v).getID() + "," + cropslist.get(v).getyear() + "," + cropslist.get(v).getclip_grid_area() + "," + cropslist.get(v).getpolygon_area() + "," + cropslist.get(v).getcrop_nass_names()[k] + "," + cropslist.get(v).getcrop_area()[k]);
                    }
                }
            }
            hru.nass_plain_list = NASS_print_list;
        }

        LOG.info("  Done NASS List;  size: " + cropslist.size());

        LOG.info(" " + all_crops.size() + " different crops/vegatation/landuses found.");

        HashMap<String, ArrayList<Nass_accurcies>> map = new HashMap<>();
        map = CSIP_NASS_GeoTIFF.DB_nassaccu(dataDir, all_crops, unique_states);
        all_crops.clear();

        HashMap<Integer, ArrayList<Nass_results>> ALL_HRU_CROPS = new HashMap();
        ALL_HRU_CROPS = CSIP_NASS_GeoTIFF.ConcurrentHRU_NASS(map, cropslist, hrus);

        map.clear();
        cropslist.clear();

        LOG.info(" ");
        LOG.info("Dominat NASS crops/vegetations linked to HRUs.");

        return ALL_HRU_CROPS;
    }

    public static ArrayList<Nass_results> NASS_GeoTIFF_clipping(int first, int last, HashMap<Integer, String> map, List<String> years, List<Geometry> Input_Geometries, File dataDir, File outputDir, boolean geotiffs, int start_id, SessionLogger LOG) throws IllegalArgumentException, IOException, ExecutionException, FactoryException {

        ArrayList<Nass_results> cropslist = new ArrayList<>();

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        CoordinateReferenceSystem targetCRS = CRS.parseWKT(CSIP_Const.WKT_CooSyst);

        double min_x = 28000000;
        double max_x = -28000000;
        double min_y = 3000000;
        double max_y = 280000;

        for (int i = first; i <= last; i++) {
            File NASS_file = new File(dataDir, "NASS_" + years.get(i) + ".tif");
            if (NASS_file.exists()) {
                //w_log.println("   Processing year: " + years.get(i));
                LOG.info("   Processing year: " + years.get(i));
                //w_log.flush();

                GridCoverage2DReader reader = new GeoTiffReader(NASS_file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE));

                final GridCoverage2D gc = (GridCoverage2D) reader.read(null);

                min_x = gc.getEnvelope().getLowerCorner().getCoordinate()[0];
                min_y = gc.getEnvelope().getLowerCorner().getCoordinate()[1];
                max_x = gc.getEnvelope().getUpperCorner().getCoordinate()[0];
                max_y = gc.getEnvelope().getUpperCorner().getCoordinate()[1];

                Geometry NASS_raster_envelope = JTS.toGeometry(new ReferencedEnvelope(min_x, max_x, min_y, max_y, targetCRS));

                Crop ImageCrop = new Crop();

                ParameterValueGroup CropParameterValueGroup = ImageCrop.getParameters();
                CropParameterValueGroup.parameter("Source").setValue(gc);

                AffineTransform gridToCRS = (AffineTransform) gc.getGridGeometry().getGridToCRS2D();
                double cell_size = org.geotools.referencing.operation.matrix.XAffineTransform.getScaleX0(gridToCRS);

                final Hints hints = new Hints();
                CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem();

                reader.dispose();

                hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);

                int y = start_id;
                for (int bj = 0; bj < Input_Geometries.size(); bj++) {

                    HashMap<Integer, Integer> Pixel_NASSID_map = new HashMap<>();
                    int values = 0;

                    Geometry targetGeometry = Input_Geometries.get(bj);
                    LinearRing lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
                    Polygon crop_poly = new Polygon(lr, null, geometryFactory);
                    Polygon crop_poly_org = crop_poly;

                    if (Input_Geometries.get(bj).intersects(NASS_raster_envelope)) {

                        if (!targetGeometry.isValid()) {
                            targetGeometry = targetGeometry.convexHull();
                        }

                        int last_point = targetGeometry.getCoordinates().length - 1;
                        if (!targetGeometry.getCoordinates()[0].equals(targetGeometry.getCoordinates()[last_point])) {
                            targetGeometry = targetGeometry.convexHull();
                        }

                        lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());

                        if (!lr.isValid()) {
                            targetGeometry = targetGeometry.convexHull();
                            lr = geometryFactory.createLinearRing(targetGeometry.getCoordinates());
                        }

                        crop_poly = new Polygon(lr, null, geometryFactory);
                        crop_poly_org = crop_poly;

                        double min_size = 1500;
                        if (cell_size > 30) {
                            min_size = 4000;
                        }
                        if (cell_size < 50) {
                            min_size = 2000;
                        }
                        if (crop_poly.getArea() < min_size) {
                            int bb = 1;
                            while (crop_poly.getArea() < min_size) {
                                crop_poly = (Polygon) crop_poly.buffer(bb++);
                            }
                        }

                        //Polygon simpleP = (Polygon) TopologyPreservingSimplifier.simplify(crop_poly, 1);
                        Polygon simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 0.1);

                        CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                        //CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(crop_poly);

                        boolean success = false;
                        double sizer = 0.1;

                        try {
                            GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                            success = true;
                            throw new Exception();

                        } catch (Exception e) {

                        } finally {
                            if (!success) {
                                //System.out.println(bj + "  No Cropping possible !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! " + years.get(i));
                                while (!success) {
                                    crop_poly = (Polygon) crop_poly.buffer(sizer);
                                    sizer = sizer + 0.1;
                                    simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 0.1);
                                    CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                                    try {
                                        GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                                        success = true;
                                        throw new Exception();
                                    } catch (Exception e) {
                                    } finally {

                                    }
                                }
                                crop_poly = (Polygon) crop_poly.buffer(sizer);
                                simpleP = (Polygon) DouglasPeuckerSimplifier.simplify(crop_poly, 0.1);
                                CropParameterValueGroup.parameter(Crop.PARAMNAME_ROI).setValue(simpleP);
                                //System.out.println(bj + " fine_org:  " + crop_poly_org.getArea() + "   new: " + crop_poly.getArea() + " sizer: " + sizer + " success " + success);
                            }
                        }

                        GridCoverage2D gcCrop = (GridCoverage2D) ImageCrop.doOperation(CropParameterValueGroup, hints);
                        if (geotiffs && Integer.parseInt(years.get(i)) > 2007) {
                            try (ImageOutputStream imageOutStream = ImageIO.createImageOutputStream(new FileOutputStream(new File(outputDir, "" + bj + "NASS_" + years.get(i) + ".tif")))) {
                                //getting a format
                                final GeoTiffFormat tiffformat = new GeoTiffFormat();

                                //getting the write parameters
                                final GeoTiffWriteParams wp = new GeoTiffWriteParams();

                                //setting the compression to LZW
                                wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
                                wp.setCompressionType("LZW");
                                wp.setCompressionQuality(0.75F);

                                //setting the tile size to 256X256
                                wp.setTilingMode(GeoToolsWriteParams.MODE_EXPLICIT);
                                wp.setTiling(256, 256);

                                //setting the write parameter for this geotiff
                                final ParameterValueGroup tiffparams = tiffformat.getWriteParameters();
                                tiffparams.parameter(AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString()).setValue(wp);

                                final GeoTiffWriter writer = new GeoTiffWriter(imageOutStream);
                                writer.write(gcCrop, (GeneralParameterValue[]) tiffparams.values().toArray(new GeneralParameterValue[1]));
                                imageOutStream.flush();
                                imageOutStream.close();
                            } catch (Exception e) {
                                LOG.info("GeoTIFF generation went wrong, year: " + years.get(i));
                            } finally {
                                LOG.info(" no GeoTIFF generated for year: " + years.get(i));
                            }
                        }
                        ArrayList pixvalues = new ArrayList<>();

                        GridGeometry2D gg = gcCrop.getGridGeometry();
                        int data[] = new int[1];
                        Rectangle gridBoundss = gg.getGridRange2D().getBounds();
                        for (int y1 = gridBoundss.y, ny = 0; ny < gridBoundss.height; y1++, ny++) {
                            for (int x = gridBoundss.x, nx = 0; nx < gridBoundss.width; x++, nx++) {
                                GridCoordinates2D gridCoord = new GridCoordinates2D(x, y1);
                                try {
                                    gcCrop.evaluate(gridCoord, data);
                                } catch (Exception e) {
                                    LOG.info("GeoTIFF reading went wrong, year: " + years.get(i));
                                }
                                if (data[0] > 0 && data[0] < 300) {
                                    if (Pixel_NASSID_map.get(data[0]) == null) {
                                        Pixel_NASSID_map.put(data[0], 1);
                                    } else {
                                        Pixel_NASSID_map.put(data[0], (Pixel_NASSID_map.get(data[0])) + 1);
                                    }
                                    values++;
                                }
                                if (!pixvalues.contains(data[0])) {
                                    pixvalues.add(data[0]);
                                }
                            }
                        }
                    }
                    if (values == 0) {
                        values = 1;
                        Pixel_NASSID_map.put(255, 1);
                    }

                    double clip_size = (cell_size * cell_size) * values;
                    double[] crops_area = new double[Pixel_NASSID_map.size()];
                    String[] crops_names = new String[Pixel_NASSID_map.size()];
                    Boolean[] is_crop = null;

                    int cc = 0;
                    for (Map.Entry<Integer, Integer> entry : Pixel_NASSID_map.entrySet()) {
                        if (map.get(entry.getKey()).isEmpty() || map.get(entry.getKey()).equals("null")) {
                            //w_log.println("HRU " + y + " Pixel ID " + entry.getKey() + "    no crop name in year: " + years.get(i));
                            LOG.info("HRU " + y + " Pixel ID " + entry.getKey() + "    no crop name in year: " + years.get(i));
                            //w_log.flush();
                        } else {
                            crops_names[cc] = map.get(entry.getKey());
                            crops_area[cc] = (double) entry.getValue() * (cell_size * cell_size);
                            cc++;
                        }
                    }
                    double round_area = Math.round(crop_poly_org.getArea() * 1000) / 1000;
                    cropslist.add(new Nass_results(years.get(i), y, round_area, clip_size, crops_names, crops_area, is_crop, crops_area));
                    y++;
                    Pixel_NASSID_map.clear();
                }
            }

            LOG.info("   Done year: " + years.get(i));
        }
        return cropslist;
    }

    /**
     *
     * @param map
     * @param cropslist
     * @param hrus
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public static HashMap<Integer, ArrayList<Nass_results>> ConcurrentHRU_NASS(HashMap<String, ArrayList<Nass_accurcies>> map, ArrayList<Nass_results> cropslist, List<ERU> hrus)
            throws InterruptedException, ExecutionException {

        final int threadNum = Partition.getThreadCount(hrus.size());;
        final int first = 0;
        final int last = hrus.size() - 1;
        final HashMap<String, ArrayList<Nass_accurcies>> fmap = map;
        final ArrayList<Nass_results> fcroplist = cropslist;
        final List<ERU> fHRU = hrus;
        final int p = (last + 1) / threadNum;
        int s = (last + 1) - p * threadNum;

        HashMap<Integer, ArrayList<Nass_results>> All_HRUs_Linked = new HashMap();

        // Prepare to execute and store the Futures
        ExecutorService executor = Executors.newFixedThreadPool(threadNum);
        List<FutureTask<HashMap<Integer, ArrayList<Nass_results>>>> taskList = new ArrayList<>();
        for (int j = 0; j < threadNum; j++) {
            final int ii = j;
            FutureTask<HashMap<Integer, ArrayList<Nass_results>>> futureTask_1 = new FutureTask<>(new Callable<HashMap<Integer, ArrayList<Nass_results>>>() {
                int inlast = (ii == threadNum - 1 ? last : p + (ii * p));
                int infirst = (ii == 0 ? first : (p * ii) + 1);

                @Override
                public HashMap<Integer, ArrayList<Nass_results>> call() throws Exception {
                    return CSIP_NASS_GeoTIFF.HRU_NASS_GeoTIFF(infirst, inlast, fmap, fcroplist, fHRU);
                }
            });
            taskList.add(futureTask_1);
            executor.execute(futureTask_1);
        }

        // Wait until all results are available and combine them at the same time
        for (int j = 0; j < threadNum; j++) {
            FutureTask<HashMap<Integer, ArrayList<Nass_results>>> futureTask = taskList.get(j);
            Set<Integer> set = futureTask.get().keySet();
            for (int u : set) {
                if (All_HRUs_Linked.get(u) == null) {
                    All_HRUs_Linked.put(u, futureTask.get().get(u));
                }
            }
        }
        executor.shutdown();
        return All_HRUs_Linked;
    }

    /**
     *
     * @param first
     * @param last
     * @param map
     * @param cropslist
     * @param hrus
     * @return
     * @throws IllegalArgumentException
     * @throws IOException
     */
    public static HashMap<Integer, ArrayList<Nass_results>> HRU_NASS_GeoTIFF(int first, int last, HashMap<String, ArrayList<Nass_accurcies>> map, ArrayList<Nass_results> cropslist, List<ERU> hrus) throws IllegalArgumentException, IOException {

        ArrayList accu_year_list = new ArrayList();
        Collections.addAll(accu_year_list, CSIP_Const.ACC_years);

        int startHRU_ID = hrus.get(0).ID;

        HashMap<Integer, ArrayList<Nass_results>> resultmap = new HashMap<>();

        for (int xx = first; xx <= last; xx++) {
            ArrayList<Nass_results> cropslist2 = new ArrayList<>();
            for (int i = 0; i < cropslist.size(); i++) { //for all crops per year
                ArrayList<Nass_area_reclassify> list = new ArrayList<>();
                if ((xx + startHRU_ID) == cropslist.get(i).getID()) { // link HRU ID to geometry ID
//                    w_log.println(" ID: " + xx);
//                    w_log.println(" YEAR: " + cropslist.get(i).getyear());
//                    w_log.flush();
                    //System.out.print("   " + cropslist.get(i).getclip_grid_area() + " m2");
                    //reclassify with NASS accu values and save 1st and 2nd dominat crops with area size
                    if (accu_year_list.contains(cropslist.get(i).getyear())) {
                        for (int k = 0; k < cropslist.get(i).getcrop_nass_names().length; k++) {
                            ArrayList<Nass_accurcies> nass_accu_list = new ArrayList<>();
                            if (map.get(cropslist.get(i).getcrop_nass_names()[k]) != null) {
                                nass_accu_list = map.get((cropslist.get(i).getcrop_nass_names()[k]).trim());
                            }
                            for (int l = 0; l < nass_accu_list.size(); l++) {
                                String state = nass_accu_list.get(l).getstate();
                                for (int m = 0; m < nass_accu_list.get(l).getaccus().length; m++) {
//                                    w_log.println(" StateSize: " + hrus.get(xx).state.size()+" "+state+"  NassAccuListSize: "+nass_accu_list.size());
//                                    w_log.flush();
                                    if (hrus.get(xx).state.get(0).equals(state) && Integer.parseInt(cropslist.get(i).getyear()) == nass_accu_list.get(l).getyears()[m]) {
                                        if (nass_accu_list.get(l).getaccus()[m] == 0.0) {
                                            list.add(new Nass_area_reclassify(cropslist.get(i).getcrop_nass_names()[k], cropslist.get(i).getcrop_area()[k], cropslist.get(i).getcrop_area()[k], 0.7, 0.999));
                                        } else {
                                            list.add(new Nass_area_reclassify(cropslist.get(i).getcrop_nass_names()[k], cropslist.get(i).getcrop_area()[k], cropslist.get(i).getcrop_area()[k], nass_accu_list.get(l).getaccus()[m], 0.999));

                                        }
                                        //System.out.println(" " + cropslist.get(i).getcrop_nass_names()[k] + "   " + nass_accu_list.get(l).getaccus()[m] + " " + cropslist.get(i).getyear());
                                    }
                                }
                            }
                        }

                        ArrayList<String> not_part_list = new ArrayList<>();

                        ArrayList<Nass_area_reclassify> list2 = new ArrayList<>();
                        //order list by accu value -->
                        Collections.sort(list, new accuComparator());
                        // list is full with crops per HRU and year
                        //double miss_classi = 0.1;
                        for (int k = 0; k < list.size(); k++) {
                            //while (list_it.hasNext()) {
                            //Nass_area_reclassify_object object = (Nass_area_reclassify) list_it.next();
                            Nass_area_reclassify object = (Nass_area_reclassify) list.get(k);
                            String name = object.getname();
                            double accu = object.getaccu();
                            double area = object.getorgArea();
                            double new_accu_area = area * accu;
                            //list.remove(object);
                            //double check_conf = (((area * accu) / cropslist.get(i).getpolygon_area()) * 100 > 100) ? 100.00 : ((area * accu) / cropslist.get(i).getpolygon_area()) * 100;
                            double check_conf_new = (area / cropslist.get(i).getclip_grid_area()) * accu;
                            //System.out.println("     -" + name + " area:" + area + " " + new_accu_area + " " + accu + " " + check_conf_new+ "  rast: " + cropslist.get(i).getclip_grid_area());
                            //System.out.println("      poly : " + cropslist.get(i).getpolygon_area() + "  rast: " + cropslist.get(i).getclip_grid_area() + " " + cropslist.get(i).getyear());
                            list2.add(new Nass_area_reclassify(name, area, new_accu_area, accu, check_conf_new));
                            //if (accu < miss_classi) {
                            if (accu > -1) {
                                double over_area = area - new_accu_area;
                                not_part_list.add(name);
                                int divider = (list.size() - (k + 1));
                                if (divider == 0) {
                                    divider = 1;
                                }
                                double area_parts = over_area / divider;
                                for (int x = 0; x < list.size(); x++) {
                                    //if (!not_part_list.contains(list.get(x).getname()) && list.get(x).getaccu() > miss_classi && list.get(x).getorgArea() > 4000) { Nov. 2013 changed
                                    if (!not_part_list.contains(list.get(x).getname())) {    //&& list.get(x).getaccu() > miss_classi) {
                                        String name_x = list.get(x).getname();
                                        double accu_x = list.get(x).getaccu();
                                        double area_x = list.get(x).getorgArea();
                                        double conf_x = list.get(x).getconf();
                                        double add_area = list.get(x).getnewArea() + area_parts;
                                        //System.out.println(" name for area change :"+name_x);
                                        list.remove(x);
                                        list.add(new Nass_area_reclassify(name_x, area_x, add_area, accu_x, conf_x));
                                    }
                                    if (list.size() == 1) { //|| (list.size() - 1 == x)
                                        String name_x = list.get(x).getname();
                                        double accu_x = list.get(x).getaccu();
                                        double area_x = list.get(x).getorgArea();
                                        double conf_x = list.get(x).getconf();
                                        double add_area = list.get(x).getnewArea() * accu_x;
                                        list.remove(x);
                                        list.add(new Nass_area_reclassify(name_x, area_x, add_area, accu_x, conf_x));
                                    }
                                }
                            }
                        }

                        //new sort by new area size
                        Collections.sort(list2, new areaComparator());
                        Boolean[] is_crop = new Boolean[list2.size()];

                        double conf_sum = 0;
                        String cr_names[] = new String[list2.size()];
                        double cr_areas[] = new double[list2.size()];
                        double cr_confs[] = new double[list2.size()];

                        //System.out.println(" ");
                        for (int k = 0; k < list2.size(); k++) {
                            conf_sum += list2.get(k).getconf();
                            cr_names[k] = list2.get(k).getname();
                            cr_areas[k] = list2.get(k).getnewArea();
                            cr_confs[k] = list2.get(k).getconf();
                            //w_log.println(k + " CropName: " + list2.get(k).getname() + " new: " + list2.get(k).getnewArea() + " old: " + list2.get(k).getorgArea());
                        }

                        if (!list2.isEmpty() && list2.size() > 1) {
                            for (int k = 0; k < 2; k++) {
                                is_crop[k] = true;
                                if (CSIP_Const.NonFieldCropClasses.contains(list2.get(k).getname())) {
                                    is_crop[k] = false;
                                }
                            }

                            //cropslist2.add(new Nass_results(cropslist.get(i).getyear(), hrus.get(xx).ID, cropslist.get(i).getpolygon_area(), cropslist.get(i).getclip_grid_area(), new String[]{list2.get(0).getname(), list2.get(1).getname()}, new double[]{list2.get(0).getnewArea(), list2.get(1).getnewArea()}, is_crop, new double[]{list2.get(0).getconf(), list2.get(1).getconf()}));
                            cropslist2.add(new Nass_results(cropslist.get(i).getyear(), hrus.get(xx).ID, cropslist.get(i).getpolygon_area(), cropslist.get(i).getclip_grid_area(), cr_names, cr_areas, is_crop, cr_confs));
                        } else {
                            is_crop[0] = (CSIP_Const.NonFieldCropClasses.contains(list2.get(0).getname())) ? false : true;
                            cropslist2.add(new Nass_results(cropslist.get(i).getyear(), hrus.get(xx).ID, cropslist.get(i).getpolygon_area(), cropslist.get(i).getclip_grid_area(), new String[]{list2.get(0).getname()}, new double[]{list2.get(0).getnewArea()}, is_crop, new double[]{list2.get(0).getconf()}));

                        }

                    } else { // NO NASS accu available take 1st and 2nd dominat crop without reclassify
                        for (int k = 0; k < cropslist.get(i).getcrop_nass_names().length; k++) {

                            double check_conf_new = (cropslist.get(i).getcrop_area()[k] / cropslist.get(i).getclip_grid_area()) * 1;

                            //list.add(new Nass_area_reclassify(cropslist.get(i).getcrop_nass_names()[k], cropslist.get(i).getcrop_area()[k], cropslist.get(i).getcrop_area()[k], 0.5, cropslist.get(i).getcrop_area()[k]));
                            list.add(new Nass_area_reclassify(cropslist.get(i).getcrop_nass_names()[k], cropslist.get(i).getcrop_area()[k], cropslist.get(i).getcrop_area()[k], 1, check_conf_new));

                        }

                        Collections.sort(list, new areaComparator());

                        String cr_names[] = new String[list.size()];
                        double cr_areas[] = new double[list.size()];
                        double cr_confs[] = new double[list.size()];

                        Boolean[] is_crop = new Boolean[list.size()];

                        if (!list.isEmpty() && list.size() > 1) {
                            for (int k = 0; k < list.size(); k++) {
                                is_crop[k] = true;
                                if (CSIP_Const.NonFieldCropClasses.contains(list.get(k).getname())) {
                                    is_crop[k] = false;
                                }
                                cr_names[k] = list.get(k).getname();
                                cr_areas[k] = list.get(k).getnewArea();
                                cr_confs[k] = list.get(k).getconf();
                            }

                            cropslist2.add(new Nass_results(cropslist.get(i).getyear(), hrus.get(xx).ID, cropslist.get(i).getpolygon_area(), cropslist.get(i).getclip_grid_area(), cr_names, cr_areas, is_crop, cr_confs));
                        } else {
                            is_crop[0] = (CSIP_Const.NonFieldCropClasses.contains(list.get(0).getname())) ? false : true;
                            cropslist2.add(new Nass_results(cropslist.get(i).getyear(), hrus.get(xx).ID, cropslist.get(i).getpolygon_area(), cropslist.get(i).getclip_grid_area(), new String[]{list.get(0).getname()}, new double[]{list.get(0).getnewArea()}, is_crop, new double[]{list.get(0).getconf()}));
                        }
                    }
                }
//                if ((cropslist2.size() > 1 && cropslist2.get(cropslist2.size() - 2).getcrop_nass_names()[0].equals("Clouds/No Data")) || (cropslist2.size() > 1 && cropslist2.get(cropslist2.size() - 2).getcrop_nass_names()[0].equals("Nonag/Undefined"))) {
//                    Nass_results check = cropslist2.get(cropslist2.size() - 2);
//                    String year = check.getyear();
//                    int Id = check.getID();
//                    double parea = check.getpolygon_area();
//                    double cgrid = cropslist2.get(cropslist2.size() - 1).getclip_grid_area();
//                    String[] cnames = cropslist2.get(cropslist2.size() - 1).getcrop_nass_names();
//                    double[] area = cropslist2.get(cropslist2.size() - 1).getcrop_area();
//                    Boolean[] crop = cropslist2.get(cropslist2.size() - 1).getcrop();
//                    double[] conf = cropslist2.get(cropslist2.size() - 1).getcrop_confidence();
//                    cropslist2.set(cropslist2.size() - 2, new Nass_results(year, Id, parea, cgrid, cnames, area, crop, conf));
//                }
            }
            resultmap.put(xx, cropslist2);
        }
        return resultmap;
    }
}