V1_0.java [src/java/m/wqm/nutappmgtscores] Revision: 8e922c3c53a447e35504683050e7e4745e89230a  Date: Thu Aug 13 09:53:30 MDT 2015
package m.wqm.nutappmgtscores;

/**
 *
 * @author RUMPAL SIDHU
 * @author Shaun Case
 * 
 */
 
import csip.ModelDataService;
import csip.utils.JSONUtils;
import csip.utils.Dates;
import csip.annotations.Polling;
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.Map;
import javax.ws.rs.Path;
import oms3.annotations.Name;
import oms3.annotations.Description;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import java.util.concurrent.TimeUnit;

@Name("WQM-16")
@Description("Nutrient Application Management Scores")
@Path("m/nutappmgtscores/1.0")
@Polling(first = 10000, next = 2000)

public class V1_0 extends ModelDataService {

    //SQL params here for quick modification
    private final String USER = "postgres";
    private final String PASS = "admin";
    private final String HOST = "localhost";
    private final String PORT = "5432";
    private final String DBNAME = "postgres";
    private final String JDBC_TYPE = "jdbc:postgresql://";
    private final String CONNECTION = JDBC_TYPE + HOST + ":" + PORT + "/" + DBNAME;
    private final String CLASS_NAME = "org.postgresql.Driver";

    //Request
    private ArrayList<Input> input;
    //Response
    private ArrayList<Result> result;
    
    //private class variables for this service
    private int AoAId = 0;
    private String p_soil_test_result = "err";
    private ArrayList<Crop> cropList;   
    private String error_msg = "";
    private Connection conn = null;
    private Statement statement = null;    
    
    @Override
    protected void preProcess() throws Exception {
        try{
            Class.forName(CLASS_NAME);            
            conn = DriverManager.getConnection(CONNECTION, USER, PASS);
            statement = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        }
        catch(ClassNotFoundException | SQLException ex) {
            if (ex instanceof SQLException) {
                LOG.info("Did not open database for WQM-16!");
                LOG.info(ex.getMessage());      
                error_msg = "Could not open database for WQM-16!  " + ex.getMessage();
            }
            else{
                error_msg = "Could not instantiate postgres database object: " + ex.getMessage();
            }                                            
        }

        if (error_msg.isEmpty()){
            AoAId = getIntParam("aoa_id", 0);
            p_soil_test_result = getStringParam("p_soil_test_result", "err");
            cropList = new ArrayList<>();

            JSONArray cropIds = getJSONArrayParam("cropIds");
            for (int i = 0; i < cropIds.length(); i++) {
                Map<String, JSONObject> mgtCropId = JSONUtils.preprocess(cropIds.getJSONArray(i));
                cropList.add( new Crop(JSONUtils.getIntParam(mgtCropId, "mgt_crop_id", 0), JSONUtils.getStringParam(mgtCropId, "crop_plant_date", "err"), 
                            JSONUtils.getDoubleParam(mgtCropId, "crop_yield", 0), JSONUtils.getStringParam(mgtCropId, "crop_yield_units", "err"), 
                            JSONUtils.getJSONArrayParam(mgtCropId, "applicationList"), p_soil_test_result, statement));
            }            
            
            ValidateInput();
        }
    }

    @Override
    protected String process() throws Exception {        
        String ret_val = EXEC_OK;
        int n_app_timing_score = 100;
        int p_app_timing_score = 100;
        int app_method_score = -1;
        int n_app_rate_score = 0;
        int p_app_rate_score = 0;
        int this_crop_id = 0;
        String query;
        ResultSet resultSet;
        
        if ( !error_msg.isEmpty()){
            ret_val = error_msg;
        }
        else{
            result = new ArrayList<>();

            try {
                for (Crop crop : cropList) {
                    
                    String crop_type = crop.getCropType();
//////TODO:  Remember to check for errors from the classes....   ///////                    
                    if ( !crop_type.isEmpty() ){                                               
                         //#Update N and P application management rate scores for each crop
                        int[] app_rate_scores = crop.getNutrientApplicationRateScores();
                        if ( !(error_msg = crop.getErrorMsg()).isEmpty() )
                            break;
                        
                        //Cummulative sum of N and P application management scores over all crops for the AoA
                        n_app_rate_score += app_rate_scores[Crop.N_APP_RATE_SCORE];
                        p_app_rate_score += app_rate_scores[Crop.P_APP_RATE_SCORE];
                                                
                        
                        //#Compute N and P application timing scores for the crop and update timing scores for the AoA
                        int [] app_time_scores = crop.getNutrientApplicationTimingScores();
                        if ( !(error_msg = crop.getErrorMsg()).isEmpty() )
                            break;                        

                        //  There is a problem with the logic of the specification here...It does not take into account the actual timing of applications when
                        //  there are mulitple crops and multiple years invovled....these final values are probably not correct.  The "-1" below is placed here
                        //  in an attempt to fix the missing database values problem that also exists with this logic at the nutrient level.
                        if (( app_time_scores[Crop.N_APP_TIMING_SCORE] < n_app_timing_score ) || (n_app_timing_score == -1))
                            n_app_timing_score = app_time_scores[Crop.N_APP_TIMING_SCORE];
                        
                        if (( app_time_scores[Crop.P_APP_TIMING_SCORE] < p_app_timing_score ) || (p_app_timing_score == -1))
                            p_app_timing_score = app_time_scores[Crop.P_APP_TIMING_SCORE];
                        
                        //#If any nutrient application for any crop is not incorporated, the method score for the AoA is zero
                        if ( !crop.allNutrientsIncorporated() ){
                            app_method_score = 0;
                        }                          
                        if ( !(error_msg = crop.getErrorMsg()).isEmpty() )
                            break;                        
                    }
                    else{
                        ret_val = error_msg = "Cannot get crop_type. " + crop.getErrorMsg();
                    }
                }
                
                //  If all crops' nutrients were incorporated this value will still be -1
                if ( app_method_score == -1 ){
                    query = "SELECT app_mgt_score from wqm_nutrient_application_mgt_scores WHERE app_mgt_kind='Method' AND app_mgt_factor='incorporate';";
                    resultSet = statement.executeQuery(query);
                    if ( resultSet.first() ){
                        app_method_score = resultSet.getInt("app_mgt_score");
                    }                                                                
                }
                
                //#Compute application management scores for nitrogen in groundwater, nitrogen in surface water, and phosphorus in surface water
                int nleach_app_mgt_score = n_app_rate_score + n_app_timing_score + app_method_score;
                int nsurf_app_mgt_score = n_app_rate_score + n_app_timing_score + app_method_score;
                int psurf_app_mgt_score = p_app_rate_score + p_app_timing_score + app_method_score;
                m.wqm.nutappmgtscores.Result result1 = new m.wqm.nutappmgtscores.Result(AoAId, nleach_app_mgt_score, nsurf_app_mgt_score, psurf_app_mgt_score, n_app_rate_score, n_app_timing_score, p_app_rate_score, p_app_timing_score, app_method_score);
                result.add(result1);                    
                
                conn.close();
            } catch (SQLException se) {
                    LOG.info("Did not open database for WQM-16!");
                    LOG.info(se.getMessage());
                    ret_val += se.getMessage();                    
                }catch (Exception ex ){
                    ret_val += ex.getMessage();
            } finally {
                if (statement != null) {
                    statement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
        }       
        return (error_msg.isEmpty()? EXEC_OK:error_msg);
    }

    @Override
    //writing the results back to JSON
    protected void postProcess() throws Exception {
        JSONArray resultArr = new JSONArray();
        for (m.wqm.nutappmgtscores.Result rs1 : result) {
            JSONArray tmpArr = new JSONArray();
            tmpArr.put(JSONUtils.dataDesc("AoAId", rs1.getAoAId(), "Area of Analysis Identifier"));
            tmpArr.put(JSONUtils.dataDesc("nleach_app_mgt_score", rs1.getNleachAppMgtScore(), "Nitrogen Application Management Score for Mitigating Leaching Loss Potential"));
            tmpArr.put(JSONUtils.dataDesc("nsurf_app_mgt_score", rs1.getNsurfAppMgtScore(), "Nitrogen Application Management Score for Mitigating Surface Runoff Loss Potential"));
            tmpArr.put(JSONUtils.dataDesc("psurf_app_mgt_score", rs1.getPsurfAppMgtScore(), "Phosphorus Application Management Score for Mitigating Surface Runoff Loss Potential"));
            tmpArr.put(JSONUtils.dataDesc("n_app_rate_score", rs1.getnAppRateScore(), "Nitrogen Application Rate Mitigation Score"));
            tmpArr.put(JSONUtils.dataDesc("n_app_timing_score", rs1.getnAppTimingScore(), "Nitrogen Application Timing Mitigation Score"));
            tmpArr.put(JSONUtils.dataDesc("p_app_rate_score", rs1.getpAppRateScore(), "Phosphorus Application Rate Mitigation Score"));
            tmpArr.put(JSONUtils.dataDesc("p_app_timing_score", rs1.getpAppTimingScore(), "Phosphorus Application Timing Mitigation Score"));
            tmpArr.put(JSONUtils.dataDesc("app_method_score", rs1.getAppMethodScore(), "Nutrient Application Method Mitigation Score"));
            resultArr.put(JSONUtils.dataDesc("Nutrition Application Summary", tmpArr, "Nutrition Application Summary"));
        }
        putResult("Result", resultArr);
    }
    
    private boolean ValidateInput(){
        for( Crop tCrop : cropList )
            if ( !tCrop.validate() )
                error_msg += "; " + tCrop.getErrorMsg();
      
      return (error_msg.isEmpty());    
    }
}