V1_0.java [src/java/m/wqm/wqm06_scsednutsrp] Revision:   Date:
package m.wqm.wqm06_scsednutsrp;

import csip.ModelDataService;
import csip.api.server.ServiceException;
import java.util.ArrayList;
import javax.ws.rs.Path;
import csip.annotations.Description;
import csip.annotations.Name;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import csip.utils.JSONUtils;
import java.util.Map;
import org.codehaus.jettison.json.JSONException;

/**
 *
 * @author Srinivas
 * @author Rumpal Sidhu
 * @author Shaun Case
 */
@Name("WQM-06: Sediment and Nutrient Soil Runoff Potential (SedNutSRP)")
@Description("This service computes sediment and nutrient soil runoff potential for soil components in an area of analysis, and then compute soil runoff potential representing the area of analysis. The service primarily will consume data from the WQM-2 soil attributes service to compute soil runoff potential values for subsequent use by WQM-13 to compute threshold treatment level scores.")
@Path("m/scsednut_srp/1.0")
@Deprecated
public class V1_0 extends ModelDataService {

    private final String[] srpList = new String[]{"LOW", "MODERATE", "MODERATELY HIGH", "HIGH"};
    //Request
    private int aoaId;
    private ArrayList<V1_0.SoilComponent> soilComponentList;
    //Result
    private String aoaSrp;

    @Override
    protected void preProcess() throws ServiceException {
        soilComponentList = new ArrayList<>();
        try {
            aoaId = parameter().getInt("AoAId");
            JSONArray groups = parameter().getJSONArray("soilcomponents");
            for (int i = 0; i < groups.length(); i++) {
                Map<String, JSONObject> group = JSONUtils.preprocess(groups.getJSONArray(i));
                V1_0.SoilComponent input = new V1_0.SoilComponent(
                        JSONUtils.getStringParam(group, "cokey", "err"),
                        JSONUtils.getDoubleParam(group, "aoa_comp_area", 0),
                        JSONUtils.getStringParam(group, "aoa_comp_hsg", "err"),
                        JSONUtils.getStringParam(group, "aoa_comp_taxorder", "err"),
                        JSONUtils.getDoubleParam(group, "aoa_comp_kfact", 0),
                        JSONUtils.getDoubleParam(group, "aoa_comp_slope", 0),
                        JSONUtils.getDoubleParam(group, "aoa_comp_coarse_frag", 0),
                        JSONUtils.getBooleanParam(group, "aoa_comp_drained", false),
                        JSONUtils.getStringParam(group, "aoa_comp_wtbl", "err"),
                        JSONUtils.getBooleanParam(group, "aoa_comp_hwt_lt_24", false));
                soilComponentList.add(input);
            }
        } catch (JSONException ex) {
            throw new ServiceException("Could not process input JSON: ", ex );
        }
    }

    @Override
    protected void doProcess() throws ServiceException {
        this.computeSedNutSRP();
        this.computeAoaSrp();
    }

    @Override
    protected void postProcess() throws Exception {
        results().put("aoa_id", aoaId, "Area of analysis identifier");
        results().put("aoa_srp", aoaSrp, "Soil runoff potential for the area of analysis");
        JSONArray resultArr = new JSONArray();
        for (V1_0.SoilComponent sc : soilComponentList) {
            JSONArray array = new JSONArray();
            array.put(JSONUtils.dataDesc("cokey", sc.getCokey(), "Soil component key"));
            array.put(JSONUtils.dataDesc("comp_srp", sc.getSrp(), "Soil runoff potential for soil component"));
            resultArr.put(JSONUtils.dataDesc("soil_component", array, "Soil Component"));
        }
        results().put("soil_components", resultArr, "List of Soil Components");
    }

    //Compute sediment and nutrient soil runoff potential for each soil component in the AoA
    private void computeSedNutSRP() throws ServiceException {
        int comp_srp_number = -2;
        for (V1_0.SoilComponent ip : soilComponentList) {
            switch (ip.getHsg()) {
                case "A":
                    comp_srp_number = 0;
                    break;
                case "B":
                    comp_srp_number = this.computeSRPHsgB(ip);
                    break;
                case "C":
                    comp_srp_number = this.computeSRPHsgC(ip);
                    break;
                case "D":
                    if ((ip.getWtbl().equals("Perched")
                            || ip.getWtbl().equals("Apparent")) || ip.isHwt_lt_24()) {
                        comp_srp_number = 3;
                    } else if (ip.getSlope() < 2 && ip.getKfact() < 0.28) {
                        comp_srp_number = 0;
                    } else if (ip.getSlope() < 2 && ip.getKfact() >= 0.28) {
                        comp_srp_number = 1;
                    } else if (ip.getSlope() >= 2 && ip.getSlope() <= 4) {
                        comp_srp_number = 2;
                    } else if (ip.getSlope() > 4) {
                        comp_srp_number = 3;
                    }
                    break;
                case "A/D":
                    if (ip.isDrained()) {
                        comp_srp_number = 0;
                    } else {
                        comp_srp_number = this.computeSRPHsgD(ip);
                    }
                    break;
                case "B/D":
                    if (ip.isDrained()) {
                        comp_srp_number = this.computeSRPHsgB(ip);
                    } else {
                        comp_srp_number = this.computeSRPHsgD(ip);
                    }
                    break;
                case "C/D":
                    if (ip.isDrained()) {
                        comp_srp_number = this.computeSRPHsgC(ip);
                    } else {
                        comp_srp_number = this.computeSRPHsgD(ip);
                    }
                    break;
            }
            if (comp_srp_number != -1 && comp_srp_number != -2) {
                ip.setSrpNumber(comp_srp_number);
                ip.setSrp(srpList[comp_srp_number]);
            } else {
                throw new ServiceException("Error in calculating SedNutSRP:  comp_srp_number could not be created.");
            }
        }
    }

    public int computeSRPHsgB(V1_0.SoilComponent ip) {
        int srp_number = -1;
        if (ip.getSlope() < 4) {
            srp_number = 0;
        } else if (ip.getSlope() >= 4 && ip.getSlope() <= 6 && ip.getKfact() < 0.32) {
            srp_number = 1;
        } else if (ip.getSlope() >= 4 && ip.getSlope() <= 6 && ip.getKfact() >= 0.32) {
            srp_number = 2;
        } else if (ip.getSlope() > 6) {
            srp_number = 3;
        }
        return srp_number;
    }

    public int computeSRPHsgC(V1_0.SoilComponent ip) {
        int srp_number = -1;
        if (ip.getSlope() < 2) {
            srp_number = 0;
        } else if (ip.getSlope() >= 2 && ip.getSlope() <= 6 && ip.getKfact() < 0.28) {
            srp_number = 1;
        } else if (ip.getSlope() >= 2 && ip.getSlope() <= 6 && ip.getKfact() >= 0.28) {
            srp_number = 2;
        } else if (ip.getSlope() > 6) {
            srp_number = 3;
        }
        return srp_number;
    }

    public int computeSRPHsgD(V1_0.SoilComponent ip) {
        int srp_number = -1;
        if (ip.getSlope() < 2 && ip.getKfact() < 0.28) {
            srp_number = 0;
        } else if (ip.getSlope() < 2 && ip.getKfact() >= 0.28) {
            srp_number = 1;
        } else if (ip.getSlope() >= 2 && ip.getSlope() <= 4) {
            srp_number = 2;
        } else if ((ip.getSlope() > 4) || ((ip.getWtbl().equals("Perched")
                || ip.getWtbl().equals("Apparent")) || ip.isHwt_lt_24())) {
            srp_number = 3;
        }
        return srp_number;
    }

    //Compute weighted average nutrient soil leaching potential for the AoA
    void computeAoaSrp() {
        double srpProduct = 0;
        double aoaArea = 0;
        for (V1_0.SoilComponent sc : soilComponentList) {
            srpProduct += (sc.getSrpNumber() * sc.getArea());
            aoaArea += sc.getArea();
        }
        double aoaSrpFract = srpProduct / aoaArea;

        if (aoaSrpFract <= 0.50) {
            aoaSrp = "LOW";
        } else if (aoaSrpFract > 0.50 && aoaSrpFract <= 1.50) {
            aoaSrp = "MODERATE";
        } else if (aoaSrpFract > 1.50 && aoaSrpFract <= 2.50) {
            aoaSrp = "MODERATELY HIGH";
        } else {
            aoaSrp = "HIGH";
        }
    }

    public class SoilComponent {

        private String cokey;
        private double area;
        private String hsg;
        private String taxorder;
        private double kfact;
        private double slope;
        private double coarseFrag;
        private boolean drained;
        private String wtbl;
        private boolean hwt_lt_24;

        private int srpNumber;
        private String srp;

        public SoilComponent(String cokey, double area, String hsg, String taxorder,
                double kfact, double slope, double coarseFrag, boolean drained,
                String wtbl, boolean hwt_lt_24) throws csip.api.server.ServiceException {
            this.cokey = cokey;
            this.area = area;
            this.hsg = hsg;
            this.taxorder = taxorder;
            this.kfact = kfact;
            this.slope = slope;
            this.coarseFrag = coarseFrag;
            this.drained = drained;
            this.wtbl = wtbl;
            this.hwt_lt_24 = hwt_lt_24;

            if (this.hsg.equalsIgnoreCase("err") || this.hsg.isEmpty()) {
                throw new ServiceException("Missing HSG value for this soil component: " + cokey);
            }
            
            if ( this.taxorder.isEmpty() || this.taxorder.contains(" ") ){
                throw new ServiceException("Missing value for taxorder for this soil component: " + cokey);
            }
        }

        //Getter Methods
        public String getCokey() {
            return this.cokey;
        }

        public double getArea() {
            return this.area;
        }

        public String getHsg() {
            return this.hsg;
        }

        public String getTaxorder() {
            return this.taxorder;
        }

        public double getKfact() {
            return this.kfact;
        }

        public double getSlope() {
            return this.slope;
        }

        public double getCoarseFrag() {
            return this.coarseFrag;
        }

        public boolean isDrained() {
            return this.drained;
        }

        public String getWtbl() {
            return this.wtbl;
        }

        public boolean isHwt_lt_24() {
            return this.hwt_lt_24;
        }

        public int getSrpNumber() {
            return this.srpNumber;
        }

        public String getSrp() {
            return this.srp;
        }

        //Setter Methods
        public void setSrpNumber(int number) {
            this.srpNumber = number;
        }

        public void setSrp(String value) {
            this.srp = value;
        }

    }

}