CliWindSoilFile.java [tools/GetLatLonCokey/src/getlatloncokey] Revision: 732ab534cb0723f078182d337db35823f3e084d0  Date: Wed Oct 30 16:01:50 MDT 2019
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package getlatloncokey;

import csip.ServiceException;
import csip.utils.JSONUtils;
import data.interpretors.CligenData;
import data.interpretors.WindGenData;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import soils.AoA;
import soils.Component;
import soils.MapUnit;
import soils.db.tables.TableComponent;
import soils.db.tables.TableComponentCalculations;

/**
 *
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
public class CliWindSoilFile {

    protected static final String SOILS_RETURN = "soils.json";
    protected static final String SOILS_REQUEST = "request.json";
    protected static final String CLIMATE_FILE = ".cli";
    protected static final String WIND_FILE = ".win";

    protected JSONArray soilsReturn;
    protected JSONArray returnVal;
    protected JSONObject request;
    protected Double latitude = Double.NaN, longitude = Double.NaN;
    protected String cokey = "";
    protected soils.AoA aoa;
    protected ArrayList<String> fields;
    protected Component maxComponent = null;
    protected MapUnit maxMapUnit = null;
    protected HashMap<String, Object> fieldData = new HashMap<>();
    protected CligenData climateData;
    protected WindGenData windData;

    public CliWindSoilFile(File filename, ArrayList<String> _fields) throws IOException, JSONException, ServiceException {
        boolean gotSoilsResponse = false;
        boolean gotRequest = false;
        boolean gotWind = false;
        boolean gotClimate = false;
        boolean gotAllFields = true;

        fields = _fields;
        if (null == fields) {
            throw new ServiceException("No field names specified for extraction.");
        }

        InputStream zipFile = new FileInputStream(filename);

        try (ZipInputStream zin = new ZipInputStream(zipFile)) {
            ZipEntry entry;

            while ((entry = zin.getNextEntry()) != null) {
                if (entry.getName().contains(SOILS_RETURN) && !gotSoilsResponse) {
                    returnVal = new JSONArray(readInputFile(zin));
                    //soilsReturn = returnVal.getJSONArray(KEY_RESULT).getJSONArray(0);

                    Map<String, JSONObject> inputMap = JSONUtils.preprocess(returnVal);

                    aoa = new soils.AoA(inputMap);

                    if (aoa.getMapUnits().size() <= 0) {
                        throw new ServiceException("Mapunits returned for this AoA did not match expected number of 1.  Mapunit size is: " + aoa.getMapUnits().size());
                    }

                    maxMapUnit = null;
                    for (String mukey : aoa.getMapUnits().keySet()) {
                        MapUnit mapunit = aoa.getMapUnits().get(mukey);
                        if (null == maxMapUnit) {
                            maxMapUnit = mapunit;
                        } else {
                            if (mapunit.muacres() > maxMapUnit.muacres()) {
                                maxMapUnit = mapunit;
                            }
                        }
                    }

                    maxComponent = null;
                    if (null != maxMapUnit) {
                        for (String cokey : maxMapUnit.components().keySet()) {
                            Component component = maxMapUnit.components().get(cokey);
                            if (null == maxComponent) {
                                maxComponent = component;
                            } else {
                                if (component.area_pct() > maxComponent.area_pct()) {
                                    maxComponent = component;
                                }
                            }
                        }
                    } else {
                        throw new ServiceException("No max mapunit was found.");
                    }
                    if (null != maxComponent) {
                        cokey = maxComponent.cokey();
                        JSONObject map_units = inputMap.get(AoA.MAP_UNIT_LIST);
                        
                        gotSoilsResponse = true;
                    }
                }

                if (entry.getName().contains(SOILS_REQUEST) && !gotRequest) {
                    request = new JSONObject(readInputFile(zin));
                    String coordinates = request.getString("coordinates");
                    String type = request.getString("type");

                    if (type.equalsIgnoreCase("point")) {
                        coordinates = coordinates.replace("[", " ");
                        coordinates = coordinates.replace("]", " ");
                        String[] coord = coordinates.split(",");
                        if (coord.length == 2) {
                            longitude = Double.parseDouble(coord[0]);
                            latitude = Double.parseDouble(coord[1]);
                            gotRequest = true;
                        }
                    }
                }

                if (entry.getName().contains(CLIMATE_FILE) && !gotClimate) {
                    climateData = new CligenData(readInputFile(zin));
                    if (!climateData.badClimateData()) {
                        gotClimate = true;
                    }
                }

                if (entry.getName().contains(WIND_FILE) && !gotWind) {
                    windData = new WindGenData(readInputFile(zin));
                    if (!windData.badWindData()) {
                        gotWind = true;
                    }
                }

                if (gotRequest && gotSoilsResponse && gotClimate && gotWind) {
                    break;
                }
            }

            for (String field : fields) {
                switch (field) {
                    case "latitude":
                    case "longitude":
                    case "cokey":
                        //NO_OP:  Already included
                        break;
                    case TableComponentCalculations.CLAYTOTAL_R:
                        fieldData.put(TableComponentCalculations.CLAYTOTAL_R, maxComponent.calculated_claytotal_r());
                        break;

                    case TableComponentCalculations.SILTTOTAL_R:
                        fieldData.put(TableComponentCalculations.SILTTOTAL_R, maxComponent.calculated_silttotal_r());
                        break;

                    case TableComponentCalculations.SANDTOTAL_R_NAME:
                        fieldData.put(TableComponentCalculations.SANDTOTAL_R_NAME, maxComponent.calculated_sandtotal_r());
                        break;

                    case TableComponentCalculations.KFFACT_NAME:
                        fieldData.put(TableComponentCalculations.KFFACT_NAME, maxComponent.calculated_kffact());
                        break;

                    case TableComponentCalculations.OM_R_NAME:
                        fieldData.put(TableComponentCalculations.OM_R_NAME, maxComponent.calculated_om_r());
                        break;

                    case TableComponent.SLOPE_R_NAME:
                        fieldData.put(TableComponent.SLOPE_R_NAME, maxComponent.slope_r());
                        break;

                    case TableComponentCalculations.LENGTH_R_NAME:
                        fieldData.put(TableComponentCalculations.LENGTH_R_NAME, maxComponent.length_r());
                        break;

                    case TableComponentCalculations.TILLAGE_LAYER_CLAY_TOTAL:
                        fieldData.put(TableComponentCalculations.TILLAGE_LAYER_CLAY_TOTAL, maxComponent.calculated_tl_claytotal());
                        break;

                    case "annual_avg_precip":
                        for (int i = 0; i < climateData.yearsInFile(); i++) {
                            fieldData.put("annual_avg_precip_year_" + i + 1, climateData.yearlySummary(i, CligenData.PRCP_INDEX));
                        }
                        break;

                    case "100yr_avg_precip":
                        fieldData.put("100yr_avg_precip", climateData.annualAvgPrecip());
                        break;

                    case "wind_energy_per_year":
                        for (int i = 0; i < windData.yearsInFile(); i++) {
                            fieldData.put("wind_energy_per_year_yr_" + i + 1, windData.yearlyAverage(i));
                        }
                        break;

                    case "wind_energy_100yr_avg":
                        fieldData.put("wind_energy_100yr_avg", windData.simulationAverage());
                        break;

                    default:
                        gotAllFields = false;
                }
            }

            if (!gotRequest || !gotSoilsResponse || !gotAllFields || !gotWind || !gotClimate) {
                ArrayList<String> missingList = new ArrayList<>();

                if (!gotRequest) {
                    missingList.add(" Request JSON");
                }

                if (!gotSoilsResponse) {
                    missingList.add(" Response JSON");
                }

                if (!gotAllFields) {
                    missingList.add(" Soils file and matching requested field names");
                }

                if (!gotWind) {
                    missingList.add(" Wind file" + ((null != windData) ? (":  " + windData.windDataMessages()) : ""));
                }
                if (!gotClimate) {
                    missingList.add(" Climate file" + ((null != climateData) ? (":  " + climateData.cligenDataMessages()) : ""));
                }

                throw new ServiceException("Could not parse all of the service zip file properly: " + filename + ".  " + "Parse isses with: " + missingList);
            }
        }

    }

    protected String readInputFile(ZipInputStream zin) throws IOException {
        String ret_val = "";

        BufferedReader bReader = new BufferedReader(new InputStreamReader(zin));
        StringBuilder fileContent = new StringBuilder();
        String inputStr;

        while ((inputStr = bReader.readLine()) != null) {
            fileContent.append(inputStr + System.lineSeparator());
        }

        ret_val = fileContent.toString();

        return ret_val;
    }

    public double latitude() {
        return latitude;
    }

    public double longitude() {
        return longitude;
    }

    public String cokey() {
        return cokey;
    }

    public void writeCSV(BufferedWriter writer) throws IOException {
        if (null != writer) {

            String outString = latitude + ", " + longitude + ", " + cokey + System.lineSeparator();
            writer.write(outString);
            writer.flush();
        }
    }
}