Displaying differences for changeset
 
display as  

src/java/m/wqm/nutappmgtscores/Crop.java

@@ -3,35 +3,270 @@
 /**
  *
  * @author RUMPAL SIDHU
+ * @author Shaun Case
  */
+import csip.utils.Dates;
+import csip.utils.JSONUtils;
+
 import java.util.Date;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONObject;
 
 public class Crop {
 
+    //  Inner Classes
+    class NutrientApplication {
+    
+        class Nutrient {
+            private String error_msg = "";
+            private String nutrientApplied;
+            private double applicationRate;
+
+            public Nutrient(String nutrientApplied, double applicationRate) {
+                this.nutrientApplied = nutrientApplied;
+                this.applicationRate = applicationRate;
+                
+                if ( !nutrientApplied.equals("Nitrogen") && !nutrientApplied.equals("Phosphorus") ) {
+                    this.error_msg += "Invalid input data.  Bad nutrient name";
+                } 
+            }
+
+            //Get Methods
+            public String getNutrientApplied() {
+                return this.nutrientApplied;
+            }
+
+            public double getApplicationRate() {
+                return this.applicationRate;
+            }
+            
+            public String getErrorMsg(){
+                return this.error_msg;
+            }      
+
+            public Boolean validate(){
+                return (this.error_msg.isEmpty());
+            }
+       }
+
+        private String error_msg = "";
+        private String applicationDate;
+        private boolean incorporated;
+        private ArrayList<Crop.NutrientApplication.Nutrient> nutrientList;
+        private int appMethodScore = 0; 
+        private int[] nutrientTimingScores = new int[2];
+
+        public NutrientApplication(String applicationDate, String incorporated, JSONArray applications) {
+            this.applicationDate = applicationDate;
+            nutrientTimingScores[N_APP_TIMING_SCORE] = nutrientTimingScores[P_APP_TIMING_SCORE] = -1;
+           
+            if ( ( !"true".equalsIgnoreCase(incorporated) ) && ( !"false".equalsIgnoreCase(incorporated) ) ) {
+                this.error_msg += "Invalid incorporation value for nutrient application " + applicationDate;
+            }
+            else{
+                this.incorporated = Boolean.parseBoolean(incorporated);               
+                nutrientList = new ArrayList<>();
+             
+                try{
+                    for (int k = 0; k < applications.length(); k++) {
+                        Map<String, JSONObject> nutrient = JSONUtils.preprocess(applications.getJSONArray(k));              
+                        nutrientList.add(new Crop.NutrientApplication.Nutrient(JSONUtils.getStringParam(nutrient, "nutrient_applied", "err"), JSONUtils.getDoubleParam(nutrient, "application_rate", 0)));
+                    }                 
+                }
+                catch(Exception ex){
+                    this.error_msg += "Cannot process applied nutrient list.  " + ex.getMessage();
+                }                   
+            }
+       }
+
+        //Get Methods
+        public Date getApplicationDate() throws Exception {
+            String[] parse = this.applicationDate.split("-");
+            //Some say should set to use UTC first...do we wanna do that?
+            Calendar date = new GregorianCalendar(Integer.parseInt(parse[0]),
+                    Integer.parseInt(parse[1]) - 1, Integer.parseInt(parse[2]));
+            return date.getTime();
+        }
+
+        public boolean isIncorporated() {
+            return this.incorporated;
+        }
+
+        public ArrayList getNutrientList() {
+            return this.nutrientList;
+        }
+       
+        public String getErrorMsg(){
+            for (Crop.NutrientApplication.Nutrient nutrient : this.nutrientList ){
+                this.error_msg += nutrient.getErrorMsg();
+            }
+            return this.error_msg;
+        }    
+        
+        public Boolean validate(){            
+            for( Crop.NutrientApplication.Nutrient nutrient : nutrientList )
+                if ( !nutrient.validate() )
+                    this.error_msg += "; " + nutrient.getErrorMsg();
+
+            return (this.error_msg.isEmpty());
+        } 
+        
+        public int[] getNutrientTimingScores( Boolean split ){
+            if ( ( nutrientTimingScores[N_APP_TIMING_SCORE] < 0 ) || ( nutrientTimingScores[P_APP_TIMING_SCORE] < 0 ) ){
+                int tempNScore = 100;
+                int tempPScore = 100;
+                ResultSet resultSet;
+                
+                for ( Crop.NutrientApplication.Nutrient nutrient : nutrientList ){
+                    int app_timing_score;
+                            
+                    try{
+                        long app_day_diff = Dates.diffInMillis( getCropPlantDate(), getApplicationDate() );
+                        app_day_diff = TimeUnit.MILLISECONDS.toDays(app_day_diff);
+
+                        String query = "SELECT app_mgt_score FROM wqm_nutrient_application_mgt_scores WHERE nutrient='";
+
+                        query += nutrient.getNutrientApplied() + "' ";
+                        query += "AND app_mgt_kind='Timing' AND app_mgt_factor='" + (split? "split":"nosplit") + "'AND days_fr_plant_1 <= " + app_day_diff + "AND days_fr_plant_2 > " + app_day_diff + ";";
+                        
+                        resultSet = statement.executeQuery(query);
+                        if ( !resultSet.first() ) {
+                            app_timing_score = -1;
+                        }
+                        else {
+                            app_timing_score = resultSet.getInt("app_mgt_score");
+                        }
+                        
+                        switch (nutrient.getNutrientApplied())
+                        {
+                            case "Nitrogen":
+                                if ( app_timing_score < tempNScore )
+                                    tempNScore = app_timing_score;                                
+                                break;
+                                
+                            case "Phosphorus":
+                                if ( app_timing_score < tempPScore )
+                                    tempPScore = app_timing_score;                                
+                                break;
+                                
+                            default:
+                                this.error_msg += "Invalid nutrient name specified";
+                        }                        
+                    }
+                    catch (Exception ex){
+                        this.error_msg += "Cannot calculate nutrient application timing scores: " + ex.getMessage();
+                    }       
+                    
+                    if ( this.error_msg.isEmpty() ){
+                        nutrientTimingScores[N_APP_TIMING_SCORE] = tempNScore;
+                        nutrientTimingScores[P_APP_TIMING_SCORE] = tempPScore;
+                    }                        
+                }                                
+            }
+            
+            return nutrientTimingScores;
+        }
+        
+        public Boolean allNutrientsIncorporated(){
+            return this.incorporated;
+        }
+   }
+    
+    
+    //  Begin Crop Class
+    public static final int N_APP_RATE_SCORE = 0;
+    public static final int P_APP_RATE_SCORE = 1;
+    public static final int N_APP_TIMING_SCORE = 0;
+    public static final int P_APP_TIMING_SCORE = 1;
+    
     private int mgtCropId;
     private String cropPlantDate;
+    private Date plantDate;
     private double cropYield;
     private String cropYieldUnits;
-    private ArrayList<Nutrient> nutrientApplicationList;
-
+    private ArrayList<Crop.NutrientApplication> nutrientApplicationList;
+    private m.wqm.nutappmgtscores.Result calc_result;
+    private Statement statement;
+    private String cropType = "";
+    private String error_msg = "";
+    private Boolean multipleNutrientApplication = false;
+    private int n_app_timing_score = 100;
+    private int p_app_timing_score = 100;
+    private int app_method_score = 0;
+    private int[] appRateScore = new int[2];
+    private int[] appNutrientTimingScore = new int[2];
+    private String pSoilTestResult = "None";
+  
     public Crop(int mgtCropId,String cropPlantDate, double cropYield,
-            String cropYieldUnits, ArrayList<Nutrient> nutrientApplicationList) {
+                String cropYieldUnits, JSONArray applicationList, String pSoilTestResult, Statement statement){
         this.mgtCropId = mgtCropId;
         this.cropPlantDate = cropPlantDate;
         this.cropYield = cropYield;
         this.cropYieldUnits = cropYieldUnits;
-        this.nutrientApplicationList = nutrientApplicationList;
+        this.statement = statement;
+        this.pSoilTestResult = pSoilTestResult;
+     
+        nutrientApplicationList = new ArrayList<>();
+        
+        try{
+            plantDate = getCropPlantDate();
+            for (int j = 0; j < applicationList.length(); j++) {
+                Map<String, JSONObject> application = JSONUtils.preprocess(applicationList.getJSONArray(j));
+                nutrientApplicationList.add(new Crop.NutrientApplication(JSONUtils.getStringParam(application, "nutrient_application_date", "err"), JSONUtils.getStringParam(application, "incorporated", ""), JSONUtils.getJSONArrayParam(application, "application")));              
+            }            
+        }
+        catch( Exception ex){
+           error_msg += "Cannot process list of applied nutrients.  " + ex.getMessage(); 
+        }
+
+        multipleNutrientApplication = (nutrientApplicationList.size() > 1);           
+        this.appRateScore[N_APP_RATE_SCORE] = this.appRateScore[P_APP_RATE_SCORE] = -1;
+        this.appNutrientTimingScore[N_APP_TIMING_SCORE] = this.appNutrientTimingScore[P_APP_TIMING_SCORE] = -1;
     }
 
-    //Getter methods
+    //Get methods
     public int getMgtCropId() {
         return this.mgtCropId;
     }
 
-    public Date getCropPlantDate() throws Exception {
+    public String getErrorMsg(){
+        for ( Crop.NutrientApplication nutrientApplied: this.nutrientApplicationList ){
+            error_msg += nutrientApplied.getErrorMsg();
+        }
+        return error_msg;
+    }
+    
+    public String getCropType(){
+        if ( (cropType.isEmpty()) && (error_msg.isEmpty()) ){
+            ResultSet resultSet;                   
+            String query = "SELECT wqm_crop_type FROM wqm_crops WHERE wqm_crop_id=" + mgtCropId + " AND wqm_crop_units='" + cropYieldUnits + "';";
+            try{
+                resultSet = statement.executeQuery(query);
+                if (!resultSet.first()){
+                    error_msg += "That crop, " + mgtCropId + ", and crop yield units, "+ cropYieldUnits + ", was not found in the database";
+                }
+                else{                        
+                    cropType = resultSet.getString("wqm_crop_type");   
+                }
+            }
+            catch( Exception ex ) {
+                error_msg += ex.getMessage();
+            }
+        }
+        return cropType;
+    }
+    public final Date getCropPlantDate() throws Exception {
         String[] parse = this.cropPlantDate.split("-");
         Calendar date = new GregorianCalendar(Integer.parseInt(parse[0]),
                 Integer.parseInt(parse[1]) - 1, Integer.parseInt(parse[2]));
@@ -49,4 +284,186 @@
     public ArrayList getNutrientApplicationList() {
         return this.nutrientApplicationList;
     }
+    
+    public int[] getNutrientApplicationRateScores(){
+        if ( ( appRateScore[N_APP_RATE_SCORE] <0 ) || ( appRateScore[P_APP_RATE_SCORE] <0 ) ) {
+            try{
+                if ( nutrientApplicationList.isEmpty() ){
+                    ResultSet resultSet;                   
+
+                    appRateScore[N_APP_RATE_SCORE] = appRateScore[P_APP_RATE_SCORE] = 0;            
+                    String queryNitrogen = "SELECT app_mgt_score FROM wqm_nutrient_application_mgt_scores WHERE nutrient='Nitrogen' AND app_mgt_kind='Rate' AND app_mgt_factor='none';";
+                    String queryPhosporous = "SELECT app_mgt_score FROM wqm_nutrient_application_mgt_scores WHERE nutrient='Phosphorus' AND app_mgt_kind='Rate' AND app_mgt_factor='none' AND soil_test_result='" + pSoilTestResult + "';";
+
+                    resultSet = statement.executeQuery(queryNitrogen);
+                    if ( resultSet.first() )
+                        appRateScore[N_APP_RATE_SCORE] = resultSet.getInt("app_mgt_score");
+
+                    resultSet = statement.executeQuery(queryPhosporous);
+                    if ( resultSet.first() )
+                        appRateScore[P_APP_RATE_SCORE] = resultSet.getInt("app_mgt_score");  
+                }
+                else{
+                    ResultSet resultSet;
+                    String query;
+                    
+                    double nrate = 0.0;
+                    double prate = 0.0;
+
+                    double wqm_crop_pct_dmat = 0.0;
+                    double wqm_pct_nitrogen = 0.0;
+                    double wqm_pct_phosphorus = 0.0;
+                    double wqm_crop_yield = 0.0;
+                                        
+                    int ncrop_app_rate_score = 0;
+                    int pcrop_app_rate_score = 0;                       
+                    
+                    for (Crop.NutrientApplication nutrient : nutrientApplicationList) {
+                        ArrayList<Crop.NutrientApplication.Nutrient> nutrientAppliedList = nutrient.getNutrientList();
+                        for (Crop.NutrientApplication.Nutrient nApplied : nutrientAppliedList) {
+                            switch(nApplied.getNutrientApplied()){  //Note:  This switch requires JDK 1.7 or above
+                                case "Nitrogen":
+                                    nrate = nrate + nApplied.getApplicationRate();
+                                    break;
+                                case "Phosphorus":
+                                    prate = prate + nApplied.getApplicationRate();
+                                    break;                                                                                                 
+                            }
+                        }
+                    }
+                    
+                    query = "SELECT wqm_crop_pct_dmat, wqm_pct_nitrogen, wqm_pct_phosphorus, wqm_crop_yield FROM wqm_crops WHERE wqm_crop_id=" + mgtCropId + ";";
+                    resultSet = statement.executeQuery(query);
+                    if (resultSet.first()) {
+                        wqm_crop_pct_dmat = resultSet.getDouble("wqm_crop_pct_dmat");
+                        wqm_pct_nitrogen = resultSet.getDouble("wqm_pct_nitrogen");
+                        wqm_pct_phosphorus = resultSet.getDouble("wqm_pct_phosphorus");
+                        wqm_crop_yield = resultSet.getDouble("wqm_crop_yield");
+                        
+                        //  Added wqm_crop_yield to the calc per bug #462839
+                        double n_growout = cropYield * wqm_crop_yield * wqm_crop_pct_dmat * wqm_pct_nitrogen;
+                        double p_growout = cropYield * wqm_crop_yield * wqm_crop_pct_dmat * wqm_pct_phosphorus;
+
+                        double n_remove_ratio = nrate / n_growout;
+                        double p_remove_ratio = prate / p_growout;      
+
+                        query = "SELECT app_mgt_score FROM wqm_nutrient_application_mgt_scores WHERE nutrient='" + "Nitrogen" + "' AND app_mgt_kind='" + "Rate" + "' AND app_mgt_factor=";
+
+                        switch( cropType ){
+                            case "Small Grain":  //Note the case conflicts here...
+                                query += "'small grain'";
+                                break;
+
+                            default:  
+                                query += "'none'";
+                        }   
+                        query += " AND remove_ratio_1 <= " + n_remove_ratio + "AND remove_ratio_2 > " + n_remove_ratio + ";";
+                        
+                        resultSet = statement.executeQuery(query);
+                        if (resultSet.first()) {
+                            ncrop_app_rate_score = resultSet.getInt("app_mgt_score");
+                        }
+                        else{
+                            appRateScore[N_APP_RATE_SCORE] = appRateScore[P_APP_RATE_SCORE] = 0;
+                        }
+                            
+                        pcrop_app_rate_score = -1;
+                        //#Compute P application management rate scores based on removal ratio and soil test result
+                        switch (pSoilTestResult){
+                            case "High":
+                               if (p_remove_ratio >= 1.2) {
+                                    pcrop_app_rate_score = 0;
+                                }
+                                break;
+                            case "Medium": case "Low":
+                                if (p_remove_ratio >= 1.6) {
+                                    pcrop_app_rate_score = 0;
+                                }
+                                break;
+                            case "None":
+                                if (p_remove_ratio >= 1.2) {
+                                    pcrop_app_rate_score = 0;
+                                }
+                                break;                                                                                                                                                                                     
+                        }
+
+                        if ( pcrop_app_rate_score == -1 ){
+                            query = "SELECT app_mgt_score FROM wqm_nutrient_application_mgt_scores WHERE nutrient='Phosphorus' AND app_mgt_kind='Rate' AND app_mgt_factor='app' AND soil_test_result='" + pSoilTestResult +"' AND remove_ratio_1 <= " + p_remove_ratio + " AND remove_ratio_2 > " + p_remove_ratio + ";";
+                            resultSet = statement.executeQuery(query);
+                            if (resultSet.first()) {
+                                 pcrop_app_rate_score = resultSet.getInt("app_mgt_score");
+                             }                                   
+                        }
+
+                        if (pcrop_app_rate_score != -1){
+                        //#Update N and P application management rate scores for the AoA
+                        appRateScore[N_APP_RATE_SCORE] = ncrop_app_rate_score;
+                        appRateScore[P_APP_RATE_SCORE] = pcrop_app_rate_score;                                                                                                
+                        }
+                        else{//We have a problem...no validity in any following computations if we proceed since the last query failed to find any data.  What would you like to do?
+                            appRateScore[N_APP_RATE_SCORE] = appRateScore[P_APP_RATE_SCORE] = 0;
+                        }                                                                                                                                                                                                                                                                                                                                                                              
+                    }
+                    else{ //We have a problem...no validity in any following computations if we proceed.  What would you like to do?
+                        appRateScore[N_APP_RATE_SCORE] = appRateScore[P_APP_RATE_SCORE] = 0;
+                    }                                                       
+                }
+            }
+            catch (Exception ex) {
+                error_msg += ex.getMessage();
+            }                   
+        }
+       
+        return this.appRateScore;
+    }
+    
+    public int[] getNutrientApplicationTimingScores(){
+        if ( ( appNutrientTimingScore[N_APP_TIMING_SCORE]  <0 ) || ( appNutrientTimingScore[P_APP_TIMING_SCORE]  <0 ) ) {
+            int tempNScore = 100;
+            int tempPScore = 100;
+            
+            for ( Crop.NutrientApplication nutrientApplication : this.nutrientApplicationList ){
+                //  Call each application compare its results to the last and adjust main score if necessary.
+                int[] tempAppTimingScores = nutrientApplication.getNutrientTimingScores( this.multipleNutrientApplication );
+                
+                if ( tempAppTimingScores[N_APP_TIMING_SCORE] < tempNScore )
+                    tempNScore = tempAppTimingScores[N_APP_TIMING_SCORE];
+                
+                if ( tempAppTimingScores[P_APP_TIMING_SCORE] < tempPScore )
+                    tempPScore = tempAppTimingScores[P_APP_TIMING_SCORE];                               
+            }
+            
+            appNutrientTimingScore[P_APP_TIMING_SCORE] = tempPScore;
+            appNutrientTimingScore[N_APP_TIMING_SCORE] = tempNScore;
+        }
+                
+        return this.appNutrientTimingScore;                        
+    }
+            
+    public Boolean allNutrientsIncorporated(){
+        Boolean ret_val = true;
+        for( Crop.NutrientApplication nutrientApplication : this.nutrientApplicationList ){
+            if ( !nutrientApplication.allNutrientsIncorporated() ){
+                ret_val = false;
+                break;
+            }
+        }
+        
+        return ret_val;
+    }
+    
+    public String processCropData(){
+        String ret_val = "";
+        
+        return ret_val;
+    }
+    
+    public Boolean validate(){          
+        for( Crop.NutrientApplication tNutrientApplication : nutrientApplicationList )
+            if ( !tNutrientApplication.validate() )
+                error_msg += "; " + tNutrientApplication.getErrorMsg();                
+
+        
+        return ( error_msg.isEmpty() );
+    }
 }