package lateblight;

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.text.*;
import java.util.*;
import java.net.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author unascribed
 * @version 1.0
 */

// sun mar 7
// thurs july 15, 2004

public class LateBlight extends Applet implements AdjustmentListener, ActionListener, MouseListener, WindowListener, KeyListener {

  Frame frame;
  Panel panel;
  Panel subpanel;
  Panel scrollpanel;
  Panel tempPanel;
  Graphics g;
  Scrollbar scroll;
  Label dateLabel;

  MenuBar menu;

  Menu file;
  MenuItem run;
  MenuItem exit;

  Menu potato;
  Menu resistanceLevel;
  MenuItem low;
  MenuItem moderate;
  MenuItem high;
  Menu harvestSeason;
  MenuItem early;
  MenuItem mid;
  MenuItem late;
  MenuItem yield;

  Menu environment;
  MenuItem lengthOfSeason;
  MenuItem emergenceDate;
  Menu weatherMenu;
  MenuItem coolwet;
  MenuItem hotdry;
  MenuItem moddry;
  MenuItem modmod;
  MenuItem modwet;

  Menu inoculum;
  MenuItem sporangia;
  MenuItem infections;

  Menu management;
  MenuItem weatherReport;
  MenuItem spraySystemic;
  MenuItem sprayProtectant;
  MenuItem killVines;

  Menu economics;
  MenuItem costs;
  MenuItem price;
  MenuItem showReport;

  Menu measure;
  MenuItem american;
  MenuItem metric;

  Menu viewMenu;
  MenuItem refresh;
  MenuItem viewLeaves;
  MenuItem viewBlight;
  MenuItem viewTemperature;
  MenuItem viewRainfall;
  MenuItem viewHumidHrs;
  MenuItem viewNewInfections;
  MenuItem viewSporangia;
  MenuItem viewAudpc;
  MenuItem viewSystemicResidue;
  MenuItem viewProtectantResidue;

  Menu log;
  MenuItem show;

  Menu help;
  MenuItem launchHelp;

  Label color1;
  Label color2;
  Label color3;
  Label color4;
  Label color5;
  Label color6;
  Label color7;
  Label color8;
  Label color9;
  Label color10;
/***************************************************************/
  Image imageTest;
  static String imageFile = "startimage.jpg";//image variable declaration


  Color leafColor = new Color(0, 204, 0);
  Color blightColor = new Color(204, 153, 0);
  Color rainColor = new Color(0, 0, 255);
  Color audpcColor = new Color(170, 170, 170);
  Color tempColor = new Color(255, 0, 0);
  Color rhColor = new Color(102, 255, 255);
  Color infColor = new Color(255, 255, 102);
  Color sporColor = new Color(255, 255, 255);
  Color systColor = new Color(204, 51, 255);
  Color protColor = new Color(0, 0, 0);

  DecimalFormat df1 = new DecimalFormat("#####0.0");
  DecimalFormat df2 = new DecimalFormat("#####0.00");

  Vector leavesxdata = new Vector();
  Vector leavesydata = new Vector();

  Vector blightxdata = new Vector();
  Vector blightydata = new Vector();

  Vector temperaturexdata = new Vector();
  Vector temperatureydata = new Vector();

  Vector rainfallxdata = new Vector();
  Vector rainfallydata = new Vector();

  Vector humidhoursxdata = new Vector();
  Vector humidhoursydata = new Vector();

  Vector coloniesxdata = new Vector();
  Vector coloniesydata = new Vector();

  Vector sporangiaxdata = new Vector();
  Vector sporangiaydata = new Vector();

  Vector audpcxdata = new Vector();
  Vector audpcydata = new Vector();

  Vector systemicxdata = new Vector();
  Vector systemicydata = new Vector();

  Vector protectantxdata = new Vector();
  Vector protectantydata = new Vector();

  public static final int xOrigin = 50;
  public static final int xEnd = 650;
  public static final int yOrigin = 450;
  public static final int yEnd = 50;
  public static final int plottingGap = 200;
  public static final String sLow = "low";
  public static final String sModerate = "moderate";
  public static final String sHigh = "high";
  public static final String sEarly = "early";
  public static final String sMid = "mid";
  public static final String sLate = "late";
  public static final int plotsize = 16;
  public static final int inocDay = 2;
  public static final double dirmax = 0.29;
  public static final double indmax = 0.81;
  public static final double zspr = 6.567;
  public static final double zoomax = 0.96;
  public static final int above45cm = 0;
  public static final int thirtyTo45cm = 1;
  public static final int fifteenTo30cm = 2;
  public static final int below15cm = 3;
  public static final int average = 4;
  public static final int metalaxyl = 0;
  public static final int chlorothalonil = 1;
  public static final double probitslope = 2.5;
  public static final double ec50 = 0.15;
  public static final double metalaxylslope = 0.12;
  public static final double metConvFct = -2.1476;
  public static final double zero = 0.00001;
  public static final double x0 = 0.211565658;
  public static final double k1 = 0.06068442;
  public static final double k2 = -0.478927203;
  public static final double k3 = -2.1988;
  public static final double tol = 0.0005;
  public static final double infmaxSp = 0.1;
  public static final double infmaxZsp = 0.01;
  public static final double maxless = 4.35;
  public static final double piby4 = 0.785398163397448;
  public static final double transferRate = 0.38;
  public static final double xlag = 6.0;
  public static final double sprmax = 763.2;
  public static final double deposit1 = 0.05;
  public static final double deposit2 = 0.2;
  public static final double deposit3 = 0.2;

  public static final Font boldFont = new Font("boldFont", Font.BOLD, 18);
  public static final Font stdFont = new Font("Courier", Font.PLAIN, 12);
  public static final Color bgColor = new Color(222, 222, 190);

  int count = 0;
  int xPos = xOrigin;
  int yPos = yOrigin;

  Dialog dataDialog;
  TextArea dialogText;

  boolean metricIndicator = true;
  int metricIndex = 0;

  String resistance = sLow;
  String harvest = sMid;

  double[] maxYield = new double[]{33641.40, 300.0};
  TextField maxYieldText;
  Button saveYield;

  int seasonLength = 120;
  TextField seasonLengthText;
  Button saveSeasonLength;

  String emergenceDateString = "June 1";
  TextField emergenceDateText;
  Button saveEmergenceDate;

  SimpleDateFormat sdf = new SimpleDateFormat("MMMM d");
  Date today = sdf.parse(emergenceDateString, new ParsePosition(0));

  double[] maxSporangiaPerDayCull = new double[]{1000, 1000};
  double[] distanceFromFieldCull = new double[]{10, 32.8};
  double[] maxSporangiaPerDayUnsprayed = new double[]{0, 0};
  double[] distanceFromFieldUnsprayed = new double[]{10, 32.8};
  TextField maxSporangiaPerDayCullText;
  TextField distanceFromFieldCullText;
  TextField maxSporangiaPerDayUnsprayedText;
  TextField distanceFromFieldUnsprayedText;
  Button saveSporangiaSources;

  double[] infectedSeed = new double[]{0, 0};
  double[] infectedVolunteers = new double[]{0, 0};
  double[] infectedFactor = new double[]{625.0, 253.0};
  TextField infectedSeedText;
  TextField infectedVolunteersText;
  Button saveInfectionSources;

  double[] systemicAmount = new double[]{0.22, 0.196};
  TextField systemicAmountText;
  Button saveSystemic;

  double[] protectantAmount = new double[]{1.25, 1.116};
  TextField protectantAmountText;
  Button saveProtectant;

  double[] fixedCosts = new double[]{2716.78, 1100.0}; // ***** cost
  double[] sprayApplicationCosts = new double[]{9.88, 4.0};
  double[] protectantCost = new double[]{3.52, 1.6};
  double[] systemicCost = new double[]{29.74, 13.5};
  //double[] blitecastCost = new double[]{61.75, 25.0};
  TextField fixedCostsText;
  TextField sprayApplicationCostsText;
  TextField protectantCostText;
  TextField systemicCostText;
  //TextField blitecastCostText;
  Button saveCosts;

  double[] marketPrice = new double[]{0.11, 5.0};
  TextField marketPriceText;
  Button savePrice;

  AgeGroup age = new AgeGroup();

  double infectionFct = 0.0;
  int latentPeriod = 0;
  double lesionExp = 0.0;
  double cvSporulationFct = 0.0;
  int daysSinceProtSpray = 0;
  int nProtSprays = 0;
  int daysSinceMetSpray = 0;
  int nMetSprays = 0;
  double sporangiaNumber = 0.0;
  double attachedSporangia = 0.0;
  double totalLeafArea = 0.0;
  double leafIndex = 0.0;
  double totalSporangia = 0.0;
  double totalColonies = 0.0;
  double inactiveArea = 0.0;
  double blightProportion = 0.0;
  double audpc = 0.0;
  int colonySCF = 0;
  int sporangSCF = 0;
  int metResSCF = 0;
  int chlorResSCF = 0;

  Weather weatherData;

  /*
  int[] nSeverity = new int[7];
  int nSeverityWeek = 0;
  int nSeveritySeason = 0;
  int nRFBits = 0;
  int nSeasonRFDays = 0;
  int nWeekRFDays = 0;
  boolean bTenRFDays = false;
  double dRainInTenDays = 0.0;
  */
  double dTuberInitTime = 0.0;
  double dTuberProdTime = 0.0;
  double dCvTimeFactor = 0.0;
  int nVineKillDay = 0;
  // .......... first correction
  // double dProtCost = 0.0; // original
  // double dSystCost = 0.0; // original
  double[] dProtCost = new double[]{0.0, 0.0};
  double[] dSystCost = new double[]{0.0, 0.0};
  // ...........end first correction
  double dTotalRain = 0.0;

  double[] lesionArea = new double[15];
  int n5DayPer;
  double redist1, redist2, redist3;
  double rainFct, temperatureFct, loss;
  double leafWetFct, germSporangia, zoospores;
  double germZoospores, tLeafWet, fungicideEffect;
  double incrFct, colonyFct, leafFct, metFct, lesionExpIncr;
  double dSporeSurvival, levelEffect, beta, alpha;
  double prob, totalProb;
  int level;
  double mu, expY, probY, transX, metEff, protEff;
  /*
  int nSeverityIndex;
  int nTempBits;
  double dFiveDayAvgTemp;
  */
  double dTuberInitTemp, dTuberProdTemp;
  double dShapeFact, CdfHx0;
  double humidityFct, metMuW, metLesionExp, dMetDeposit, dProbitResponse;
  double dTrh, intercept, metResidue;
  double initialMicroColonies;
  double tempLesExp, activeArea, sporArea, sporangiaToday;
  double leavesToday, leavesYesterday;
  int nToday, nEndDay;
  boolean bDefoliated;
  double[] blightArray = new double[141];

  double leafWetHrs, leafWetTemp;
  double[] dForecastTemp = new double[3];
  double[] dChanceOfRain = new double[3];
  double densityFct;
  double dTubersIfNoBlite;
  double dYieldLoss;

  double initialSporangia = 40000;
  double dNewInfections;
  double[] residue = new double[5];
  double[] sporB1Before = new double[]{
    -0.3, -0.2, -0.12132, -0.0306, 0.06009, 0.0578, 0.0555, 0.02775, 0.0, 0.0
  };
  double[] sporB2Before = new double[]{
    0.0, 0.0, -0.00534, -0.0166, -0.027975, -0.02449, -0.021023, -0.0105, 0.0, 0.0
  };

  double[] earlyArray = new double[]{
    0.006, 0.06, 0.19, 0.45, 0.81, 1.30, 1.88, 2.20, 2.42, 2.50
  };
  double[] midArray = new double[]{
    0.006, 0.06, 0.19, 0.45, 0.81, 1.30, 1.88, 2.56, 2.99, 3.28, 3.47, 3.53
  };
  double[] lateArray = new double[]{
    0.006, 0.06, 0.19, 0.45, 0.81, 1.30, 1.88, 2.76, 3.29, 3.74, 4.16, 4.38, 4.50
  };

  double cost[][] = new double[][]{
    {2.47, 1.0}, {2.47, 1.0}
  };

  DataRecord record = new DataRecord();

  boolean bShowLeaves = true;
  boolean bShowBlight = true;
  boolean bShowTemperature = false;
  boolean bShowRainfall = true;
  boolean bShowHumidHrs = false;
  boolean bShowNewInfections = false;
  boolean bShowSporangia = false;
  boolean bShowAudpc = false;
  boolean bShowSystemicResidue = true;
  boolean bShowProtectantResidue = true;

  boolean bMetSprayed = false;

  /**Construct the applet*/ // QUESTION: Caps on Late blight see line 1
  public LateBlight() {
  }

  // ................................. START INITIALIZE APPLET
  public void init() {
    imageTest = getImage(getDocumentBase(),imageFile); // get image prev declared
    frame = new Frame("LateBlight Simulation"){
      public void paint(Graphics g) { //paint image in frame
       g.drawImage(imageTest,0,42,this);//y42 is about right for top of viewable page
       g.drawString("",20,340);//no text message for now, all message on picture
        }
    };
    frame.setBackground(Color.white);
    frame.setLayout(new BorderLayout());
    frame.addWindowListener(this);
    // ................................ END INITIALIZE APPLET
    menu = new MenuBar();
    createMenu();

    frame.setMenuBar(menu);


    panel = new Panel(new BorderLayout()) {
      public void update(Graphics g) {
        plot(g);
       }
      };

    panel.setBackground(bgColor);
    panel.addKeyListener(this);

    dataDialog = new Dialog(frame, "Dialog Box", false);
    dataDialog.setLayout(new BorderLayout());
    dataDialog.setBackground(Color.lightGray);
    dataDialog.addWindowListener(this);

    createScroll();
    scrollpanel = new Panel(new BorderLayout());
    scrollpanel.setBackground(bgColor);
    scrollpanel.add(scroll, BorderLayout.SOUTH);

    StringBuffer buff = new StringBuffer("Today is ");
    sdf.format(today, buff, new FieldPosition(0));
    dateLabel = new Label(buff.toString(), Label.CENTER);
    scrollpanel.add(dateLabel, BorderLayout.NORTH);

    subpanel = new Panel(new GridLayout(2,5));
    subpanel.setBackground(bgColor);
    subpanel.addKeyListener(this);
    setColorBar();

    setLayout(new BorderLayout());

    tempPanel = new Panel(new BorderLayout());
    add(tempPanel, BorderLayout.CENTER);

    frame.add(this, BorderLayout.CENTER);
    frame.show();
    frame.setSize(800, 600); //sets size of frame
    frame.addKeyListener(this);

    weatherData = new CoolWetWeather();
    initSimulation();
    initSeason();
    initCalculations();
    doCalculations();

    g = getGraphics();
    panel.repaint();
    panel.invalidate();
    frame.validate();

  }

  /**Start the applet*/
  public void beginNew() {
    // start the simulation over

    remove(tempPanel);
    add(subpanel, BorderLayout.NORTH);
    add(panel, BorderLayout.CENTER);
    add(scrollpanel, BorderLayout.SOUTH);

    count = 0;
    scroll.setValue(0);
    panel.removeAll();
    today = sdf.parse(emergenceDateString, new ParsePosition(0));
    StringBuffer buff = new StringBuffer("Today is ");
    sdf.format(today, buff, new FieldPosition(0));
    dateLabel.setText(buff.toString());

    setColorBar();
    showReport.setEnabled(false);

    record = new DataRecord();
    initSimulation();
    initSeason();
    initCalculations();
    doCalculations();

    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  /**Main method*/
  public static void main(String[] args) {
    LateBlight lateblight = new LateBlight();
    lateblight.init();

  }
  /**************************************************************************************/
  /*public void paint(Graphics g) {
      g.drawImage(imageTest,20,50,this);
      ///g.drawString("Read this message",20,10);
        }*/

  public void adjustmentValueChanged(AdjustmentEvent e) {
    advanceDay();
  }

  public void advanceDay() {
    int temp = scroll.getValue();

    // if crop is 100% defoliated, no further simulation is allowed
    // *** corrected 06/16/2004
    if(bDefoliated) {
      showDefoliatedMessage();
      calculateYieldLoss();
      showReport.setEnabled(true);
      return;
    }

    // backwards scrollbar movement not allowed
    if(temp < count) {
      scroll.setValue(count);
      return;
    }
    count = temp;
    scroll.setValue(count);

    doCalculations();

    // increment current date by one day
    //long millis = today.getTime();
    //millis += 1000*60*60*24;
    //today.setTime(millis);
    Calendar cal = Calendar.getInstance();
    cal.setTime(today);
    cal.add(Calendar.DATE, 1);
    today = cal.getTime();
    StringBuffer buff = new StringBuffer("Today is ");
    sdf.format(today, buff, new FieldPosition(0));
    dateLabel.setText(buff.toString());

    StringBuffer dateBuff = new StringBuffer();
    sdf.format(today, dateBuff, new FieldPosition(0));
    record.dateData.addElement(dateBuff.toString());

    // add data to be plotted
    xPos += (int)Math.floor((xEnd - xOrigin)/seasonLength);

    // leaves
    yPos = yOrigin - (int)Math.round(4 * leavesToday * 10);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    leavesxdata.addElement(new Integer(xPos));
    leavesydata.addElement(new Integer(yPos));
    record.leafData.addElement(String.valueOf(Math.round(100.0 * leavesToday) / 100.0));

    // blight
    yPos = yOrigin - (int)Math.round(4 * blightArray[count]);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    blightxdata.addElement(new Integer(xPos));
    blightydata.addElement(new Integer(yPos));
    record.blightData.addElement(String.valueOf(Math.round(100.0 * blightArray[count]) / 100.0));

    // temperature
    if(metricIndicator) {
      yPos = yOrigin - (int)Math.round(4 * weatherData.temperature[count]);
      record.temperatureData.addElement(String.valueOf(weatherData.temperature[count]));
    } else {
      yPos = yOrigin - (int)Math.round(4 * (1.8 * weatherData.temperature[count] + 32));
      record.temperatureData.addElement(String.valueOf(1.8 * weatherData.temperature[count] + 32));
    }
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    temperaturexdata.addElement(new Integer(xPos));
    temperatureydata.addElement(new Integer(yPos));

    // rainfall
    if(metricIndicator) {
      yPos = yOrigin - (int)Math.round(4 * weatherData.rainfall[count] * 25.4);
      record.rainData.addElement(String.valueOf(Math.round(100.0 * weatherData.rainfall[count] * 2.54) / 100.0));
    } else {
      yPos = yOrigin - (int)Math.round(4 * weatherData.rainfall[count] * 10.0);
      record.rainData.addElement(String.valueOf(Math.round(100.0 * weatherData.rainfall[count]) / 100.0));
    }
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    rainfallxdata.addElement(new Integer(xPos));
    rainfallydata.addElement(new Integer(yPos));

    // humid hours
    yPos = yOrigin - (int)Math.round(4 * weatherData.humidHrs[count]);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    humidhoursxdata.addElement(new Integer(xPos));
    humidhoursydata.addElement(new Integer(yPos));
    record.humidHrsData.addElement(String.valueOf(weatherData.humidHrs[count]));

    // colonies
    yPos = yOrigin - (int)Math.round(4 * dNewInfections / colonySCF);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    coloniesxdata.addElement(new Integer(xPos));
    coloniesydata.addElement(new Integer(yPos));
    record.newInfectionsData.addElement(String.valueOf(Math.round(100.0 * dNewInfections) / 100.0));

    // sporangia
    yPos = yOrigin - (int)Math.round(4 * sporangiaToday / sporangSCF);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    sporangiaxdata.addElement(new Integer(xPos));
    sporangiaydata.addElement(new Integer(yPos));
    record.sporangiaData.addElement(String.valueOf(Math.round(100.0 * sporangiaToday) / 100.0));

    // audpc
    yPos = yOrigin - (int)Math.round(4 * audpc);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    audpcxdata.addElement(new Integer(xPos));
    audpcydata.addElement(new Integer(yPos));
    record.audpcData.addElement(String.valueOf(Math.round(100.0 * audpc) / 100.0));

    // systemic
    yPos = yOrigin - (int)Math.round(4 * metResidue * metResSCF);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    systemicxdata.addElement(new Integer(xPos));
    systemicydata.addElement(new Integer(yPos));
    record.systemicResidueData.addElement(String.valueOf(Math.round(100.0 * metResidue) / 100.0));

    // protectant
    yPos = yOrigin - (int)Math.round(4 * residue[average] * chlorResSCF);
    while(yPos < yEnd) {
      yPos += yOrigin - yEnd;
    }
    protectantxdata.addElement(new Integer(xPos));
    protectantydata.addElement(new Integer(yPos));
    record.protectantResidueData.addElement(String.valueOf(Math.round(100.0 * residue[average]) / 100.0));

    if(count == seasonLength - 1) {
      // the season has ended
      calculateYieldLoss();
      showReport.setEnabled(true);
    }

    panel.removeAll();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void windowClosing(WindowEvent e) {
    if(e.getSource() == dataDialog) {
      dataDialog.hide();
      panel.repaint();
      panel.invalidate();
      frame.validate();
    } else if(e.getSource() == frame) {
      frame.dispose();
      destroy();
    }
  }

  public void windowActivated(WindowEvent e) {
    }

  public void windowClosed(WindowEvent e) {

  }

  public void windowDeactivated(WindowEvent e) {

  }

  public void windowDeiconified(WindowEvent e) {

  }

  public void windowIconified(WindowEvent e) {

  }

  public void windowOpened(WindowEvent e) {

  }

  public void mouseClicked(MouseEvent e) {

  }

  public void mousePressed(MouseEvent e) {

  }

  public void mouseExited(MouseEvent e) {

  }

  public void mouseEntered(MouseEvent e) {

  }

  public void mouseReleased(MouseEvent e) {

  }

  public void keyReleased(KeyEvent e) {

  }

  public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
      if(count < seasonLength - 1) {
        if(!bDefoliated) {
          count++;
        }
        scroll.setValue(count);
        advanceDay();
      }
    }
  }

  public void keyTyped(KeyEvent e) {

  }

  public void showDefoliatedMessage() {
    dataDialog.removeAll();
    dataDialog.setTitle("Defoliation Message");
    dataDialog.setLayout(new BorderLayout());
    Label temp = new Label("The crop is 100% defoliated.  No further simulation possible.", Label.CENTER);
    temp.setBackground(Color.lightGray);
    dataDialog.add(temp, BorderLayout.CENTER);
    dataDialog.setSize(480, 120);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void showLog() {
    dataDialog.removeAll();
    dataDialog.setTitle("Log Information");
    dataDialog.setLayout(new BorderLayout());
    dialogText = new TextArea();
    dialogText.setFont(stdFont);
    dialogText.setBackground(Color.white);
    addTextToLog();
    dataDialog.add(dialogText, BorderLayout.CENTER);
    dataDialog.setSize(640, 480);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }


  static String sSpace = " ";

  public String setLogText(String arg) {
    int width = 30;
    StringBuffer buffer = new StringBuffer();
    buffer.append(arg);
    for(int i = arg.length(); i < width; i++) {
      buffer.append(sSpace);
    }
    return buffer.toString();
  }

  public void addTextToLog() {
    StringBuffer temp = new StringBuffer();

    temp.append(setLogText("Date"));
    temp.append(setLogText("Blight"));
    temp.append(setLogText("AUDPC"));
    temp.append(setLogText("L.A.I."));
    temp.append(setLogText("Temp " + (metricIndicator ? "(C)" : "(F)")));
    temp.append(setLogText("Rain " + (metricIndicator ? "(cm.)" : "(in.)")));
    temp.append(setLogText("Humid Hrs."));
    temp.append(setLogText("New Infections"));
    temp.append(setLogText("Sporangia"));
    temp.append(setLogText("Systemic Residue"));
    temp.append(setLogText("Protectant Residue"));

    dialogText.append(temp.toString());
    dialogText.append("\n\n");

    StringBuffer dataString = new StringBuffer();
    for(int i = 0; i < record.dateData.size(); i++) {
      dataString.append(setLogText((String)record.dateData.elementAt(i)));
      dataString.append(setLogText((String)record.blightData.elementAt(i)));
      dataString.append(setLogText((String)record.audpcData.elementAt(i)));
      dataString.append(setLogText((String)record.leafData.elementAt(i)));
      dataString.append(setLogText((String)record.temperatureData.elementAt(i)));
      dataString.append(setLogText((String)record.rainData.elementAt(i)));
      dataString.append(setLogText((String)record.humidHrsData.elementAt(i)));
      dataString.append(setLogText((String)record.newInfectionsData.elementAt(i)));
      dataString.append(setLogText((String)record.sporangiaData.elementAt(i)));
      dataString.append(setLogText((String)record.systemicResidueData.elementAt(i)));
      dataString.append(setLogText((String)record.protectantResidueData.elementAt(i)));
      dataString.append("\n");
    }
    dialogText.append(dataString.toString());
  }

  public void createScroll() {
    scroll = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, seasonLength);
    scroll.addAdjustmentListener(this);
    scroll.setBackground(Color.white);
    scroll.setBlockIncrement(1);
    scroll.setUnitIncrement(1);
  }

  public void setColorBar() {
    subpanel.removeAll();

    color1 = new Label("Leaves");
    color1.setForeground(leafColor);
    color2 = new Label("Blight");
    color2.setForeground(blightColor);
    color3 = new Label("Temperature");
    color3.setForeground(tempColor);
    color4 = new Label("Rainfall");
    color4.setForeground(rainColor);
    color5 = new Label("Hrs. RH > 90%");
    color5.setForeground(rhColor);
    color6 = new Label("New Infections");
    color6.setForeground(infColor);
    color7 = new Label("Sporangia");
    color7.setForeground(sporColor);
    color8 = new Label("AUDPC");
    color8.setForeground(audpcColor);
    color9 = new Label("Systemic Residue");
    color9.setForeground(systColor);
    color10 = new Label("Protectant Residue");
    color10.setForeground(protColor);

    int tally = 0;

    if(bShowLeaves) {
      subpanel.add(color1);
      tally++;
    }
    if(bShowBlight) {
      subpanel.add(color2);
      tally++;
    }
    if(bShowTemperature) {
      subpanel.add(color3);
      tally++;
    }
    if(bShowRainfall) {
      subpanel.add(color4);
      tally++;
    }
    if(bShowHumidHrs) {
      subpanel.add(color5);
      tally++;
    }
    if(bShowNewInfections) {
      subpanel.add(color6);
      tally++;
    }
    if(bShowSporangia) {
      subpanel.add(color7);
      tally++;
    }
    if(bShowAudpc) {
      subpanel.add(color8);
      tally++;
    }
    if(bShowSystemicResidue) {
      subpanel.add(color9);
      tally++;
    }
    if(bShowProtectantResidue) {
      subpanel.add(color10);
      tally++;
    }

    for(int i = tally; i < 10; i++) {
      subpanel.add(new Label(""));
    }

  }


  public void createMenu() {

    file = new Menu("Simulation");
    run = new MenuItem("Begin New");
    run.addActionListener(this);
    exit = new MenuItem("Exit");
    exit.addActionListener(this);
    file.add(run);
    file.add(exit);

    potato = new Menu("Potato");
    resistanceLevel = new Menu("Resistance Level");
    low = new MenuItem("* Low");
    low.addActionListener(this);
    moderate = new MenuItem("  Moderate");
    moderate.addActionListener(this);
    high = new MenuItem("  High");
    high.addActionListener(this);
    harvestSeason = new Menu("Harvest Season");
    early = new MenuItem("  Early");
    early.addActionListener(this);
    mid = new MenuItem("* Mid");
    mid.addActionListener(this);
    late = new MenuItem("  Late");
    late.addActionListener(this);
    yield = new MenuItem("Yield");
    yield.addActionListener(this);
    resistanceLevel.add(low);
    resistanceLevel.add(moderate);
    resistanceLevel.add(high);
    potato.add(resistanceLevel);
    harvestSeason.add(early);
    harvestSeason.add(mid);
    harvestSeason.add(late);
    potato.add(harvestSeason);
    potato.add(yield);

    environment = new Menu("Environment");
    lengthOfSeason = new MenuItem("Length of Season...");
    lengthOfSeason.addActionListener(this);
    emergenceDate = new MenuItem("Emergence Date...");
    emergenceDate.addActionListener(this);
    environment.add(lengthOfSeason);
    environment.add(emergenceDate);
    weatherMenu = new Menu("Weather");
    coolwet = new MenuItem("* Cool and Wet");
    coolwet.addActionListener(this);
    hotdry = new MenuItem("  Hot and Dry");
    hotdry.addActionListener(this);
    moddry = new MenuItem("  Moderate and Dry");
    moddry.addActionListener(this);
    modmod = new MenuItem("  Moderate and Moderate");
    modmod.addActionListener(this);
    modwet = new MenuItem("  Moderate and Wet");
    modwet.addActionListener(this);
    weatherMenu.add(coolwet);
    weatherMenu.add(hotdry);
    weatherMenu.add(moddry);
    weatherMenu.add(modmod);
    weatherMenu.add(modwet);
    environment.add(weatherMenu);

    inoculum = new Menu("Inoculum");
    sporangia = new MenuItem("Sporangia...");
    sporangia.addActionListener(this);
    infections = new MenuItem("Infections...");
    infections.addActionListener(this);
    inoculum.add(sporangia);
    inoculum.add(infections);

    management = new Menu("Management");
    weatherReport = new MenuItem("Weather Report");
    weatherReport.addActionListener(this);
    spraySystemic = new MenuItem("Spray Systemic...");
    spraySystemic.addActionListener(this);
    sprayProtectant = new MenuItem("Spray Protectant...");
    sprayProtectant.addActionListener(this);
    killVines = new MenuItem("Kill Vines");
    killVines.addActionListener(this);
    management.add(weatherReport);
    management.add(spraySystemic);
    management.add(sprayProtectant);
    management.add(killVines);

    economics = new Menu("Economics");
    costs = new MenuItem("Costs...");
    costs.addActionListener(this);
    price = new MenuItem("Price...");
    price.addActionListener(this);
    showReport = new MenuItem("Show Report");
    showReport.addActionListener(this);
    showReport.setEnabled(false);
    economics.add(costs);
    economics.add(price);
    economics.add(showReport);

    measure = new Menu("Measure");
    american = new MenuItem("  American");
    american.addActionListener(this);
    metric = new MenuItem("* Metric");
    metric.addActionListener(this);
    measure.add(american);
    measure.add(metric);

    viewMenu = new Menu("View");
    refresh = new MenuItem("Refresh");
    refresh.addActionListener(this);
    viewLeaves = new MenuItem("* Leaves");
    viewLeaves.addActionListener(this);
    viewBlight = new MenuItem("* Blight");
    viewBlight.addActionListener(this);
    viewTemperature = new MenuItem("  Temperature");
    viewTemperature.addActionListener(this);
    viewRainfall = new MenuItem("* Rainfall");
    viewRainfall.addActionListener(this);
    viewHumidHrs = new MenuItem("  Hrs. RH > 90%");
    viewHumidHrs.addActionListener(this);
    viewNewInfections = new MenuItem("  New Infections");
    viewNewInfections.addActionListener(this);
    viewSporangia = new MenuItem("  Sporangia");
    viewSporangia.addActionListener(this);
    viewAudpc = new MenuItem("  AUDPC");
    viewAudpc.addActionListener(this);
    viewSystemicResidue = new MenuItem("* Systemic Residue");
    viewSystemicResidue.addActionListener(this);
    viewProtectantResidue = new MenuItem("* Protectant Residue");
    viewProtectantResidue.addActionListener(this);
    viewMenu.add(refresh);
    viewMenu.add(viewLeaves);
    viewMenu.add(viewBlight);
    viewMenu.add(viewTemperature);
    viewMenu.add(viewRainfall);
    viewMenu.add(viewHumidHrs);
    viewMenu.add(viewNewInfections);
    viewMenu.add(viewSporangia);
    viewMenu.add(viewAudpc);
    viewMenu.add(viewSystemicResidue);
    viewMenu.add(viewProtectantResidue);

    log = new Menu("Log");
    show = new MenuItem("Show Log");
    show.addActionListener(this);
    log.add(show);

    help = new Menu("Help");
    launchHelp = new MenuItem("Show Help");
    launchHelp.addActionListener(this);
    help.add(launchHelp);

    menu.add(file);
    menu.add(potato);
    menu.add(environment);
    menu.add(inoculum);
    menu.add(management);
    menu.add(economics);
    menu.add(measure);
    menu.add(viewMenu);
    menu.add(log);
    menu.add(help);

  }

  public void actionPerformed(ActionEvent e) {
    if(e.getSource() == run) {
      // run the simulation
      beginNew();
    } else if(e.getSource() == exit) {
      frame.dispose();
      destroy();
    } else if(e.getSource() == low) {
      resistance = sLow;
      low.setLabel("* Low");
      moderate.setLabel("  Moderate");
      high.setLabel("  High");
    } else if(e.getSource() == moderate) {
      resistance = sModerate;
      low.setLabel("  Low");
      moderate.setLabel("* Moderate");
      high.setLabel("  High");
    } else if(e.getSource() == high) {
      resistance = sHigh;
      low.setLabel("  Low");
      moderate.setLabel("  Moderate");
      high.setLabel("* High");
    } else if(e.getSource() == early) {
      harvest = sEarly;
      early.setLabel("* Early");
      mid.setLabel("  Mid");
      late.setLabel("  Late");
    } else if(e.getSource() == mid) {
      harvest = sMid;
      early.setLabel("  Early");
      mid.setLabel("* Mid");
      late.setLabel("  Late");
    } else if(e.getSource() == late) {
      harvest = sLate;
      early.setLabel("  Early");
      mid.setLabel("  Mid");
      late.setLabel("* Late");
    } else if(e.getSource() == yield) {
      yield();
    } else if(e.getSource() == saveYield) {
      saveYield();
    } else if(e.getSource() == lengthOfSeason) {
      seasonLength();
    } else if(e.getSource() == saveSeasonLength) {
      saveSeasonLength();
    } else if(e.getSource() == emergenceDate) {
      emergenceDate();
    } else if(e.getSource() == saveEmergenceDate) {
      saveEmergenceDate();
    } else if(e.getSource() == sporangia) {
      sporangiaSources();
    } else if(e.getSource() == saveSporangiaSources) {
      saveSporangiaSources();
    } else if(e.getSource() == infections) {
      infectionSources();
    } else if(e.getSource() == saveInfectionSources) {
      saveInfectionSources();
    } else if(e.getSource() == saveInfectionSources) {
      saveInfectionSources();
    } else if(e.getSource() == spraySystemic) {
      spraySystemic();
    } else if(e.getSource() == saveSystemic) {
      saveSystemic();
    } else if(e.getSource() == sprayProtectant) {
      sprayProtectant();
    } else if(e.getSource() == saveProtectant) {
      saveProtectant();
    } else if(e.getSource() == killVines) {
      killVines();
    } else if(e.getSource() == costs) {
      costs();
    } else if(e.getSource() == saveCosts) {
      saveCosts();
    } else if(e.getSource() == price) {
      price();
    } else if(e.getSource() == savePrice) {
      savePrice();
    } else if(e.getSource() == american) {
      metricIndicator = false;
      metricIndex = 1;
      american.setLabel("* American");
      metric.setLabel("  Metric");
    } else if(e.getSource() == metric) {
      metricIndicator = true;
      metricIndex = 0;
      american.setLabel("  American");
      metric.setLabel("* Metric");
    } else if(e.getSource() == coolwet) {
      weatherData = new CoolWetWeather();
      coolwet.setLabel("* Cool and Wet");
      hotdry.setLabel("  Hot and Dry");
      moddry.setLabel("  Moderate and Dry");
      modmod.setLabel("  Moderate and Moderate");
      modwet.setLabel("  Moderate and Wet");
    } else if(e.getSource() == hotdry) {
      weatherData = new HotDryWeather();
      coolwet.setLabel("  Cool and Wet");
      hotdry.setLabel("* Hot and Dry");
      moddry.setLabel("  Moderate and Dry");
      modmod.setLabel("  Moderate and Moderate");
      modwet.setLabel("  Moderate and Wet");
    } else if(e.getSource() == moddry) {
      weatherData = new ModDryWeather();
      coolwet.setLabel("  Cool and Wet");
      hotdry.setLabel("  Hot and Dry");
      moddry.setLabel("* Moderate and Dry");
      modmod.setLabel("  Moderate and Moderate");
      modwet.setLabel("  Moderate and Wet");
    } else if(e.getSource() == modmod) {
      weatherData = new ModModWeather();
      coolwet.setLabel("  Cool and Wet");
      hotdry.setLabel("  Hot and Dry");
      moddry.setLabel("  Moderate and Dry");
      modmod.setLabel("* Moderate and Moderate");
      modwet.setLabel("  Moderate and Wet");
    } else if(e.getSource() == modwet) {
      weatherData = new ModWetWeather();
      coolwet.setLabel("  Cool and Wet");
      hotdry.setLabel("  Hot and Dry");
      moddry.setLabel("  Moderate and Dry");
      modmod.setLabel("  Moderate and Moderate");
      modwet.setLabel("* Moderate and Wet");
    } else if(e.getSource() == show) {
      showLog();
    } else if(e.getSource() == weatherReport) {
      showForecast();
    } else if(e.getSource() == showReport) {
      showReport();
    } else if(e.getSource() == viewLeaves) {
      bShowLeaves = !bShowLeaves;
      if(bShowLeaves) {
        viewLeaves.setLabel("* Leaves");
      } else {
        viewLeaves.setLabel("  Leaves");
      }
    } else if(e.getSource() == viewBlight) {
      bShowBlight = !bShowBlight;
      if(bShowBlight) {
        viewBlight.setLabel("* Blight");
      } else {
        viewBlight.setLabel("  Blight");
      }
    } else if(e.getSource() == viewTemperature) {
      bShowTemperature = !bShowTemperature;
      if(bShowTemperature) {
        viewTemperature.setLabel("* Temperature");
      } else {
        viewTemperature.setLabel("  Temperature");
      }
    } else if(e.getSource() == viewRainfall) {
      bShowRainfall = !bShowRainfall;
      if(bShowRainfall) {
        viewRainfall.setLabel("* Rainfall");
      } else {
        viewRainfall.setLabel("  Rainfall");
      }
    } else if(e.getSource() == viewHumidHrs) {
      bShowHumidHrs = !bShowHumidHrs;
      if(bShowHumidHrs) {
        viewHumidHrs.setLabel("* Hrs. RH > 90%");
      } else {
        viewHumidHrs.setLabel("  Hrs. RH > 90%");
      }
    } else if(e.getSource() == viewNewInfections) {
      bShowNewInfections = !bShowNewInfections;
      if(bShowNewInfections) {
        viewNewInfections.setLabel("* New Infections");
      } else {
        viewNewInfections.setLabel("  New Infections");
      }
    } else if(e.getSource() == viewSporangia) {
      bShowSporangia = !bShowSporangia;
      if(bShowSporangia) {
        viewSporangia.setLabel("* Sporangia");
      } else {
        viewSporangia.setLabel("  Sporangia");
      }
    } else if(e.getSource() == viewAudpc) {
      bShowAudpc = !bShowAudpc;
      if(bShowAudpc) {
        viewAudpc.setLabel("* AUDPC");
      } else {
        viewAudpc.setLabel("  AUDPC");
      }
    } else if(e.getSource() == viewSystemicResidue) {
      bShowSystemicResidue = !bShowSystemicResidue;
      if(bShowSystemicResidue) {
        viewSystemicResidue.setLabel("* Systemic Residue");
      } else {
        viewSystemicResidue.setLabel("  Systemic Residue");
      }
    } else if(e.getSource() == viewProtectantResidue) {
      bShowProtectantResidue = !bShowProtectantResidue;
      if(bShowProtectantResidue) {
        viewProtectantResidue.setLabel("* Protectant Residue");
      } else {
        viewProtectantResidue.setLabel("  Protectant Residue");
      }
    } else if(e.getSource() == launchHelp) {
      // open a new browser window to the help pages
      // retained .html even though our protocols ask for .htm
      try {
        getAppletContext().showDocument(new URL(getDocumentBase() + "help.html"), "_blank");
      } catch (Exception e1) {
      }
    } else if(e.getSource() == refresh) {
      panel.repaint();
      panel.invalidate();
      frame.validate();
    }
  }

  public void yield() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(2,2));
    dataDialog.setTitle("Potato Yield");

    saveYield = new Button("Save");
    saveYield.addActionListener(this);

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    StringBuffer buff = new StringBuffer();
    df1.format(maxYield[metricIndex], buff, new FieldPosition(0));
    maxYieldText = new TextField(buff.toString());
    dataDialog.add(maxYieldText);
    if(metricIndicator) {
      dataDialog.add(new Label("kg. per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("cwt. per acre", Label.LEFT));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(saveYield);

    dataDialog.setSize(320, 100);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveYield() {
    try {
      maxYield[metricIndex] = (new Double(maxYieldText.getText())).doubleValue();
      if(maxYield[metricIndex] < 0.0) {
        maxYield[metricIndex] = 0.0;
      } else if(maxYield[metricIndex] > 999999.9) {
        maxYield[metricIndex] = 999999.9;
      }
    } catch (Exception e) {
    }
    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void seasonLength() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(2,3));
    dataDialog.setTitle("Season Length");

    saveSeasonLength = new Button("Save");
    saveSeasonLength.addActionListener(this);

    dataDialog.add(new Label("Length of Season", Label.RIGHT));
    seasonLengthText = new TextField(String.valueOf(seasonLength));
    dataDialog.add(seasonLengthText);
    dataDialog.add(new Label("days", Label.LEFT));

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(saveSeasonLength);

    dataDialog.setSize(320, 100);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveSeasonLength() {
    try {
      seasonLength = (int)Math.round((new Double(seasonLengthText.getText())).doubleValue());
      if(seasonLength > 141) {
        seasonLength = 141;
      }
      scroll.setMaximum(seasonLength);
    } catch (Exception e) {
    }
    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void emergenceDate() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(2,2));
    dataDialog.setTitle("Emergence Date");

    saveEmergenceDate = new Button("Save");
    saveEmergenceDate.addActionListener(this);

    dataDialog.add(new Label("Emergence Date", Label.RIGHT));
    emergenceDateText = new TextField(emergenceDateString);
    dataDialog.add(emergenceDateText);

    dataDialog.add(new Label(""));
    dataDialog.add(saveEmergenceDate);

    dataDialog.setSize(320, 100);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveEmergenceDate() {
    try {
      emergenceDateString = emergenceDateText.getText();
    } catch (Exception e) {
    }
    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void sporangiaSources() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(8,3));
    dataDialog.setTitle("Sporangia Sources");

    saveSporangiaSources = new Button("Save");
    saveSporangiaSources.addActionListener(this);

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    StringBuffer buff = new StringBuffer();
    df1.format(maxSporangiaPerDayCull[metricIndex], buff, new FieldPosition(0));
    maxSporangiaPerDayCullText = new TextField(buff.toString());
    buff = new StringBuffer();
    df1.format(distanceFromFieldCull[metricIndex], buff, new FieldPosition(0));
    distanceFromFieldCullText = new TextField(buff.toString());
    buff = new StringBuffer();
    df1.format(maxSporangiaPerDayUnsprayed[metricIndex], buff, new FieldPosition(0));
    maxSporangiaPerDayUnsprayedText = new TextField(buff.toString());
    buff = new StringBuffer();
    df1.format(distanceFromFieldUnsprayed[metricIndex], buff, new FieldPosition(0));
    distanceFromFieldUnsprayedText = new TextField(buff.toString());

    dataDialog.add(new Label("Cull Pile:"));
    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));

    dataDialog.add(new Label("Maximum Sporangia Per Day:", Label.RIGHT));
    dataDialog.add(maxSporangiaPerDayCullText);
    dataDialog.add(new Label(""));

    dataDialog.add(new Label("Distance From Field:", Label.RIGHT));
    dataDialog.add(distanceFromFieldCullText);
    if(metricIndicator) {
      dataDialog.add(new Label("meters", Label.LEFT));
    } else {
      dataDialog.add(new Label("feet", Label.LEFT));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));

    dataDialog.add(new Label("Unsprayed Field:"));
    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));

    dataDialog.add(new Label("Maximum Sporangia Per Day:", Label.RIGHT));
    dataDialog.add(maxSporangiaPerDayUnsprayedText);
    if(metricIndicator) {
      dataDialog.add(new Label("per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("per acre", Label.LEFT));
    }

    dataDialog.add(new Label("Distance From Field:", Label.RIGHT));
    dataDialog.add(distanceFromFieldUnsprayedText);
    if(metricIndicator) {
      dataDialog.add(new Label("meters", Label.LEFT));
    } else {
      dataDialog.add(new Label("feet", Label.LEFT));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(saveSporangiaSources);

    dataDialog.setSize(640, 300);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveSporangiaSources() {
    try {
      maxSporangiaPerDayCull[metricIndex] = (new Double(maxSporangiaPerDayCullText.getText())).doubleValue();
      if(maxSporangiaPerDayCull[metricIndex] < 0.0) {
        maxSporangiaPerDayCull[metricIndex] = 0.0;
      } else if(maxSporangiaPerDayCull[metricIndex] > 9999.9) {
        maxSporangiaPerDayCull[metricIndex] = 9999.9;
      }
      distanceFromFieldCull[metricIndex] = (new Double(distanceFromFieldCullText.getText())).doubleValue();
      if(distanceFromFieldCull[metricIndex] < 0.0) {
        distanceFromFieldCull[metricIndex] = 0.0;
      } else if(distanceFromFieldCull[metricIndex] > 9999.9) {
        distanceFromFieldCull[metricIndex] = 9999.9;
      }
      maxSporangiaPerDayUnsprayed[metricIndex] = (new Double(maxSporangiaPerDayUnsprayedText.getText())).doubleValue();
      if(maxSporangiaPerDayUnsprayed[metricIndex] < 0.0) {
        maxSporangiaPerDayUnsprayed[metricIndex] = 0.0;
      } else if(maxSporangiaPerDayUnsprayed[metricIndex] > 9999.9) {
        maxSporangiaPerDayUnsprayed[metricIndex] = 9999.9;
      }
      distanceFromFieldUnsprayed[metricIndex] = (new Double(distanceFromFieldUnsprayedText.getText())).doubleValue();
      if(distanceFromFieldUnsprayed[metricIndex] < 0.0) {
        distanceFromFieldUnsprayed[metricIndex] = 0.0;
      } else if(distanceFromFieldUnsprayed[metricIndex] > 9999.9) {
        distanceFromFieldUnsprayed[metricIndex] = 9999.9;
      }
    } catch (Exception e) {
    }
    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void infectionSources() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(5,2));
    dataDialog.setTitle("Infection Sources");

    saveInfectionSources = new Button("Save");
    saveInfectionSources.addActionListener(this);

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    StringBuffer buff = new StringBuffer();
    df1.format(infectedSeed[metricIndex] * infectedFactor[metricIndex], buff, new FieldPosition(0));
    infectedSeedText = new TextField(buff.toString());
    buff = new StringBuffer();
    df1.format(infectedVolunteers[metricIndex] * infectedFactor[metricIndex], buff, new FieldPosition(0));
    infectedVolunteersText = new TextField(buff.toString());

    dataDialog.add(new Label("Infected Seed:"));
    dataDialog.add(new Label(""));

    dataDialog.add(infectedSeedText);
    if(metricIndicator) {
      dataDialog.add(new Label("infections per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("infections per acre", Label.LEFT));
    }

    dataDialog.add(new Label("Volunteers:"));
    dataDialog.add(new Label(""));

    dataDialog.add(infectedVolunteersText);
    if(metricIndicator) {
      dataDialog.add(new Label("infections per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("infections per acre", Label.LEFT));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(saveInfectionSources);

    dataDialog.setSize(320, 200);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveInfectionSources() {
    try {
      infectedSeed[metricIndex] = (new Double(infectedSeedText.getText())).doubleValue() / infectedFactor[metricIndex];
      if(infectedSeed[metricIndex] < 0.0) {
        infectedSeed[metricIndex] = 0.0;
      } else if(infectedSeed[metricIndex] > 9999.9) {
        infectedSeed[metricIndex] = 9999.9;
      }
      infectedVolunteers[metricIndex] = (new Double(infectedVolunteersText.getText())).doubleValue()  / infectedFactor[metricIndex];
      if(infectedVolunteers[metricIndex] < 0.0) {
        infectedVolunteers[metricIndex] = 0.0;
      } else if(infectedVolunteers[metricIndex] > 9999.9) {
        infectedVolunteers[metricIndex] = 9999.9;
      }
    } catch (Exception e) {
    }
    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void spraySystemic() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(4,3));
    dataDialog.setTitle("Spray Systemic");

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    dataDialog.add(new Label("The systemic spray ", Label.RIGHT));
    dataDialog.add(new Label("will be applied tomorrow,", Label.LEFT));
    dataDialog.add(new Label(""));

    StringBuffer buff = new StringBuffer();
    Calendar cal = Calendar.getInstance();
    cal.setTime(today);
    cal.add(Calendar.DATE, 1);
    sdf.format(cal.getTime(), buff, new FieldPosition(0));
    buff.append(" at ");

    StringBuffer buff2 = new StringBuffer();
    df2.format(systemicAmount[metricIndex], buff2, new FieldPosition(0));
    systemicAmountText = new TextField(buff2.toString());
    saveSystemic = new Button("Spray");
    saveSystemic.addActionListener(this);

    dataDialog.add(new Label(buff.toString(), Label.RIGHT));
    dataDialog.add(systemicAmountText);
    if(metricIndicator) {
      dataDialog.add(new Label("kg. a.i. / hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("lbs. a.i. / acre", Label.LEFT));
    }

    if((count + 1) < weatherData.rainfall.length) {
      if(weatherData.rainfall[count + 1] > 0.0) {
        dataDialog.add(new Label("The spray will be ", Label.RIGHT));
        dataDialog.add(new Label("applied in the rain " +
          (metricIndicator ? ("(" + weatherData.rainfall[count + 1] + " cm).")
          : ("(" + Math.round(100.0 * weatherData.rainfall[count + 1] / 2.54) / 100.0 + " in). "))
          , Label.LEFT));
        dataDialog.add(new Label("Are you sure you want to spray?", Label.CENTER));
      } else {
        dataDialog.add(new Label(""));
        dataDialog.add(new Label(""));
        dataDialog.add(new Label(""));
      }
    } else {
      dataDialog.add(new Label(""));
      dataDialog.add(new Label(""));
      dataDialog.add(new Label(""));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(saveSystemic);

    dataDialog.setSize(560, 180);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveSystemic() {
    try {
      systemicAmount[metricIndex] = (new Double(systemicAmountText.getText())).doubleValue();
      if(systemicAmount[metricIndex] < 0.0) {
        systemicAmount[metricIndex] = 0.0;
      } else if(systemicAmount[metricIndex] > 99.99) {
        systemicAmount[metricIndex] = 99.99;
      }
    } catch (Exception e) {
    }

    // adjust variables
    // ............................ third set of corrections
    //daysSinceMetSpray = 0; // original
    // bMetSprayed = true;  // original
    //nMetSprays += 1;  // original
    //dSystCost += (systemicAmount[metricIndex] / 1.12) * cost[metalaxyl][metricIndex];  // original
    daysSinceMetSpray = 0;
    bMetSprayed = true;
    nMetSprays += 1;
    dSystCost[metricIndex] += systemicAmount[metricIndex] * systemicCost[metricIndex];

    // ............................ end third set of corrections
    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void sprayProtectant() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(4,3));
    dataDialog.setTitle("Spray Protectant");

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    StringBuffer buff2 = new StringBuffer();
    df2.format(protectantAmount[metricIndex], buff2, new FieldPosition(0));
    protectantAmountText = new TextField(buff2.toString());
    saveProtectant = new Button("Spray");
    saveProtectant.addActionListener(this);

    dataDialog.add(new Label("The protectant spray ", Label.RIGHT));
    dataDialog.add(new Label("will be applied tomorrow,", Label.LEFT));
    dataDialog.add(new Label(""));

    StringBuffer buff = new StringBuffer();
    Calendar cal = Calendar.getInstance();
    cal.setTime(today);
    cal.add(Calendar.DATE, 1);
    sdf.format(cal.getTime(), buff, new FieldPosition(0));
    buff.append(" at ");

    dataDialog.add(new Label(buff.toString(), Label.RIGHT));
    dataDialog.add(protectantAmountText);
    if(metricIndicator) {
      dataDialog.add(new Label("kg. a.i. / hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("lbs. a.i. / acre", Label.LEFT));
    }

    if((count + 1) < weatherData.rainfall.length) {
      if(weatherData.rainfall[count + 1] > 0.0) {
        dataDialog.add(new Label("The spray will be ", Label.RIGHT));
        dataDialog.add(new Label("applied in the rain " +
          (metricIndicator ? ("(" + weatherData.rainfall[count + 1] + " cm).")
          : ("(" + Math.round(100.0 * weatherData.rainfall[count + 1] / 2.54) / 100.0 + " in). "))
          , Label.LEFT));
        dataDialog.add(new Label("Are you sure you want to spray?", Label.CENTER));
      } else {
        dataDialog.add(new Label(""));
        dataDialog.add(new Label(""));
        dataDialog.add(new Label(""));
      }
    } else {
      dataDialog.add(new Label(""));
      dataDialog.add(new Label(""));
      dataDialog.add(new Label(""));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(saveProtectant);

    dataDialog.setSize(560, 180);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void saveProtectant() {
    try {
      protectantAmount[metricIndex] = (new Double(protectantAmountText.getText())).doubleValue();
      if(protectantAmount[metricIndex] < 0.0) {
        protectantAmount[metricIndex] = 0.0;
      } else if(protectantAmount[metricIndex] > 99.99) {
        protectantAmount[metricIndex] = 99.99;
      }
    } catch (Exception e) {
    }

    // spray protectant
    // .......................................... fourth set of corrections
    double[] depositFactor = new double[4];
    // nProtSprays++; // original
    // dProtCost += (protectantAmount[metricIndex] / 1.12) * cost[chlorothalonil][metricIndex]; // original
    nProtSprays++;
    dProtCost[metricIndex] += protectantAmount[metricIndex] * protectantCost[metricIndex];
    // .......................................... end fourth set of corrections

    if((count + 1) < 52) {
      depositFactor[above45cm] = -0.012 * (count + 1) + 2.5;
      depositFactor[thirtyTo45cm] = -0.031 * (count + 1) + 2.5;
      depositFactor[fifteenTo30cm] = -0.031 * (count + 1) + 2.0;
      depositFactor[below15cm] = -0.015 * (count + 1) + 1.0;
    } else {
      depositFactor[above45cm] = 1.88;
      depositFactor[thirtyTo45cm] = 0.89;
      depositFactor[fifteenTo30cm] = 0.39;
      depositFactor[below15cm] = 0.22;
    } // end if (count + 1) < 52

    if((count + 1) < weatherData.rainfall.length) {
      for(int level = above45cm; level <= below15cm; level++) {
        if(weatherData.rainfall[count + 1] > 0.0) {
          depositFactor[level] *= 0.25 / (0.25 + weatherData.rainfall[count + 1] * 2.54);
        } // end if weatherData.rainfall[count]

        residue[level] += depositFactor[level] * protectantAmount[metricIndex];
      } // end for level
    }

    residue[average] = (residue[below15cm] + residue[fifteenTo30cm] + residue[thirtyTo45cm] + residue[above45cm]) / 4.0;

    daysSinceProtSpray = 0;

    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void killVines() {
    nVineKillDay = 1;
    bDefoliated = true;
    nToday += 7;
  }

  public void costs() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(5,3));
    dataDialog.setTitle("Costs");

    saveCosts = new Button("Save");
    saveCosts.addActionListener(this);

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    StringBuffer buff = new StringBuffer();
    df2.format(fixedCosts[metricIndex], buff, new FieldPosition(0));
    fixedCostsText = new TextField(buff.toString());
    buff = new StringBuffer();
    df2.format(sprayApplicationCosts[metricIndex], buff, new FieldPosition(0));
    sprayApplicationCostsText = new TextField(buff.toString());
    buff = new StringBuffer();
    df2.format(protectantCost[metricIndex], buff, new FieldPosition(0));
    protectantCostText = new TextField(buff.toString());
    buff = new StringBuffer();
    df2.format(systemicCost[metricIndex], buff, new FieldPosition(0));
    systemicCostText = new TextField(buff.toString());
    //blitecastCostText = new TextField(String.valueOf(blitecastCost[metricIndex]));

    dataDialog.add(new Label("Fixed Costs:", Label.RIGHT));
    dataDialog.add(fixedCostsText);
    if(metricIndicator) {
      dataDialog.add(new Label("per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("per acre", Label.LEFT));
    }

    dataDialog.add(new Label("Spray Application Costs:", Label.RIGHT));
    dataDialog.add(sprayApplicationCostsText);
    if(metricIndicator) {
      dataDialog.add(new Label("per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("per acre", Label.LEFT));
    }

    dataDialog.add(new Label("Protectant Cost:", Label.RIGHT));
    dataDialog.add(protectantCostText);
    if(metricIndicator) {
      dataDialog.add(new Label("per kg.", Label.LEFT));
    } else {
      dataDialog.add(new Label("per lb.", Label.LEFT));
    }

    dataDialog.add(new Label("Systemic Cost:", Label.RIGHT));
    dataDialog.add(systemicCostText);
    if(metricIndicator) {
      dataDialog.add(new Label("per kg.", Label.LEFT));
    } else {
      dataDialog.add(new Label("per lb.", Label.LEFT));
    }

    /*
    dataDialog.add(new Label("Blitecast Cost:", Label.RIGHT));
    dataDialog.add(blitecastCostText);
    if(metricIndicator) {
      dataDialog.add(new Label("per hectare", Label.LEFT));
    } else {
      dataDialog.add(new Label("per acre", Label.LEFT));
    }
    */

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(saveCosts);


    dataDialog.setSize(420, 200);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();

  }

  public void saveCosts() {
    try {
      fixedCosts[metricIndex] = (new Double(fixedCostsText.getText())).doubleValue();
      if(fixedCosts[metricIndex] < 0.0) {
        fixedCosts[metricIndex] = 0.0;
      } else if(fixedCosts[metricIndex] > 99999.99) {
        fixedCosts[metricIndex] = 99999.99;
      }
      sprayApplicationCosts[metricIndex] = (new Double(sprayApplicationCostsText.getText())).doubleValue();
      if(sprayApplicationCosts[metricIndex] < 0.0) {
        sprayApplicationCosts[metricIndex] = 0.0;
      } else if(sprayApplicationCosts[metricIndex] > 99999.99) {
        sprayApplicationCosts[metricIndex] = 99999.99;
      }
      protectantCost[metricIndex] = (new Double(protectantCostText.getText())).doubleValue();
      if(protectantCost[metricIndex] < 0.0) {
        protectantCost[metricIndex] = 0.0;
      } else if(protectantCost[metricIndex] > 99999.99) {
        protectantCost[metricIndex] = 99999.99;
      }
      systemicCost[metricIndex] = (new Double(systemicCostText.getText())).doubleValue();
      if(systemicCost[metricIndex] < 0.0) {
        systemicCost[metricIndex] = 0.0;
      } else if(systemicCost[metricIndex] > 99999.99) {
        systemicCost[metricIndex] = 99999.99;
      }
      //blitecastCost[metricIndex] = (new Double(blitecastCostText.getText())).doubleValue();
    } catch (Exception e) {
    }

    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void price() {
    dataDialog.removeAll();
    dataDialog.setLayout(new GridLayout(2,3));
    dataDialog.setTitle("Price");

    savePrice = new Button("Save");
    savePrice.addActionListener(this);

    if(metricIndicator) {
      metricIndex = 0;
    } else {
      metricIndex = 1;
    }

    StringBuffer buff = new StringBuffer();
    df2.format(marketPrice[metricIndex], buff, new FieldPosition(0));
    marketPriceText = new TextField(buff.toString());
    dataDialog.add(new Label("Market Price", Label.RIGHT));
    dataDialog.add(marketPriceText);
    if(metricIndicator) {
      dataDialog.add(new Label("per kg.", Label.LEFT));
    } else {
      dataDialog.add(new Label("per cwt.", Label.LEFT));
    }

    dataDialog.add(new Label(""));
    dataDialog.add(new Label(""));
    dataDialog.add(savePrice);

    dataDialog.setSize(320, 100);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void savePrice() {
    try {
      marketPrice[metricIndex] = (new Double(marketPriceText.getText())).doubleValue();
      if(marketPrice[metricIndex] < 0.0) {
        marketPrice[metricIndex] = 0.0;
      } else if(marketPrice[metricIndex] > 99999.99) {
        marketPrice[metricIndex] = 99999.99;
      }
    } catch (Exception e) {
    }

    dataDialog.hide();
    panel.repaint();
    panel.invalidate();
    frame.validate();
  }

  public void showForecast() {
    Panel titlePanel = new Panel(new GridLayout(3,1));
    Panel weatherPanel = new Panel(new GridLayout(3,4));

    dataDialog.removeAll();
    dataDialog.setTitle("Weather Report");
    dataDialog.setLayout(new BorderLayout());

    // show user the weather forecast
    double dYestTemp, dYestRain;
    String yesterdayTemp = "";
    String yesterdayRain = "";
    if(count > 0) {
      dYestTemp = metricIndicator ? weatherData.temperature[count - 1]
                                  : 1.8 * weatherData.temperature[count - 1] + 32.0;
      yesterdayTemp = "Yesterday's Temperature: " + dYestTemp
        + (metricIndicator ? " C" : " F");
      dYestRain = weatherData.rainfall[count - 1] *
        (metricIndicator ? 2.54 : 1.0);
      yesterdayRain = "Yesterday's Rainfall: " + Math.round(10.0 * dYestRain) / 10.0
        + (metricIndicator ? " cm." : " in.");
    } // end if count > 0

    Date tempDate = new Date();
    long millis = today.getTime();
    tempDate.setTime(millis);

    StringBuffer dateBuffer = new StringBuffer("Weather Report For ");
    sdf.format(tempDate, dateBuffer, new FieldPosition(0));
    titlePanel.add(new Label(dateBuffer.toString()));
    titlePanel.add(new Label(yesterdayTemp));
    titlePanel.add(new Label(yesterdayRain));

    weatherPanel.add(new Label("Forecast:"));
    StringBuffer buff;
    for(int i = 0; i < 3; i++) {
      buff = new StringBuffer();
      tempDate.setTime(millis);
      sdf.format(tempDate, buff, new FieldPosition(0));
      weatherPanel.add(new Label(buff.toString()));
      millis += 1000*60*60*24;
    } // end for i

    String temp = "";
    weatherPanel.add(new Label("Mean Temperature:"));
    for(int i = 0; i < 3; i++) {
      temp = (metricIndicator ? dForecastTemp[i] : 1.8 * dForecastTemp[i] + 32.0)
        + (metricIndicator ? " C" : " F");
      weatherPanel.add(new Label(temp));
    } // end for i

    String rain = "";
    weatherPanel.add(new Label("Chance of Rainfall"));
    for(int i = 0; i < 3; i++) {
      temp = Math.round(dChanceOfRain[i]) + "%";
      weatherPanel.add(new Label(temp));
    } // end for i

    dataDialog.add(titlePanel, BorderLayout.NORTH);
    dataDialog.add(weatherPanel, BorderLayout.CENTER);
    dataDialog.addWindowListener(this);
    dataDialog.setSize(640, 480);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void showReport() {
    double dTuberBlightProp;
    double dNetTuberYield;
    double dCwtBlightedTubers;
    double dNetCleanTuberYield;
    double dProfitLoss;

    dataDialog.removeAll();
    dataDialog.setTitle("Report");
    dataDialog.setLayout(new BorderLayout());

    dialogText = new TextArea();
    dialogText.setBackground(Color.white);
    dialogText.setFont(stdFont);

    dNetTuberYield = Math.max(0.0, dTubersIfNoBlite - dYieldLoss);
    dTuberBlightProp = Math.max(0.0, Math.min(1.0, -0.321 + 0.0318 * dTotalRain + 0.0229 * audpc));
    dCwtBlightedTubers = dNetTuberYield * dTuberBlightProp;
    dNetCleanTuberYield = Math.max(0.0, dNetTuberYield - dCwtBlightedTubers);

    StringBuffer buff = new StringBuffer();
    sdf.format(today, buff, new FieldPosition(0));

    // ........................... fifth and largest set of corrections

    dialogText.append("Season ended on " + buff.toString() + " with " + Math.round(100.0 * blightArray[count]) / 100.0 + "% blighted foliage.\n\n");
   if(dNetTuberYield > 0.0) {
     if(!metricIndicator) {
       dialogText.append("Your crop is " + Math.round(100.0 * dNetTuberYield) / 100.0 + " cwt./acre.\n");
       dialogText.append("At the current market price of " + Math.round(100.0 * marketPrice[metricIndex]) / 100.0 + "/cwt this would bring " + Math.round(100.0 * marketPrice[metricIndex] * dNetTuberYield) / 100.0 + "/acre\n");
     } else {
       dialogText.append("Your crop is " + Math.round(100.0 * dNetTuberYield * 112.13) / 100.0 + " kg./ha.\n");
       dialogText.append("At the current market price of " + Math.round(100.0 * marketPrice[metricIndex]) / 100.0 + "/kg this would bring " + Math.round(100.0 * marketPrice[metricIndex] * (dNetTuberYield * 112.13)) /100.0 + "/hectare\n");
     } // end if !metricIndicator
     dialogText.append(Math.round(100.0 * dTuberBlightProp * 100.0) / 100.0 + "% of your tubers are blighted.\n\n");
   } else {
     dialogText.append("You lost the entire crop.\n");
     dialogText.append("Time to call a Phytopathologist!\n\n");
   } // end if dNetTuberYield > 0.0

   if(metricIndicator) {
     dialogText.append("YIELD REPORT\n");
     dialogText.append("                                      Yield\n");
     dialogText.append("                                       (kg)            Revenue\n");
     dialogText.append("           Total Potential Yield:     " + Math.round(dTubersIfNoBlite * 112.13) + "          " + Math.round(100.0 * marketPrice[metricIndex] * dTubersIfNoBlite * 112.13) / 100.0 + "\n");
     dialogText.append("Yield Losses due to Plant Blight:    -" + Math.round(dYieldLoss * 112.13) + "         -" + Math.round(100.0 * marketPrice[metricIndex] * dYieldLoss * 112.13) / 100.0 + "\n");
     dialogText.append("Yield Losses due to Tuber Blight:    -" + Math.round(dCwtBlightedTubers * 112.13) + "         -" + Math.round(100.0 * marketPrice[metricIndex] * dCwtBlightedTubers * 112.13) / 100.0 + "\n");
     dialogText.append("                       Net Yield:     " + Math.round(dNetCleanTuberYield * 112.13) + "          " + Math.round(100.0 * marketPrice[metricIndex] * dNetCleanTuberYield * 112.13) / 100.0 + "\n\n");
     dialogText.append("SPRAY REPORT\n");
     dialogText.append("                      Sprays      Fungicide (kg)\n");
     dialogText.append("        Protectant:     " + nProtSprays + "            " + Math.round(100.0 * dProtCost[metricIndex] / protectantCost[metricIndex]) / 100.0 + "\n");
     dialogText.append("          Systemic:     " + nMetSprays + "            " + Math.round(100.0 * dSystCost[metricIndex] / systemicCost[metricIndex]) / 100.0 + "\n\n");
     dialogText.append("COST REPORT\n");
     dialogText.append("         Fixed Costs:   " + Math.round(100.0 * fixedCosts[metricIndex]) / 100.0 + "\n");
     dialogText.append("         Spray Costs:   " + Math.round(100.0 * (dProtCost[metricIndex] + dSystCost[metricIndex])) / 100.0 + "\n");
     dialogText.append("   Application Costs:   " + Math.round(100.0 * sprayApplicationCosts[metricIndex] * (nMetSprays + nProtSprays)) / 100.0 + "\n\n");

     dProfitLoss = (dNetCleanTuberYield * marketPrice[metricIndex] * 112.13)
       - fixedCosts[metricIndex]
       - (dProtCost[metricIndex] + dSystCost[metricIndex])
       - sprayApplicationCosts[metricIndex] * (nMetSprays + nProtSprays);
     dProfitLoss = Math.round(100.0 * dProfitLoss) / 100.0;
     dialogText.append("          Net Profit:   " + dProfitLoss);

   } else {

     dialogText.append("YIELD REPORT\n");
     dialogText.append("                                      Yield\n");
     dialogText.append("                                       (cwt)            Revenue\n");
     dialogText.append("           Total Potential Yield:     " + Math.round(100.0 * dTubersIfNoBlite) / 100.0 + "          " + Math.round(100.0 * marketPrice[metricIndex] * dTubersIfNoBlite) / 100.0 + "\n");
     dialogText.append("Yield Losses due to Plant Blight:    -" + Math.round(100.0 * dYieldLoss) / 100.0 + "         -" + Math.round(100.0 * marketPrice[metricIndex] * dYieldLoss) / 100.0 + "\n");
     dialogText.append("Yield Losses due to Tuber Blight:    -" + Math.round(100.0 * dCwtBlightedTubers) / 100.0 + "         -" + Math.round(100.0 * marketPrice[metricIndex] * dCwtBlightedTubers) / 100.0 + "\n");
     dialogText.append("                       Net Yield:     " + Math.round(100.0 * dNetCleanTuberYield) / 100.0 + "          " + Math.round(100.0 * marketPrice[metricIndex] * dNetCleanTuberYield) / 100.0 + "\n\n");
     dialogText.append("SPRAY REPORT\n");
     dialogText.append("                      Sprays      Fungicide (lb)\n");
     dialogText.append("        Protectant:        " + nProtSprays + "          " + Math.round(100.0 * dProtCost[metricIndex] / protectantCost[metricIndex]) / 100.0 + "\n");
     dialogText.append("          Systemic:          " + nMetSprays + "          " + Math.round(100.0 * dSystCost[metricIndex] / systemicCost[metricIndex]) / 100.0 + "\n\n");
     dialogText.append("COST REPORT\n");
     dialogText.append("         Fixed Costs:  " + Math.round(100.0 * fixedCosts[metricIndex]) / 100.0 + "\n");
     dialogText.append("         Spray Costs:  " + Math.round(100.0 * (dProtCost[1] + dSystCost[1])) / 100.0 + "\n");
     dialogText.append("   Application Costs:  " + Math.round(100.0 * sprayApplicationCosts[1] * (nMetSprays + nProtSprays)) / 100.0 + "\n\n");

     dProfitLoss = (dNetCleanTuberYield * marketPrice[metricIndex])
       - fixedCosts[metricIndex]
       - (dProtCost[metricIndex] + dSystCost[metricIndex])
       - sprayApplicationCosts[metricIndex] * (nMetSprays + nProtSprays);
     dProfitLoss = Math.round(100.0 * dProfitLoss) / 100.0;
     dialogText.append("          Net Profit:  " + dProfitLoss);
   } // end if metricIndicator
// .............................................................. end fifth and largest set of corrections

    dataDialog.add(dialogText, BorderLayout.CENTER);
    dataDialog.setSize(640, 480);
    dataDialog.show();
    dataDialog.invalidate();
    frame.validate();
  }

  public void plot(Graphics g) {
    g.clearRect(0, 0, 800, 600);

    g.setColor(Color.black);
    // draw axes
    g.drawLine(xOrigin,yOrigin,xOrigin,yEnd);
    g.drawLine(xOrigin,yOrigin,xEnd,yOrigin);

    // label y axis
    g.drawString("100", 10, 55);
    g.drawString(" 80", 10, 135);
    g.drawString(" 60", 10, 215);
    g.drawString(" 40", 10, 295);
    g.drawString(" 20", 10, 375);
    g.drawString("  0", 10, 455);

    // label x axis
    int xReference = xOrigin;
    int yReference = yOrigin + 50;
    long totalIncrement = 0;
    Calendar cal = Calendar.getInstance();
    Date currentDate = sdf.parse(emergenceDateString, new ParsePosition(0));
    Date steadyDate = sdf.parse(emergenceDateString, new ParsePosition(0));
    cal.setTime(currentDate);
    StringBuffer axisLabel = new StringBuffer();
    while(totalIncrement < seasonLength) {
      axisLabel = new StringBuffer();
      sdf.format(currentDate, axisLabel, new FieldPosition(0));
      g.drawString(axisLabel.toString(), xReference, yReference);

      // update vars for next time around the loop
      cal.add(Calendar.MONTH, 1);
      currentDate = cal.getTime();
      totalIncrement = (currentDate.getTime() - steadyDate.getTime()) / (1000*60*60*24);
      xReference = (int)Math.floor(50 + totalIncrement * 600 / seasonLength);
    }

    int tempX1, tempX2, tempY1, tempY2;

    // plot data

    // leaves
    if(bShowLeaves) {
      g.setColor(leafColor);
      for(int i = 0; i < leavesxdata.size() - 1; i++) {
        tempX1 = ((Integer)leavesxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)leavesxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)leavesydata.elementAt(i)).intValue();
        tempY2 = ((Integer)leavesydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

    // blight
    if(bShowBlight) {
      g.setColor(blightColor);
      for(int i = 0; i < blightxdata.size() - 1; i++) {
        tempX1 = ((Integer)blightxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)blightxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)blightydata.elementAt(i)).intValue();
        tempY2 = ((Integer)blightydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

    // temperature
    if(bShowTemperature) {
      g.setColor(tempColor);
      for(int i = 0; i < temperaturexdata.size() - 1; i++) {
        tempX1 = ((Integer)temperaturexdata.elementAt(i)).intValue();
        tempX2 = ((Integer)temperaturexdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)temperatureydata.elementAt(i)).intValue();
        tempY2 = ((Integer)temperatureydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

    // rainfall
    if(bShowRainfall) {
      g.setColor(rainColor);
      for(int i = 0; i < rainfallxdata.size() - 1; i++) {
        tempX1 = ((Integer)rainfallxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)rainfallxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)rainfallydata.elementAt(i)).intValue();
        tempY2 = ((Integer)rainfallydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          //g.drawLine(tempX1, tempY1, tempX2, tempY2);
          g.drawLine(tempX2, yOrigin, tempX2, tempY2);
        }
      }
    }

    // humid hours
    if(bShowHumidHrs) {
      g.setColor(rhColor);
      for(int i = 0; i < humidhoursxdata.size() - 1; i++) {
        tempX1 = ((Integer)humidhoursxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)humidhoursxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)humidhoursydata.elementAt(i)).intValue();
        tempY2 = ((Integer)humidhoursydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

    // colonies
    if(bShowNewInfections) {
      g.setColor(infColor);
      for(int i = 0; i < coloniesxdata.size() - 1; i++) {
        tempX1 = ((Integer)coloniesxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)coloniesxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)coloniesydata.elementAt(i)).intValue();
        tempY2 = ((Integer)coloniesydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          //g.drawLine(tempX1, tempY1, tempX2, tempY2);
          g.drawLine(tempX2, yOrigin, tempX2, tempY2);
        }
      }
    }

    // sporangia
    if(bShowSporangia) {
      g.setColor(sporColor);
      for(int i = 0; i < sporangiaxdata.size() - 1; i++) {
        tempX1 = ((Integer)sporangiaxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)sporangiaxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)sporangiaydata.elementAt(i)).intValue();
        tempY2 = ((Integer)sporangiaydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          //g.drawLine(tempX1, tempY1, tempX2, tempY2);
          g.drawLine(tempX2, yOrigin, tempX2, tempY2);
        }
      }
    }

    // audpc
    if(bShowAudpc) {
      g.setColor(audpcColor);
      for(int i = 0; i < audpcxdata.size() - 1; i++) {
        tempX1 = ((Integer)audpcxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)audpcxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)audpcydata.elementAt(i)).intValue();
        tempY2 = ((Integer)audpcydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

    // systemic
    if(bShowSystemicResidue) {
      g.setColor(systColor);
      for(int i = 0; i < systemicxdata.size() - 1; i++) {
        tempX1 = ((Integer)systemicxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)systemicxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)systemicydata.elementAt(i)).intValue();
        tempY2 = ((Integer)systemicydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

    // protectant
    if(bShowProtectantResidue) {
      g.setColor(protColor);
      for(int i = 0; i < protectantxdata.size() - 1; i++) {
        tempX1 = ((Integer)protectantxdata.elementAt(i)).intValue();
        tempX2 = ((Integer)protectantxdata.elementAt(i + 1)).intValue();
        tempY1 = ((Integer)protectantydata.elementAt(i)).intValue();
        tempY2 = ((Integer)protectantydata.elementAt(i + 1)).intValue();
        if(Math.abs(tempY1 - tempY2) < plottingGap) {
          g.drawLine(tempX1, tempY1, tempX2, tempY2);
        }
      }
    }

  }

  public void initSeason() {
    if(resistance.equals(sModerate)) {
      infectionFct = 0.90;
      latentPeriod = 6;
      lesionExp = 1.40;
      cvSporulationFct = 0.45;
    } else if(resistance.equals(sHigh))  {
      infectionFct = 0.80;
      latentPeriod = 7;
      lesionExp = 1.40;
      cvSporulationFct = 0.45;
    } else if(resistance.equals(sLow)) {
      infectionFct = 1.0;
      latentPeriod = 6;
      lesionExp = 1.50;
      cvSporulationFct = 0.55;
    }

    daysSinceProtSpray = nProtSprays = 0;
    blightProportion = audpc = 0.0;
    daysSinceMetSpray = -400;
    nMetSprays = 0;
    sporangiaNumber = 0;
    attachedSporangia = 0.0;
    totalLeafArea = leafIndex * plotsize;
    totalSporangia = totalColonies = 0.0;
    inactiveArea = 0.0;
    bDefoliated = false;

    colonySCF = 100;
    sporangSCF = 100;
    //metResSCF = 1000000;
    metResSCF = 2;
    //chlorResSCF = 1000000;
    chlorResSCF = 20;

    /*
    for(int i = 0; i < 7; i++) {
      nSeverity[i] = 0;
    }
    nSeverityWeek = 0;
    nSeveritySeason = 0;
    nRFBits = 0;
    nSeasonRFDays = 0;
    nWeekRFDays = 0;
    bTenRFDays = false;
    dRainInTenDays = 0.0;
    */

    // Tuber production initializations
    dTuberInitTime = 0.0;
    dTuberProdTime = 0.0;
    if(harvest.equals(sEarly)) {
      dCvTimeFactor = 1.60;
    } else if(harvest.equals(sMid)) {
      dCvTimeFactor = 1.404;
    } else if(harvest.equals(sLate)) {
      dCvTimeFactor = 1.333;
    }
    nVineKillDay = 0;
    // ........................ second set of corrections
    // dProtCost = 0.0; // original
    // dSystCost = 0.0; // original

    for(int i = 0; i < 2; i++) {
      dProtCost[i] = 0;
      dSystCost[i] = 0;
    }
    // ........................ end second set of corrections
    dTotalRain = 0.0;

  }

  public void initSimulation() {
    age = new AgeGroup();
  }

  public void initCalculations() {
    lesionArea = new double[15];
    residue = new double[5];
    metResidue = 0.0;
    n5DayPer = 0;
    redist1 = redist2 = redist3 = 0.0;
    rainFct = temperatureFct = loss = 0.0;
    leafWetFct = germSporangia = zoospores = 0.0;
    germZoospores = tLeafWet = dTrh = fungicideEffect = 0.0;
    incrFct = colonyFct = leafFct = metFct = lesionExpIncr = 0.0;
    dSporeSurvival = levelEffect = beta = alpha = 0.0;
    prob = totalProb = 0.0;
    level = 0;
    mu = expY = probY = transX = metEff = protEff = 0.0;
    /*
    nSeverityIndex = 0;
    nTempBits = 0;
    dFiveDayAvgTemp = 0;
    */
    dTuberInitTemp = dTuberProdTemp = 0.0;
    dShapeFact = CdfHx0 = 0.0;
    humidityFct = metMuW = metLesionExp = dMetDeposit = dProbitResponse = 0.0;

    leavesxdata = new Vector();
    leavesydata = new Vector();

    blightxdata = new Vector();
    blightydata = new Vector();

    temperaturexdata = new Vector();
    temperatureydata = new Vector();

    rainfallxdata = new Vector();
    rainfallydata = new Vector();

    humidhoursxdata = new Vector();
    humidhoursydata = new Vector();

    coloniesxdata = new Vector();
    coloniesydata = new Vector();

    sporangiaxdata = new Vector();
    sporangiaydata = new Vector();

    audpcxdata = new Vector();
    audpcydata = new Vector();

    systemicxdata = new Vector();
    systemicydata = new Vector();

    protectantxdata = new Vector();
    protectantydata = new Vector();

    xPos = xOrigin;
    yPos = yOrigin;
    today = sdf.parse(emergenceDateString, new ParsePosition(0));
    StringBuffer buff = new StringBuffer("Today is ");
    sdf.format(today, buff, new FieldPosition(0));
    dateLabel.setText(buff.toString());
  }

  public void doCalculations() {
    leafWetHrs = weatherData.humidHrs[count] + 3.0;
    leafWetHrs = Math.max(leafWetHrs, 0.0);
    leafWetTemp = (weatherData.temperature[count] + weatherData.humidTemp[count]) / 2.0;
    leavesYesterday = leavesToday;

    // generate temperature and rainfall forecasts for the next three days
    // by the time the forecast is reported, today will be history
    // thus, we need forecasts for tomorrow and the next two days
    for(int i = 0; i < 3 && count + i < seasonLength; i++) {
      // generate temperature forecast
      dForecastTemp[i] = (int)(normal(weatherData.temperature[i + count], (i == 0) ? 3.0 : ((i == 1) ? 4.0 : 5.0)) + 0.5);
      // generate rainfall probability forecast
      dShapeFact = (i == 0) ? 0.6 : ((i == 1) ? 0.9 : 1);
      if(weatherData.rainfall[i + count] > 0) {
        dChanceOfRain[i] = 10.0 * weatherData.rainfall[i + count] + 100.0 * (1.0 - dShapeFact * Math.pow(Math.random(), 2.0));
      } else {
        dChanceOfRain[i] = 100.0 * (dShapeFact * Math.pow(Math.random(), 2.0));
      }
      // round to nearest 10 percent
      dChanceOfRain[i] = Math.round(10.0 * dChanceOfRain[i]) / 10.0;
      dChanceOfRain[i] = Math.min(100.0, dChanceOfRain[i]);
    } // end for i

    // end weather calculations

    /*
    // blitecast calculations
    // evaluate severity value from table based on relative humidity and temperature
    if(weatherData.humidTemp[count] <= 7.2) {
      nSeverityIndex = 0;
    } else if(weatherData.humidTemp[count] <= 11.6) {
      if(weatherData.humidHrs[count] <= 15) {
        nSeverityIndex = 0;
      } else if(weatherData.humidHrs[count] <= 18) {
        nSeverityIndex = 1;
      } else if(weatherData.humidHrs[count] <= 21) {
        nSeverityIndex = 2;
      } else {
        nSeverityIndex = 3;
      }
    } else if(weatherData.humidTemp[count] <= 15.0) {
      if(weatherData.humidHrs[count] <= 12) {
        nSeverityIndex = 0;
      } else if(weatherData.humidHrs[count] <= 15) {
        nSeverityIndex = 1;
      } else if(weatherData.humidHrs[count] <= 18) {
        nSeverityIndex = 2;
      } else if(weatherData.humidHrs[count] <= 21) {
        nSeverityIndex = 3;
      } else {
        nSeverityIndex = 4;
      }
    } else if(weatherData.humidTemp[count] <= 26.6) {
      if(weatherData.humidHrs[count] <= 9) {
        nSeverityIndex = 0;
      } else if(weatherData.humidHrs[count] <= 12) {
        nSeverityIndex = 1;
      } else if(weatherData.humidHrs[count] <= 15) {
        nSeverityIndex = 2;
      } else if(weatherData.humidHrs[count] <= 18) {
        nSeverityIndex = 3;
      } else {
        nSeverityIndex = 4;
      }
    } else {
      nSeverityIndex = 0;
    }

    // severity values during last 7 days
    nSeverity[(count + 1) % 7] = nSeverityIndex;
    nSeverityWeek = 0;
    for(int i = 1; i < 7; i++) {
      nSeverityWeek += nSeverity[i];
    } // end for i

    // severity values summed for season
    nSeveritySeason += nSeverityIndex;

    // keep track of the amount of rain in the 10 previous days
    dRainInTenDays = 0.0;
    for(int i = count; i > 0 && i > count - 10; i--) {
      dRainInTenDays += weatherData.rainfall[i];
    } // end for i

    // keep track of mean temperature in the 5 previous days
    dFiveDayAvgTemp = 0.0;
    for(int i = count; i > 0 && i > count - 10; i--) {
      dFiveDayAvgTemp += weatherData.temperature[i];
    } // end for i
    dFiveDayAvgTemp /= 5;

    // rain-favorable day dfined and counted for season
    nRFBits <<= 1;
    if((count + 1) >= 10 && dRainInTenDays >= 1.2 && dFiveDayAvgTemp < 25.5 && weatherData.temperature[count] > 7.2) {
      nRFBits++;
      nSeasonRFDays++;
    } // end if
    nTempBits = nRFBits;
    nWeekRFDays = 0;
    for(int i = 0; i < 7; i++) {
      nWeekRFDays += nTempBits % 2;
      nTempBits >>= 1;
    }
    if(nWeekRFDays < 7) {
      bTenRFDays = false;
    } else {
      bTenRFDays = true;
      for(int i = 0; i < 3; i++) {
        if(nTempBits % 2 == 0) {
          bTenRFDays = false;
        } // end if
        nTempBits >>= 1;
      } // end for
    } // end if nWeekRFDays
    */

    // increment days since spray of metalaxyl
    // it will be reset to 0 when the users sprays
    if(bMetSprayed) {
      bMetSprayed = false;
    } else {
      daysSinceMetSpray++;
    }

    if((count + 1) >= inocDay && nVineKillDay == 0) {
      // Fungus calcuations

      // densityFct is used to adjust the rates of infection,
      // expansion, and sporulation to account for density dependence.
      // In the original model it affected infection only.  We found
      // it necessary to include the others to make the disease
      // progress curve have a reasonable shape for pedagogical purposes -- PAA
      densityFct = 1.0 - blightProportion;

      // addition of sporangia as inoculum
      // add inoculum from cull pile
      // negative logistic inoculum production with time
      // corrected July 15, 2004 lb
      attachedSporangia += maxSporangiaPerDayCull[0]
          if(metricIndicator) {
        attachedSporangia += maxSporangiaPerDayCull[0]
            // adjust for time
            * (1.0 - (1.0 / (1.0 + 199 * Math.exp(-0.15 * ((count + 1) - inocDay)))))
            // adjust for distance
            * Math.exp(-0.05 * distanceFromFieldCull[0]);
      } else {
        attachedSporangia += maxSporangiaPerDayCull[1]
      // adjust for time
      * (1.0 - (1.0 / (1.0 + 199 * Math.exp(-0.15 * ((count + 1) - inocDay)))))
      // adjust for distance
      * Math.exp(-0.05 * distanceFromFieldCull[1] / 3.28);
}


      // add inoculum from unsprayed field
      // logistic inoculum production with time
      if(metricIndicator) {
        attachedSporangia += maxSporangiaPerDayUnsprayed[0]
            // adjust for time
            * (1.0 / (1.0 + 199 * Math.exp(-0.12 * ((count + 1) - inocDay))))
            // adjust for distance
            * Math.exp(-0.05 * distanceFromFieldUnsprayed[0]);
      } else {
        attachedSporangia += maxSporangiaPerDayUnsprayed[1]
            // adjust for time
            * (1.0 / (1.0 + 199 * Math.exp(-0.12 * ((count + 1) - inocDay))))
            // adjust for distance
            * Math.exp(-0.05 * distanceFromFieldUnsprayed[1] / 3.28);
      }

      // dispersal
      if(weatherData.temperature[count] > 21.0) {
        dSporeSurvival = Math.exp(6.0 * (-0.0256 * weatherData.temperature[count] + 0.537));
      } else {
        dSporeSurvival = 1.0;
      } // end if weatherData
      sporangiaNumber = 0.025 * dSporeSurvival * Math.min(leafIndex / 3.5, 1.0) * attachedSporangia;
      // end dispersal

      // infection
      dNewInfections = 0.0;
      temperatureFct = Math.min(1.0, 0.03 * weatherData.humidTemp[count] + 0.4);

      // calculation of leafWetFct
      if(leafWetHrs * temperatureFct > 8.0) {
        leafWetFct = Math.min(0.8 + 0.0125 * (leafWetHrs * temperatureFct - 8.0), 1.0);
      } else {
        leafWetFct = Math.max(0.0, 0.16 * (leafWetHrs * temperatureFct - 3.0));
      } // end if leafWetHours

      // direct germination of sporangia
      if(leafWetTemp >= 14.0 && leafWetTemp <= 29.0) {
        tLeafWet = Math.min(Math.max(2.1 + leafWetTemp * (-0.48 + leafWetTemp * (0.031 + leafWetTemp * (-4.5E-04d - 4.4E-06d * leafWetTemp))), 0.0), 1.0);
        germSporangia = sporangiaNumber * (dirmax * tLeafWet);
      } else {
        germSporangia = 0.0;
      }

      // formation of zoospores
      if(leafWetTemp >= 0.0 && leafWetTemp <= 24.0) {
        tLeafWet = Math.min(Math.max(1.314E-02d + leafWetTemp * (6.98E-02d + leafWetTemp
          * (1.815E-02d + leafWetTemp * (-2.23E-03d + leafWetTemp
          * (7.48E-05d - 7.68E-07d * leafWetTemp)))), 0.0), 1.0);
        zoospores = sporangiaNumber * (indmax * tLeafWet * zspr);
      } else {
        zoospores = 0.0;
      } // end if leafWetTemp

      // germination of zoospores
      if(leafWetTemp >= 0.0 && leafWetTemp <= 28.0) {
        tLeafWet = Math.min(Math.max(4.94E-03d + leafWetTemp * (0.364 + leafWetTemp
          * (-5.813E-02d + leafWetTemp * (4.52E-03d + leafWetTemp
          * (-1.617E-04d + 2.068E-06d * leafWetTemp)))), 0.0), 1.0);
        germZoospores = zoospores * (zoomax * tLeafWet);
      } else {
        germZoospores = 0.0;
      } // end if leafWetTemp

      // infection
      if(weatherData.humidTemp[count] >= 1.5 && weatherData.humidTemp[count] <= 30.0) {
        /*
        dTrh = -0.4846 + weatherData.humidTemp[count] * (0.3735 + weatherData.humidTemp[count]
          * (-3.556E-02d + weatherData.humidTemp[count] * (1.509E-03d - 2.405E-05d
          * weatherData.humidTemp[count])));
        */
        dTrh = Math.min(Math.max((
          -0.4846 + weatherData.humidTemp[count] * (0.3735 + weatherData.humidTemp[count]
          * (-3.556E-02d + weatherData.humidTemp[count] * (1.509E-03d - 2.405E-05d
          * weatherData.humidTemp[count])))), 0.0), 1.0);
        if(residue[average] < 0.001) {
          protEff = 1.0;
        } else {
          // this is a linear probit / log dose function
          dProbitResponse = 5.0 + probitslope
            * base10log(residue[average] / ec50);
          // the proportional effect is simulated with a logistic function that
          // approximates a probit function (exactly equal at .01, .50, and .99)
          protEff = 1.0 - 1.0 / (1.0 + 19466.6 * Math.exp(-1.97529 * dProbitResponse));
        } // end if residue[average]

        // metylaxyl effect
        metEff = 1.0;
        if(daysSinceMetSpray == 0) {
          // intercept is the natural log of the residue
          dMetDeposit = Math.exp(-0.118 + 8.71 * systemicAmount[metalaxyl]);
          if(weatherData.rainfall[count] > 0.0) {
            dMetDeposit *= 0.25 / (0.25 + weatherData.rainfall[count] * 2.54);
          } // end if weatherData.rainfall[count]
          intercept = Math.log(metResidue + dMetDeposit);
        } // end if daysSinceMetSpray
        if(daysSinceMetSpray >= 0) {
          // mu is a lognormal parameter estimate
          // mu = ln(metalaxyl residue) per Milgroom
          mu = intercept - metalaxylslope * daysSinceMetSpray;
          metResidue = Math.max(0.0, Math.exp(mu));
          if(mu <= -1.77) {
            metEff = 1.0;
          } else {
            // expected proportion of infections that establish
            expY = Math.exp(metConvFct + 1.0362 - 1.1988 * mu);
            transX = 0.640374 - 0.183685 * mu;
            if(transX <= 0.0) {
              probY = 0.0;
            } else {
              // probY is an approximate probability of x <= 0.2116 for a given mu
              probY = Math.min(Math.max(Math.pow(transX, 6.349), 0.0), 1.0);
            } // end if transX
            integration(zero, x0);
            metEff = Math.min(Math.max(expY - CdfHx0 + probY, 0.0), 1.0);
          } // end if mu
        } // end if daysSinceMetSpray
        // end metalaxyl effect

        fungicideEffect = protEff * metEff;
        dNewInfections = (infmaxSp * germSporangia + infmaxZsp * germZoospores)
          * (dTrh * leafWetFct * fungicideEffect * infectionFct) * densityFct;
      } else {
        dNewInfections = 0.0;
      } // end if weatherData.humidTemp[count]

      // total colonies sums dNewInfections over days
      totalColonies += dNewInfections;

      // initial infection on day of inoculation
      // initial infection on day of inoculation
      // corrected July 15, 2004 lb
      if((count + 1) == inocDay) {
        if(metricIndicator) {
          initialMicroColonies = infectedVolunteers[0] + infectedSeed[0];
        } else {
          initialMicroColonies = infectedVolunteers[1] + infectedSeed[1];
        } // end if metricIndicator
        dNewInfections += initialMicroColonies;
      } // end if count == inocDay
    // end infection


      // lesion expansion
      if(weatherData.temperature[count] >= 0.0 && weatherData.temperature[count] <= 33.0) {
        // effect of temperature
        tempLesExp = Math.sqrt(8.4E-04d + weatherData.temperature[count] * (0.1261
          + weatherData.temperature[count] * (-3.079E-02d + weatherData.temperature[count]
          * (3.08E-03d + weatherData.temperature[count] * (-1.152E-04d
          + 1.414E-06d * weatherData.temperature[count])))));
      } else {
        tempLesExp = 0.0;
      } // end if weatherData.humidTemp[count]

      lesionExpIncr = maxless * tempLesExp * lesionExp;
      activeArea = 0.0;

      // update inactive lesion area by adding in class 15
      inactiveArea += (age.lesionNumber[14] * age.lesionDiam[14] * age.lesionDiam[14] * piby4);

      //reset to 0 each day
      for(int i = 0; i < 15; i++) {
        lesionArea[i] = 0.0;
      }

      if(daysSinceMetSpray >= 0 && daysSinceMetSpray <= 6) {
        metLesionExp = Math.max(0.0, Math.min(1.0, (0.0143 + 0.150 * daysSinceMetSpray)));
      } else {
        metLesionExp = 1.0;
      } // end if daysSinceMetSpray

      // metalaxyl has effect on lesion expansion
      if(daysSinceMetSpray == 0) {
        age.lesionNumber[0] = 0.0;
        for(int ageInt = 0; ageInt < 15; ageInt++) {
          age.metExpFct[ageInt] = Math.max(0.0, Math.min(1.0, metLesionExp * age.metInitFct[ageInt]));
        } // end for ageInt
      } else {
        for(int ageInt = 0; ageInt < 15; ageInt++) {
          age.metExpFct[ageInt] = metLesionExp;
        } // end for ageInt
      } // end if daysSinceMetSpray

      for(int ageInt = 14; ageInt >= 1; ageInt--) {
        age.lesionNumber[ageInt] += age.lesionNumber[ageInt - 1] * transferRate;
        age.lesionNumber[ageInt - 1] -= age.lesionNumber[ageInt - 1] * transferRate;
        if(ageInt >= latentPeriod) {
          // update lesionDiameter for expanding lesions
          incrFct = Math.max(0.0, Math.min(1.0, 1.72 - 0.12 * ageInt));
          age.lesionDiam[ageInt] = age.lesionDiam[ageInt - 1] + lesionExpIncr * incrFct
            * densityFct * age.metExpFct[ageInt - 1];
        } else if(ageInt == latentPeriod - 1) {
          // initialize diameter at latentPeriod
          age.lesionDiam[ageInt] = 2.0 * densityFct * age.metExpFct[ageInt];
        } // end if ageInt

        // calculate area for each age class
        if(ageInt >= latentPeriod - 1) {
          lesionArea[ageInt] = age.lesionNumber[ageInt] * age.lesionDiam[ageInt] * age.lesionDiam[ageInt] * piby4;
        } // end if ageInt
      } // end for ageInt

      age.lesionNumber[0] = dNewInfections;

      // calculate total lesion area
      for(int ageInt = latentPeriod + 1; ageInt < 15; ageInt++) {
        activeArea += lesionArea[ageInt];
      } // end for ageInt
      // end lesion expansion

      //sporulation
      sporArea = 0.0;
      if(daysSinceMetSpray >= 0 && daysSinceMetSpray <= 27) {
        // effect of metalaxyl on sporulation
        if(daysSinceMetSpray == 0) {
          // 2*intercept is estimate of mu-wash for conversion
          // to ng/cm2 from kg ai/ha; +2 is for scaling only
          metMuW = 2.0 * intercept + 2.0;
          for(int ageInt = 0; ageInt < 15; ageInt++) {
            age.metSporFct[ageInt] = age.sporAAfter[ageInt] + age.sporBAfter[ageInt] * metMuW;
            age.metSporFct[ageInt] = Math.min(1.0, Math.max(0.0, age.metSporFct[ageInt]));
          } // end for ageInt
        } // end if daysSinceMetSpray == 0

        for(int ageInt = 14; ageInt > 0; ageInt--) {
          if(ageInt > latentPeriod) {
            sporArea += lesionArea[ageInt] * age.metSporFct[ageInt];
          } // end if ageInt > latentPeriod
          age.metSporFct[ageInt] = age.metSporFct[ageInt - 1];
        } // end for ageInt
        if(daysSinceMetSpray <= 9) {
          age.metSporFct[0] = sporB1Before[daysSinceMetSpray] * metMuW
            + sporB2Before[daysSinceMetSpray] * metMuW * metMuW;
          age.metSporFct[0] = Math.min(Math.max(age.metSporFct[0], 0.0), 1.0);
        } else {
          age.metSporFct[0] = 1.0;
        } // end if daysSinceMetSpray <= 9
      } else {
        for(int ageInt = 14; ageInt > latentPeriod - 1; ageInt--) {
          sporArea += lesionArea[ageInt];
        } // end for ageInt
      } // end if daysSinceMetSpray

      if(weatherData.humidTemp[count] >= 0.0 && weatherData.humidTemp[count] <= 26) {
        /*
        dTrh = -0.3882 + weatherData.humidTemp[count] * (0.2482 + weatherData.humidTemp[count]
          * (-3.187E-02d + weatherData.humidTemp[count]
          * (2.52E-03d - 5.32E-05d * weatherData.humidTemp[count])));
        */
        dTrh = Math.min(Math.max((-0.3882 + weatherData.humidTemp[count] * (0.2482
          + weatherData.humidTemp[count] * (-3.817E-02d + weatherData.humidTemp[count]
          * (2.52E-03d - 5.32E-05d * weatherData.humidTemp[count])))), 0.0), 1.0);
        humidityFct = Math.min(Math.max(((weatherData.humidHrs[count] - xlag) / (24.0 - xlag)), 0.0), 1.0);
        attachedSporangia = Math.max(0.0, (0.36 * cvSporulationFct * sprmax * dTrh * humidityFct * sporArea * densityFct));
      } else {
        attachedSporangia = 0.0;
      } // end if weatherData.humidTemp[count]
      totalSporangia += attachedSporangia;
      sporangiaToday = attachedSporangia;
      // end sporulation
      // end fungus

      // disease
      // note: activeArea and inactiveArea are in sq mm, and totalLeafArea is in sq meters
      blightProportion = Math.max(0.0, ((activeArea + inactiveArea) / 1.0E+06d) / totalLeafArea);

      // if complete defoliation has occurred set flag for early termination
      if(blightProportion >= 1.0) {
        blightProportion = 1.0;
        if(nVineKillDay == 0) {
          nVineKillDay = 1;
        }
      } // end if blightProportion >= 1.0
      blightArray[count] = blightProportion * 100;
      if(blightArray[count] >= 1) {
        dTotalRain += weatherData.rainfall[count];
      } // end if blight >= 1
      audpc += blightProportion;
      // end disease
    } // end if count >= inocDay

    // host growth
    if(nVineKillDay == 0) {
      n5DayPer = (count + 1) / 5;
      if(harvest.equals(sEarly)) {
        if((count + 1) > 44) {
          leafIndex = 2.5;
        } else {
          leafIndex = earlyArray[n5DayPer]
            + ((earlyArray[n5DayPer + 1] - earlyArray[n5DayPer])
            * (((count + 1) - (n5DayPer * 5.0)) / 5.0));
        } // end if count > 44
      } else if(harvest.equals(sMid)) {
        if((count + 1) > 52) {
          leafIndex = 3.5;
        } else {
          leafIndex = midArray[n5DayPer]
            + ((midArray[n5DayPer + 1] - midArray[n5DayPer])
            * (((count + 1) - (n5DayPer * 5.0)) / 5.0));
        } // end if count > 52
      } else if(harvest.equals(sLate)) {
        if((count + 1) > 59) {
          leafIndex = 4.5;
        } else {
          leafIndex = lateArray[n5DayPer]
            + ((lateArray[n5DayPer + 1] - lateArray[n5DayPer])
            * (((count + 1) - (n5DayPer * 5.0)) / 5.0));
        } // end if count > 59
      } // end if harvest
      totalLeafArea = leafIndex * plotsize;
      leavesToday = leafIndex;
    } // end if nVineKillDay == 0
    // end host growth

    if(nVineKillDay <= 7) {
      // tuber development -- translated from fortran game
      // tuber production -- function of time, temperature, and cultivar
      // dTuberIfNoBlite represents tuber production before the effects
      // of disease.  Yield losses due to disease are calculated at the end
      // of the season
      dTubersIfNoBlite = 0.0;
      // tuber initiation time
      dTuberInitTemp = 0.0;

      if(weatherData.temperature[count] > 0.0 && weatherData.temperature[count] < 35.0) {
        dTuberInitTemp = -0.00911 + (0.1038 * weatherData.temperature[count]) - (0.00296 * weatherData.temperature[count] * weatherData.temperature[count]);
      } // end if weatherData.temperature[count]
      dTuberInitTime += dCvTimeFactor * dTuberInitTemp;
      if(dTuberInitTime >= 45.0 || (count + 1) >= (70.0 / dCvTimeFactor)) {
        // tuber production time is used in tuber production equation
        dTuberProdTemp = 0.0;
        if(weatherData.temperature[count] > 5.0 && weatherData.temperature[count] < 40.0) {
          dTuberProdTemp = -0.3837 + (0.1261 * weatherData.temperature[count]) - (0.00298 * weatherData.temperature[count] * weatherData.temperature[count]);
        } // end if weatherData.temperature[count]
        dTuberProdTime += dCvTimeFactor * dTuberProdTemp;
        if(dTuberProdTime <= 94) {
          dTubersIfNoBlite = 0.56 * dTuberProdTime;
        } else {
          dTubersIfNoBlite = 52.0;
        } // end if dTuberProdTime <= 94

        // convert from tons/hectare to cwt/acre
        dTubersIfNoBlite /= 0.112;

        // adjust for maximum yield of cultivar - corrected
        if(metricIndicator) {
          dTubersIfNoBlite *= (maxYield[0] * 0.001) / 52.0;
        } else {
          dTubersIfNoBlite *= (maxYield[1] * 0.112) / 52.0;
        }

      } // end if dTuberInitTime
      // end tuber development
    } // end if nVineKillDay <= 7

    // protectant loss
    daysSinceProtSpray += 1;

    if(weatherData.temperature[count] < 27.5) {
      temperatureFct = Math.min(1.0, Math.exp(-0.043 * (weatherData.temperature[count] - 15.5)));
    } else {
      temperatureFct = 0.6;
    } // end if weatherData.temperature[count]

    if(weatherData.rainfall[count] > 0.08) {
      rainFct = Math.exp(-1.09 * Math.pow(weatherData.rainfall[count], 0.333) + 0.313
        * Math.pow((daysSinceProtSpray - 1) * weatherData.rainfall[count], 0.333));
      redist1 = (1.0 - rainFct * temperatureFct) * residue[above45cm];
    } else {
      redist1 = 0.0;
      rainFct = 1.0;
    } // end if weatherData.rainfall[count]

    loss = Math.pow((rainFct * temperatureFct), 0.471);

    if(weatherData.rainfall[count] > 0.08) {
      redist2 = (1.0 - loss) * residue[thirtyTo45cm];
      redist3 = (1.0 - loss) * residue[fifteenTo30cm];
    } else {
      redist2 = redist3 = 0.0;
    } // end if weatherData.rainfall[count]

    // the following is added to compensate for host growth,
    // which has been removed from sprayProtectant()
    if((count + 1) > 1 && leavesToday > 0.0) {
      for(int level = above45cm; level <= below15cm; level++) {
        residue[level] *= leavesYesterday / leavesToday;
      } // end for level
    } // end if count > 1

    if((count + 1) < seasonLength) {
      residue[above45cm] = residue[above45cm] * rainFct * temperatureFct;
      residue[thirtyTo45cm] = residue[thirtyTo45cm] * loss + deposit1 * redist1;
      residue[fifteenTo30cm] = residue[fifteenTo30cm] * loss + deposit1 * redist2 + deposit2 * redist1;
      residue[below15cm] = residue[below15cm] * loss + deposit1 * redist3 + deposit2 * redist2 + deposit3 * redist1;
      // note: should that last one be redist1?  -- perhaps it's a bug in the original c code?
      residue[average] = (residue[above45cm] + residue[thirtyTo45cm] + residue[fifteenTo30cm] + residue[below15cm]) / 4.0;
    } // end if count < seasonLength
    // end protectant loss

    if(nVineKillDay != 0) {
      bDefoliated = true;
      dNewInfections = 0.0;
      sporangiaToday = 0.0;
      blightArray[count] = blightProportion * 100.0;
      audpc += blightProportion;
      leavesToday = leavesYesterday;
      nVineKillDay++;
      if(nVineKillDay > 7) {
        //bDefoliated = true;
        nEndDay = nToday;
        nToday = count + 2;
      } // end if nVineKillDay > 7
    } // end if nVineKillDay != 0

    // update scale factors (SCF's)
    while((dNewInfections / colonySCF) > 100) {
      colonySCF *= 10;
    } // end while dNewInfections

    while((sporangiaToday / sporangSCF) > 100) {
      sporangSCF *= 10;
    } // end while sporangiaToday

    /*
    while((residue[average] * chlorResSCF) > 50) {
      chlorResSCF /= 10;
    } // end while residue[average]

    while((metResidue * metResSCF) > 50) {
      metResSCF /= 10;
    } // end while metResidue
    */
  } // end of method doCalculations()

  public void calculateYieldLoss() {
    double[] dIncrement = new double[14]; // weekly increments in % blight
    double[] dCoefficient = new double[]{
      1.867, 0.446, 1.144, 0.628, 0.193, 0.180, -0.012, 0.343, 0.829, 0.170, 0.067, 0.044, -0.155, -0.829
    }; // regression equation coefficients
    boolean bDone = false; // true when increments have been calculated through end of season
    double dSum = 0.0; // sum of the first five increments

    // compute weekly disease increments
    if(count > 66) {
      dIncrement[0] = blightArray[65] * 0.01;
    } else {
      dIncrement[0] = blightArray[count - 1] * 0.01;
      bDone = true;
    } // end if count > 66

    for(int i = 1, nEndWeek = 73; i < 9 && !bDone; i++, nEndWeek += 7) {
      if(count > nEndWeek) {
        dIncrement[i] = Math.max(0.0, blightArray[nEndWeek - 1] - blightArray[nEndWeek - 8]);
      } else {
        dIncrement[i] = Math.max(0.0, blightArray[count - 1] - blightArray[nEndWeek - 8]);
        bDone = true;
      } // end if count > nEndWeek
    } // end for i

    // if first 5 increments sum to less than 10%, set
    // last five increments to the five increments preceding them
    for(int i = 0; i < 5; i++) {
      dSum += dIncrement[i];
    } // end for i
    if(dSum < 10.0) {
      for(int i = 9; i < 14; i++) {
        dIncrement[i] = dIncrement[i - 5];
      } // end for i
    } // end if dSum < 10.0

    dYieldLoss = 0.0;
    if(count >= 66) {
      for(int i = 0; i < 14; i++) {
        dYieldLoss += dCoefficient[i] * dIncrement[i];
      } // end for i
      dYieldLoss = Math.min(100.0, dYieldLoss);
      dYieldLoss /= 100.0; // proportion yield loss
      dYieldLoss *= dTubersIfNoBlite; // cwt. yield loss
    } // end if count >= 66
  } // end calculateYieldLoss()

  public void integration(double lower, double upper) {
    double oddSum, evenSum, endSum, sum1;
    double x, deltaX;
    int pieces = 2;
    int k = 0;

    deltaX = (upper - lower) / pieces;
    oddSum = fx(lower + deltaX, mu);
    evenSum = 0.0;
    endSum = fx(lower, mu) + fx(upper, mu);
    CdfHx0 = (endSum + 4.0 * oddSum) * deltaX / 3.0;

    do {
      pieces = pieces * 2;
      sum1 = CdfHx0;
      deltaX = (upper - lower) / pieces;
      evenSum += oddSum;
      oddSum = 0.0;
      k = pieces / 2;
      for(int i = 1; i <= k; i++) {
        x = lower + deltaX * (2.0 * i - 1.0);
        oddSum += fx(x, mu);
      }
      CdfHx0 = (endSum + 4.0 * oddSum + 2.0 * evenSum) * deltaX / 3.0;
    } while(tol < Math.abs(sum1 - CdfHx0));
  }

  public double fx(double x, double mu) {
    return (k1 * Math.pow(x, k3) * Math.exp(k2 * (Math.log(x) - mu) * (Math.log(x) - mu)));
  }

  public double base10log(double aValue) {
    return Math.log(aValue) / Math.log(10);
  }

  public double normal(double mu, double sigma) {
    double r1, r2, v1, v2, s, x1, x2;
    if(sigma == 0.0) {
      x1 = mu;
    } else {
      do {
        do {
          r1 = Math.random(); // uniform random variate over 0..1
          r2 = Math.random();
          v1 = 2 * r1 - 1;
          v2 = 2 * r2 - 1;
          s = v1 * v1 + v2 * v2;
        } while(s >= 1.0);
        x1 = v1 * Math.sqrt(-2 * Math.log(s) / s);
        x1 = mu + sigma * x1;
      } while(x1 < 0.0);
    }
    return x1;
  }

  public class AgeGroup {
    public double[] metInitFct = new double[]
      {0.0, 0.2, 0.4, 0.6, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 1.0};
    public double[] sporAAfter = new double[]
      {0.0, 0.0, 0.0752, 0.1504, 0.3707, 0.5911, 0.7955, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
    public double[] sporBAfter = new double[]
      {0.0, 0.0, -0.01803, -0.0361, -0.0694, -0.1027, -0.0514, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    public double[] lesionNumber = new double[]
      {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    public double[] lesionDiam = new double[]
      {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    public double[] metExpFct = new double[]
      {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
    public double[] metSporFct = new double[]
      {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};

    public AgeGroup() {
      // creates new AgeGroup object
    }
  }

  public class Weather {
    public double[] rainfall = new double[141];
    public double[] temperature = new double[141];
    public double[] humidHrs = new double[141];
    public double[] humidTemp = new double[141];

    public Weather() {
      // create new Weather object
    }
  }

  public class CoolWetWeather extends Weather {

    public CoolWetWeather() {
      // create new CoolWetWeather object
      // populate data arrays
      rainfall = new double[]{
        0.0, 0.14, 0.05, 0.37, 0.0, 1.18, 0.18, 0.0, 0.33, 0.0, 0.14, 0.15,
        0.03, 0.0, 0.0, 0.0, 0.12, 0.25, 0.0, 0.0, 0.0, 0.0, 1.05, 0.89, 0.0,
        0.07, 0.17, 0.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.06, 0.0, 0.0, 0.21, 0.79,
        0.0, 0.0, 0.53, 0.28, 0.0, 0.02, 0.0, 0.32, 0.11, 0.0, 0.14, 0.0, 0.02,
        0.43, 0.12, 0.0, 0.0, 0.04, 0.0, 0.0, 0.0, 0.0, 0.33, 0.06, 0.13, 0.0,
        0.0, 0.26, 0.0, 0.11, 0.02, 0.0, 0.0, 0.1, 0.01, 0.0, 0.0, 0.1, 0.03,
        0.0, 0.0, 0.0, 0.0, 0.02, 0.08, 0.0, 0.0, 0.03, 0.0, 0.0, 0.72, 0.0,
        1.02, 0.0, 0.0, 0.69, 0.0, 0.0, 3.19, 0.32, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.1, 0.48, 0.0, 0.0, 0.11, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.63, 0.0, 0.08, 0.13, 0.0, 0.0, 0.0, 0.22, 0.0, 0.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.09, 0.0, 0.0
      };

      temperature = new double[]{
        7.5,10.5,10.0,13.7,13.0,6.1,12.7,18.1,18.9,18.4,16.4,17.4,16.1,14.4,11.7,13.8,
        6.4,7.9,15.8,8.3,13.4,14.1,16.2,23.7,21.4,16.0,16.8,13.7,19.9,19.2,26.3,18.2,20.1,
        20.5,21.6,21.4,27.0,16.6,12.5,17.7,24.7,24.8,17.6,26.3,19.3,21.7,17.8,23.5,20.4,
        27.4,23.2,23.5,21.6,17.0,21.8,17.9,20.8,29.0,23.9,24.5,22.5,14.4,22.6,20.3,19.2,
        19.6,19.7,22.8,19.2,19.9,19.6,26.5,21.9,21.6,20.2,15.4,21.3,23.0,18.2,17.4,16.5,
        20.5,17.9,17.1,20.4,21.3,19.3,18.2,19.9,24.9,14.9,24.5,15.6,24.7,20.0,19.3,20.2,
        18.1,16.3,19.1,19.1,16.3,17.4,20.5,16.7,16.4,17.1,18.7,26.3,20.6,22.3,19.8,14.1,
        16.5,14.1,19.4,18.1,20.2,16.3,13.3,17.3,9.2,5.2,13.5,7.4,14.9,11.5,13.4,20.2,19.1,
        18.0,19.7,15.4,15.0,16.3,23.0,15.4,13.4,16.7,16.7,16.6
      };

      humidHrs = new double[]{
        11.0,14.0,16.0,24.0,6.0,24.0,22.0,9.0,14.0,12.0,17.0,22.0,19.0,13.0,10.0,8.0,15.0,
        23.0,11.0,8.0,9.0,11.0,22.0,19.0,19.0,21.0,21.0,16.0,10.0,9.0,12.0,10.0,9.0,16.0,
        11.0,10.0,17.0,20.0,9.0,10.0,20.0,17.0,16.0,14.0,11.0,24.0,19.0,8.0,15.0,15.0,18.0,
        22.0,23.0,14.0,11.0,20.0,9.0,14.0,11.0,13.0,23.0,16.0,19.0,9.0,16.0,24.0,16.0,22.0,
        19.0,15.0,11.0,22.0,18.0,13.0,14.0,21.0,19.0,16.0,12.0,12.0,15.0,20.0,22.0,11.0,
        10.0,24.0,16.0,10.0,21.0,14.0,20.0,10.0,13.0,19.0,11.0,17.0,24.0,19.0,14.0,10.0,
        12.0,11.0,12.0,11.0,16.0,8.0,19.0,20.0,16.0,14.0,18.0,14.0,10.0,13.0,12.0,12.0,
        14.0,11.0,20.0,14.0,21.0,20.0,12.0,13.0,16.0,19.0,10.0,8.0,12.0,13.0,11.0,9.0,9.0,
        12.0,11.0,13.0,12.0,19.0,21.0,11.0,11.0
      };

      humidTemp = new double[]{
        5.8,8.0,8.5,10.8,11.8,5.9,9.6,15.0,16.5,16.5,15.7,14.3,13.4,13.7,9.3,10.0,2.6,6.3,
        12.3,7.6,11.5,12.3,15.3,21.9,19.3,12.2,13.9,11.8,18.5,17.7,22.6,14.3,19.1,17.4,19.0,
        19.8,26.4,13.0,12.5,13.8,21.9,24.1,14.8,23.1,17.0,19.1,16.2,23.0,18.6,24.7,20.6,21.4,
        18.2,13.7,18.3,15.1,19.5,25.0,20.2,24.3,19.2,11.1,20.7,19.9,17.4,18.8,17.0,19.8,15.5,
        16.7,17.5,26.3,21.2,19.4,18.6,13.5,18.5,22.3,16.0,15.3,15.9,18.1,15.1,16.1,17.1,19.1,
        17.8,15.3,19.1,24.8,12.7,22.6,14.3,21.4,19.8,19.0,18.4,14.3,15.9,16.4,17.3,15.6,14.1,
        19.2,15.6,13.4,14.8,15.9,23.8,16.7,21.0,18.1,13.0,14.7,13.1,16.8,15.4,16.7,15.1,11.0,
        15.9,7.8,3.3,10.2,5.3,11.9,8.2,12.6,18.1,18.0,15.4,16.2,13.7,11.9,15.6,22.8,14.4,11.5,
        16.2,14.5,13.20
      };

    }
  }

  public class HotDryWeather extends Weather {

    public HotDryWeather() {
      // create new HotDryWeather object
      // populate data arrays
      rainfall = new double[]{
        0,0.02,0.09,0.03,0,0,0,0,0,0,0,0,0.09,0,0,0,0,0,0,0,1.11,0,0.02,0.31,0,0.18,0,
        0,0,0,0.14,0,0,0,0,0,0.35,0,0,0,0,0,0,0.06,0,0.12,0.03,0,0,0,0.02,0,0.54,0.2,
        0,0.12,0,0,0,0,0.13,0.22,0,0,0,0.51,0,0,0.44,0,0,0,0,0,0,0.07,0.07,0,0,0,0,0,
        0,0,0,0,0.2,0,0,0,1.65,0,0.22,0,0,0,0,0.2,0,0,0,0,0.22,0.02,0,0,0,0.06,0,0,0,
        0,0,0,0,0,0,0,0.46,0,0,0,0,0,0,0,0,0.27,0.01,0,0,0.1,1.25,0,0,0,0,1.05,0.46,0,0
      };

      temperature = new double[]{
        13.6,10.8,14.8,21.5,11.7,14.2,9.4,16.5,22.4,21.2,20.7,21.5,19.8,16.8,14,14.7,
        10.1,11.9,18.6,9.8,16.4,17.8,25.5,27,19.1,19.6,24.7,22.2,17.6,27.9,17,22.8,26,
        23.8,28.8,19,22,22.5,16.9,19.6,26.5,28.8,21.5,23.5,23.5,29.6,19.9,27,24.2,30.5,
        25.1,28.6,23.6,21.4,23.2,21.9,26,32.1,26.7,27.9,27.9,17.3,23.6,22.7,22.8,24.7,
        20.1,24.8,22.4,22,23.9,28.7,23.4,23.9,24.9,17.5,25.6,25.2,22.5,20.1,19,22.3,
        21.4,21,24.7,23.1,23.7,19.6,22.9,28.1,15.7,26.8,18.8,26,20.3,22.7,23.8,22.3,
        21.6,22.5,24.6,21.6,22.1,23.7,20.5,18.5,19.7,21.2,28.6,22.6,26.5,22.7,18.4,
        18.3,17.2,24.7,22.1,22.3,18.7,16.5,21.5,13.9,8.4,17.8,9,17.8,12.7,16.6,21.8,
        21.3,20.9,22,18.3,17.9,17.2,26.3,19.9,16.1,20.4,20.2,18.3
      };

      humidHrs = new double[]{
        10,15,16,17,10,7,8,5,7,9,3,8,14,11,8,9,7,5,6,4,16,9,19,18,10,14,8,8,6,13,14,
        10,8,5,6,9,14,10,7,4,9,8,6,18,12,16,20,13,9,8,15,10,18,19,10,18,9,10,6,5,19,
        19,17,12,10,17,13,9,15,11,6,10,8,5,9,21,20,16,11,9,5,9,10,8,5,11,21,9,10,5,
        22,12,22,10,8,9,6,18,12,9,4,9,17,21,10,9,9,22,15,8,7,10,6,5,4,10,8,7,19,16,
        10,8,5,8,10,7,6,19,20,10,8,21,22,11,8,7,9,16,16,10,5
      };

      humidTemp = new double[]{
        11.2,10.4,13,21,8.9,11,7.1,14.4,21,18.8,19.1,17.9,16.8,12.9,10.5,12.8,8.5,
        9.4,16.5,9.6,12.4,16.6,23.3,24.4,15.5,17.8,21.6,18.3,16.4,25.2,13.8,18.9,
        25.1,21.9,27.5,18,22,20.6,14.8,16.8,24.8,26.3,19.1,20.8,21.7,26,17.2,24.5,
        20.5,27.1,24,27,20.8,19.9,19.6,18.1,23.8,28.4,25.5,25.1,26.2,16.8,22.6,
        22.3,21.1,21.1,16.8,24.2,21.3,18.6,23.7,25.5,19.7,20,23.8,15.1,22.4,21.3,
        19.2,20,16.5,19.3,20,20.4,22,22.7,22,15.7,21.2,24.2,11.9,26.5,15.1,25.4,
        17,22.3,22.1,19.7,20.6,22.3,21.4,20.6,20.6,23.4,20.5,18.4,16.9,17.8,25.7,
        19.4,24.1,19,15.4,15.7,13.5,22.6,20,20.5,17.4,13.3,19.3,12.8,4.8,16,8.6,
        17.5,10.3,15.8,19.8,17.5,17.7,21,15.3,14.6,14.3,23.1,16,12.5,20.3,17.6,14.5
      };
    }
  }

  public class ModDryWeather extends Weather {

    public ModDryWeather() {
      // create new ModDryWeather object
      // populate data arrays
      rainfall = new double[]{
        0,0.02,0.09,0.03,0,0,0,0,0,0,0,0,0.09,0,0,0,0,0,0,0,1.11,0,0.02,0.18,0,0.31,
        0,0,0,0,0.14,0,0,0,0,0,0.35,0,0,0,0,0,0,0.06,0,0.12,0.03,0,0,0,0.02,0,0.54,
        0.2,0,0.12,0,0,0,0,0.13,0.22,0,0,0,0.51,0,0,0.44,0,0,0,0,0,0,0.07,0.07,0,0,
        0,0,0,0,0,0,0,0.2,0,0,0,1.65,0,0.22,0,0,0,0,0.2,0,0,0,0,0.22,0.02,0,0,0,0.06,
        0,0,0,0,0,0,0,0,0,0,0.46,0,0,0,0,0,0,0,0,0.27,0.01,0,0,0.1,1.25,0,0,0,0,1.05,
        0.46,0,0
      };

      temperature = new double[]{
        12,9,14,19,11,14,8,14,21,19,20,19,17,16,12,14,9,9,18,9,15,16,23,18,25,17,22,
        21,17,15,27,21,23,22,28,17,22,22,15,18,26,27,20,21,27,23,18,25,23,28,25,26,22,
        20,22,20,23,30,25,25,25,17,23,22,21,22,20,23,21,21,22,27,23,23,23,16,24,23,21,
        20,17,22,19,19,22,23,21,19,21,26,15,26,17,25,20,20,22,20,19,20,22,19,20,23,19,
        18,17,21,28,22,25,21,17,18,15,22,21,22,17,15,19,11,8,16,8,16,12,14,21,20,18,
        20,17,15,17,24,18,15,19,18,18
      };

      humidHrs = new double[]{
        10,15,16,17,10,7,8,5,7,9,3,8,14,11,8,9,7,5,6,4,19,6,19,14,10,18,8,8,6,10,18,
        10,8,5,6,9,14,10,7,4,9,8,6,18,10,16,20,13,9,8,15,10,18,19,10,18,9,10,6,5,19,
        19,17,12,10,17,13,9,15,11,6,10,8,5,9,21,20,16,11,9,5,9,10,8,5,11,21,9,10,5,
        22,12,22,10,8,9,6,18,12,9,4,9,17,21,10,9,9,22,15,8,7,10,6,5,4,10,8,7,19,16,
        10,8,5,8,10,7,6,19,20,10,8,21,22,11,8,7,9,16,16,10,5
      };

      humidTemp = new double[]{
        11,8,14,20,12,12,6,12,17,14,17,15,16,16,10,12,8,6,15,6,15,15,23,19,26,16,23,19,
        15,13,28,18,20,18,26,13,21,22,11,15,25,27,18,21,25,21,16,22,22,28,23,25,19,18,
        19,18,23,30,25,24,25,16,23,21,19,20,17,21,18,19,20,24,19,20,20,14,23,21,18,18,
        15,20,17,18,22,22,20,17,19,24,14,26,15,24,18,18,20,18,17,18,21,16,19,23,17,16,
        15,19,26,19,22,18,14,16,13,20,19,19,14,13,17,9,7,15,7,15,10,13,19,17,15,17,14,
        14,16,23,16,13,16,15,15
      };
    }
  }

  public class ModModWeather extends Weather {

    public ModModWeather() {
      // create new ModModWeather object
      // populate data arrays
      rainfall = new double[]{
        0,0.02,0.09,0.03,0,0,0,0,0,0,0.08,0.95,0.09,0,0,0,0,0,0,0,1.11,0,0.02,0.18,
        0,0.06,0.31,0.14,0,0,0,0,0,0,0,0,0.35,0.06,0.52,0,0.08,0.13,0,0.06,0,0.12,
        0.03,0,0,0,0.02,0.73,0,0.2,0,0.12,0,0,0,0,0.13,0.22,0,0,0,0.51,0,0,0.44,0,
        0,0,0,0,0,0.07,0.07,0,0,0,0,0,0,0,0,0,0.2,0.22,0,0,1.65,0,0.22,0,0,0,0,0.2,
        0,0,0,0,0.22,0.02,0,0,0,0.06,0,0,0,0,0,0,0,0,0,0,0.46,0,0,0,0,0,0,0,0,0.27,
        0.01,0,0.09,0.1,1.25,0,0,0,0,3.05,0.46,0,0
      };

      temperature = new double[]{
        12,9,14,19,11,14,8,14,21,19,20,19,17,16,12,14,9,9,18,9,15,16,23,18,25,17,22,
        21,17,15,27,21,23,22,28,17,22,22,15,18,26,27,20,21,27,23,18,25,23,28,25,26,22,
        20,22,20,23,30,25,25,25,17,23,22,21,22,20,23,21,21,22,27,23,23,23,16,24,23,21,
        20,17,22,19,19,22,23,21,19,21,26,15,26,17,25,20,20,22,20,19,20,22,19,20,23,19,
        18,17,21,28,22,25,21,17,18,15,22,21,22,17,15,19,11,8,16,8,16,12,14,21,20,18,
        20,17,15,17,24,18,15,19,18,18
      };

      humidHrs = new double[]{
        10,15,16,17,10,7,8,8,7,9,19,22,14,11,8,9,7,7,6,10,19,6,19,14,8,15,18,28,8,7,
        13,8,10,11,11,9,14,18,17,12,17,18,6,18,6,16,20,13,11,11,19,24,12,19,10,18,16,
        12,10,13,19,19,17,12,12,17,13,14,15,11,16,10,13,10,9,21,20,16,11,9,12,9,10,
        10,11,11,21,23,9,13,22,12,22,13,11,11,10,18,15,11,11,9,17,21,12,14,11,22,15,
        12,11,10,11,10,11,10,14,10,19,16,10,8,11,8,10,10,10,19,20,10,22,21,22,16,18,
        12,16,16,16,13,13
      };

      humidTemp = new double[]{
        11,8,14,20,12,12,6,12,17,14,17,15,16,16,10,12,8,6,15,6,15,15,23,19,26,16,23,
        19,15,13,28,18,20,18,26,13,21,22,11,15,25,27,18,21,25,21,16,22,22,28,23,25,19,
        18,19,18,23,30,25,24,25,16,23,21,19,20,17,21,18,19,20,24,19,20,20,14,23,21,18,
        18,15,20,17,18,22,22,20,24,17,19,14,26,15,24,18,18,20,18,17,18,21,16,19,23,17,
        16,15,19,26,19,22,18,14,16,13,20,19,19,14,13,17,9,7,15,7,15,10,13,19,17,15,17,
        14,14,16,23,16,13,16,15,15
      };
    }
  }

  public class ModWetWeather extends Weather {

    public ModWetWeather() {
      // create new ModWetWeather object
      // populate data arrays
      rainfall = new double[]{
        0,0.14,0,0.05,0,0.37,1.18,0,0.33,0,0,0.15,0.03,0,0,0,0.12,0.25,0,0,0,0,1.05,
        0.89,0,0.07,0.17,0.09,0,0,0,0,0,0.06,0,0,0.21,0.79,0,0,0.53,0.28,0,0.02,0,
        0.32,0.11,0,0.14,0,0.02,0.43,0.12,0,0,0.04,0,0,0,0,0.33,0.06,0.13,0,0,0.26,
        0,0.11,0.02,0,0,0.1,0.01,0,0,0.1,0.03,0,0,0,0,0.02,0.08,0,0,0.03,0,0,0.72,
        0,1.02,0,0,0.69,0,0,3.19,0.32,0,0,0,0,0,0.1,0,0,0,0.48,0,0,0.11,0,0,0,0,0,0,
        0,0.63,0,0.08,0.13,0,0,0,0.22,0,0,0,0,0,0,0,0,0,0,0,0.01,0.09,0,0
      };

      temperature = new double[]{
        12,9,14,19,11,14,8,14,21,19,20,19,17,16,12,14,9,9,18,9,15,16,23,18,25,17,22,
        21,17,15,27,21,23,22,28,17,22,22,15,18,26,27,20,21,27,23,18,25,23,28,25,26,22,
        20,22,20,23,30,25,25,25,17,23,22,21,22,20,23,21,21,22,27,23,23,23,16,24,23,21,
        20,17,22,19,19,22,23,21,19,21,26,15,26,17,25,20,20,22,20,19,20,22,19,20,23,19,
        18,17,21,28,22,25,21,17,18,15,22,21,22,17,15,19,11,8,16,8,16,12,14,21,20,18,
        20,17,15,17,24,18,15,19,18,18
      };

      humidHrs = new double[]{
        10,14,6,19,9,24,24,12,14,7,12,22,19,13,10,8,15,23,11,8,9,11,22,20,10,21,21,
        19,11,6,12,10,9,16,7,10,21,20,9,10,20,17,16,15,10,24,19,8,15,15,18,22,23,14,
        11,20,9,14,11,13,23,16,19,9,16,24,16,22,19,15,11,22,18,13,14,21,19,16,12,12,
        15,20,22,11,10,24,16,10,21,14,20,10,13,19,11,17,24,19,14,10,12,11,12,19,11,
        16,8,20,16,14,18,14,10,13,12,12,14,11,20,14,21,20,12,13,16,19,10,8,12,13,11,
        9,9,12,11,13,12,19,21,11,11
      };

      humidTemp = new double[]{
        11,8,14,20,12,12,6,12,17,14,17,15,16,16,10,12,8,6,15,6,15,15,23,19,26,16,23,
        19,15,13,28,18,20,18,26,13,21,22,11,15,25,27,18,21,25,21,16,22,22,28,23,25,19,
        18,19,18,23,30,25,24,25,16,23,21,19,20,17,21,18,19,20,24,19,20,20,14,23,21,18,
        18,15,20,17,18,22,22,20,17,19,24,14,26,15,24,18,18,20,18,17,18,21,16,19,16,23,
        17,15,19,26,19,22,18,14,16,13,20,19,19,14,13,17,9,7,15,7,15,10,13,19,17,15,17,
        14,14,16,23,16,13,16,15,15
      };
    }
  }

  public class DataRecord {
    public Vector dateData = new Vector();
    public Vector blightData = new Vector();
    public Vector audpcData = new Vector();
    public Vector leafData = new Vector();
    public Vector temperatureData = new Vector();
    public Vector rainData = new Vector();
    public Vector humidHrsData = new Vector();
    public Vector newInfectionsData = new Vector();
    public Vector sporangiaData = new Vector();
    public Vector systemicResidueData = new Vector();
    public Vector protectantResidueData = new Vector();

    public DataRecord() {
      // creates new DataRecord object
    }
  }

}
