
package usda.weru.remoteDataAccess.csip.polygon.soil;

import csip.utils.JSONUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Map;
import javax.swing.JOptionPane;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import usda.weru.remoteDataAccess.csip.CsipInterfaceTreeMap;
import usda.weru.remoteDataAccess.csip.polygon.CsipInterfacePolygon;
import usda.weru.remoteDataAccess.exceptions.RdaConnectException;
import usda.weru.util.ConfigData;
import static usda.weru.util.Util.getProperty;

/**
 *
 * @author mhaas
 */
public class CsipInterfaceSoil extends CsipInterfacePolygon {

    private static final Logger LOGGER = LogManager.getLogger(CsipInterfaceSoil.class);

    CsipInputContSoilCachingSupport cacheSupport;

    public CsipInterfaceSoil() {
        super();
        cacheSupport = null;
    }

    public void setCacheSupport(CsipInputContSoilCachingSupport cacheSupport) {
        this.cacheSupport = cacheSupport;
    }

    @Override
    protected void addParmsCatalog(JSONObject modelParms) throws JSONException {
        JSONArray jsonParmsArr = modelParms.getJSONArray("parameter");

        JSONArray parmArr = new JSONArray();
        JSONObject parmObj = new JSONObject();

        if (polygon == null) {
            throw new RuntimeException("polygon not set in " + interfaceName + " addParmsCatalog");
        }

        parmObj.put("name", "aoa_geometry");
        parmObj.put("type", "Polygon");

        parmArr.put(new JSONArray().put(polygon.get(0).x).put(polygon.get(0).y));
        parmArr.put(new JSONArray().put(polygon.get(1).x).put(polygon.get(1).y));
        parmArr.put(new JSONArray().put(polygon.get(2).x).put(polygon.get(2).y));
        parmArr.put(new JSONArray().put(polygon.get(3).x).put(polygon.get(3).y));
        parmArr.put(new JSONArray().put(polygon.get(0).x).put(polygon.get(0).y));

        parmObj.put("coordinates", parmArr);

        jsonParmsArr.put(parmObj);
    }

    @Override
    protected String getCatalogUrl() {
        return ConfigData.getDefault().getData("CD-WS-csip-soils-params-endpoint");
    }

    @Override
    protected ArrayList<String> parseResultCatalog(JSONObject modelResult) throws JSONException {
        ArrayList<String> retList = new ArrayList<>();
        String muFullname;
        JSONArray jArrayMunitsList;
        JSONArray jArrayCompList;
        Map<String, JSONObject> resultsMap;
        Map<String, JSONObject> muMap;
        Map<String, JSONObject> compMap;

        try {
            //System.out.print(formatResults(modelResult,4));
            resultsMap = JSONUtils.preprocess(modelResult.getJSONArray("result"));
            jArrayMunitsList = JSONUtils.getJSONArrayParam(resultsMap, "Map Units");

            extendedReturnTree = new CsipInterfaceTreeMap();

            if (cacheSupport != null) {
                cacheSupport.loadSoilCacheProperties();
            }

            // step through returned map units
            for (int i = 0; i < jArrayMunitsList.length(); i++) {
                muMap = JSONUtils.preprocess(jArrayMunitsList.getJSONArray(i));
                String muname = JSONUtils.getStringParam(muMap, "muname", "");
                //String mukey = JSONUtils.getStringParam(muMap, "mukey", "");
                String muSym = JSONUtils.getStringParam(muMap, "musym", "");
                jArrayCompList = JSONUtils.getJSONArrayParam(muMap, "Components");
                muFullname = muSym + " - " + muname;

                // this survey name is merely a place holder.
                // the full survey name is known only from the ifc file.
                // this place holder will be replaced later when the ifc file
                // is cached.
                String surveyName = JSONUtils.getStringParam(muMap, "areasymbol", "");

                CsipInterfaceTreeMap extendedReturnComps = new CsipInterfaceTreeMap();
                for (int j = 0; j < jArrayCompList.length(); j++) {
                    compMap = JSONUtils.preprocess(jArrayCompList.getJSONArray(j));
                    String compName = JSONUtils.getStringParam(compMap, "compname", "");
                    String cokeyRef = JSONUtils.getStringParam(compMap, "cokey", "");
                    String compPercent = JSONUtils.getStringParam(compMap, "comppct_r", "");
                    if (compPercent.indexOf('.') > 0) {
                        compPercent = compPercent.substring(0, compPercent.indexOf('.'));
                    }
                    CsipInterfaceTreeMap cokeyRefMap = new CsipInterfaceTreeMap();
                    cokeyRefMap.put(cokeyRef, null);
                    CsipInterfaceTreeMap cokeyMap = new CsipInterfaceTreeMap();
                    cokeyMap.put("cokey", cokeyRefMap);
                    String compFileName = compPercent + " - " + compName + ".ifc";
                    extendedReturnComps.put(compFileName, cokeyMap);

                    String fullname = surveyName + "\\" + muFullname + "\\" + compFileName;
                    if (cacheSupport != null) {
                        surveyName = cacheSupport.updateName(surveyName);
                        fullname = surveyName + "\\" + muFullname + "\\" + compFileName;
                        fullname = cacheSupport.updateName(fullname);
                    }

                    retList.add(fullname);
                }
                extendedReturnTree.put(surveyName + "\\" + muFullname, extendedReturnComps);
            }
        } catch (JSONException ex) {
            LOGGER.log(Level.INFO, ex.getMessage());
        }

        return retList;
    }

    /**
     * Utilized when a user selects a soil from the CSIP Soil Service.
     * 
     * @param name - name of the soil file
     * @param parentPath - folder location of soil file
     * @return - the soil file data
     * @throws RdaConnectException - when the modelPrms can't get loaded or the results fail
     */
    @Override
    public File callCsipGetRecord(String name, String parentPath) throws RdaConnectException {
        JSONObject modelParms;
        JSONObject modelResult;
        File file = null;

        this.name = name;
        this.parentPath = parentPath;
        CsipInterfaceTreeMap fileMap = extendedReturnTree.get(parentPath);
        String coKey = "";
        try {
            fileMap = fileMap.get(name);
            fileMap = fileMap.get("cokey");
            coKey = fileMap.firstKey();
        } catch (NullPointerException e) {
            System.err.println("File does not appear in the File Map:" + name);
            throw (new RdaConnectException("Unable to get CSIP soil data from fileMap", null, this.interfaceName));
        }

        try {
            modelParms = newCsipJson();
            addParmsRecord(modelParms, coKey, null);
            modelResult = doCsipPost(ConfigData.getDefault().getData("CD-WS-csip-soils-data-endpoint"), modelParms);

            if (modelResult.getJSONObject("metainfo").get("status").equals("Failed")) {
                String error = "An error occured while retrieving the CSIP Soil Data of : " + this.name + "\n\n ERROR: '" 
                        + modelResult.getJSONObject("metainfo").get("error")
                        + "'\n";
                JOptionPane.showMessageDialog(null, error, "Failed to get Model Results", JOptionPane.ERROR_MESSAGE);
                throw new RdaConnectException();
            }

            file = parseResultRecord(modelResult, name);
        } catch (Exception ex) {
            LOGGER.log(Level.INFO, ex.getMessage());
            throw (new RdaConnectException("Unable to get CSIP soil data", ex, this.interfaceName));
        }

        return file;
    }

    @Override
    protected void addParmsRecord(JSONObject modelParms, String name, String path) throws JSONException {
        JSONArray jsonParmsArr = modelParms.getJSONArray("parameter");

        jsonParmsArr.put(new JSONObject().put("name", "cokey").put("value", name));
    }

    @Override
    protected File parseResultRecord(JSONObject modelResults, String recordName) throws JSONException {

        File outFile = null;
        File tempFile;
        try {
            tempFile = downloadCsipResults(modelResults, new File(getProperty("project.directory")));
            if (!recordName.endsWith(".ifc")) {
                recordName += ".ifc";
            }
            outFile = new File(destinationPath.toString(), recordName);
            Files.move(tempFile.toPath(), outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException ex) {
            LOGGER.log(Level.INFO, "JSON error: {0}", ex.getMessage());
            throw (new JSONException("Failed to convert / write LMOD data: cannot write temp file: " + recordName));
        }
        return outFile;
    }
}
