extensions/net.sf.basedb.labenv/trunk/src/net/sf/basedb/labenv/servlet/LabEnvironmentStatisticsServlet.java

Code
Comments
Other
Rev Date Author Line
2303 02 Apr 14 olle 1 package net.sf.basedb.labenv.servlet;
2303 02 Apr 14 olle 2
2303 02 Apr 14 olle 3 import java.io.IOException;
2395 29 Apr 14 olle 4 import java.text.DateFormat;
2303 02 Apr 14 olle 5 import java.text.SimpleDateFormat;
2303 02 Apr 14 olle 6 import java.util.Calendar;
2303 02 Apr 14 olle 7 import java.util.Collections;
2303 02 Apr 14 olle 8 import java.util.Date;
2303 02 Apr 14 olle 9 import java.util.GregorianCalendar;
2303 02 Apr 14 olle 10 import java.util.HashMap;
2303 02 Apr 14 olle 11 import java.util.ArrayList;
2303 02 Apr 14 olle 12 import java.util.List;
2303 02 Apr 14 olle 13
2303 02 Apr 14 olle 14 import javax.servlet.ServletException;
2303 02 Apr 14 olle 15 import javax.servlet.http.HttpServlet;
2303 02 Apr 14 olle 16 import javax.servlet.http.HttpServletRequest;
2303 02 Apr 14 olle 17 import javax.servlet.http.HttpServletResponse;
2303 02 Apr 14 olle 18 import net.sf.basedb.labenv.LabEnv;
2303 02 Apr 14 olle 19 import net.sf.basedb.labenv.LabEnvironment;
2303 02 Apr 14 olle 20 import net.sf.basedb.labenv.LabEnvironmentConfiguration;
2303 02 Apr 14 olle 21 import net.sf.basedb.labenv.converter.DateToStringConverter;
2303 02 Apr 14 olle 22 import net.sf.basedb.labenv.converter.StringToDateConverter;
2303 02 Apr 14 olle 23 import net.sf.basedb.labenv.dao.LabEnvironmentData;
2303 02 Apr 14 olle 24 import net.sf.basedb.labenv.dao.LabSensorConfig;
2303 02 Apr 14 olle 25 import net.sf.basedb.labenv.util.LabEnvironmentStorageUtil;
2303 02 Apr 14 olle 26 import net.sf.basedb.labenv.util.ReportTableUtil;
2303 02 Apr 14 olle 27 import net.sf.basedb.util.Values;
2303 02 Apr 14 olle 28 import net.sf.basedb.util.error.ThrowableUtil;
2303 02 Apr 14 olle 29 import net.sf.basedb.util.formatter.DateFormatter;
2303 02 Apr 14 olle 30
2303 02 Apr 14 olle 31 import org.json.simple.JSONArray;
2303 02 Apr 14 olle 32 import org.json.simple.JSONObject;
2328 08 Apr 14 olle 33 import org.slf4j.Logger;
2328 08 Apr 14 olle 34 import org.slf4j.LoggerFactory;
2303 02 Apr 14 olle 35
2303 02 Apr 14 olle 36 public class LabEnvironmentStatisticsServlet
2303 02 Apr 14 olle 37   extends HttpServlet 
2303 02 Apr 14 olle 38 {
3013 05 Dec 14 nicklas 39   private static final long serialVersionUID = 8523842862909616267L;
3013 05 Dec 14 nicklas 40   
2328 08 Apr 14 olle 41   private static final Logger log = LoggerFactory.getLogger(LabEnvironmentStatisticsServlet.class);
2303 02 Apr 14 olle 42   public static final String weekdayFilterAll = "all";
2303 02 Apr 14 olle 43   public static final String weekdayFilterMondayToFriday = "mondaytofriday";
2303 02 Apr 14 olle 44   public static final String weekdayFilterSaturdayToSunday = "saturdaytosunday";
2395 29 Apr 14 olle 45   public static final String weekdayFilterWorkdays = "workdays";
2395 29 Apr 14 olle 46   public static final String weekdayFilterNonWorkdays = "nonworkdays";
2303 02 Apr 14 olle 47   public static final String variableTypeTemperature = "temperature";
2303 02 Apr 14 olle 48   public static final String variableTypeHumidity = "humidity";
2303 02 Apr 14 olle 49   /**
2303 02 Apr 14 olle 50     Default converter for string values to date+time values: yyyyMMdd HHmm
2303 02 Apr 14 olle 51     @since 1.0
2303 02 Apr 14 olle 52   */
2303 02 Apr 14 olle 53   public static final StringToDateConverter CONVERTER_STRING_TO_DATETIME = new StringToDateConverter(new SimpleDateFormat("yyyyMMdd HHmm"));
2303 02 Apr 14 olle 54   public static final StringToDateConverter CONVERTER_STRING_TO_DATE = new StringToDateConverter(new SimpleDateFormat("yyyy-MM-dd"));
2303 02 Apr 14 olle 55
2303 02 Apr 14 olle 56   private ReportTableUtil tableUtil;
2303 02 Apr 14 olle 57
2303 02 Apr 14 olle 58   private static int numberOfDecimals = 1;
2303 02 Apr 14 olle 59   private int minItemsForStatisticsCalculation = 5;
2395 29 Apr 14 olle 60   private DateFormat yearMonthDayFormat = new SimpleDateFormat("YYYYMMdd");
2395 29 Apr 14 olle 61   private DateFormat monthDayFormat = new SimpleDateFormat("MMdd");
2395 29 Apr 14 olle 62   private HashMap<String, Boolean> workdayFlagSeHashMap = new HashMap<String, Boolean>();
2395 29 Apr 14 olle 63   
2303 02 Apr 14 olle 64   public LabEnvironmentStatisticsServlet()
2303 02 Apr 14 olle 65   {
2303 02 Apr 14 olle 66     // Create new instance of ReportTableUtil for common report table utilities
2303 02 Apr 14 olle 67     tableUtil = new ReportTableUtil();
2303 02 Apr 14 olle 68   }
2303 02 Apr 14 olle 69
2303 02 Apr 14 olle 70
2303 02 Apr 14 olle 71   @Override
2303 02 Apr 14 olle 72   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
2303 02 Apr 14 olle 73     throws ServletException, IOException 
2303 02 Apr 14 olle 74   {  
2303 02 Apr 14 olle 75     String ID = req.getParameter("ID");
2303 02 Apr 14 olle 76     String cmd = req.getParameter("cmd");
2303 02 Apr 14 olle 77     resp.setContentType("application/json");
2303 02 Apr 14 olle 78     resp.setCharacterEncoding("UTF-8");
2303 02 Apr 14 olle 79     
2303 02 Apr 14 olle 80     JSONObject json = new JSONObject();
2303 02 Apr 14 olle 81     json.put("status", "ok");
2303 02 Apr 14 olle 82
2303 02 Apr 14 olle 83     try
2303 02 Apr 14 olle 84     {
2303 02 Apr 14 olle 85       log.debug("cmd = " + cmd);
2303 02 Apr 14 olle 86       if ("labenvironmentdailydistribution".equals(cmd) || "labenvironmentweeklydistribution".equals(cmd))
2303 02 Apr 14 olle 87       {
2303 02 Apr 14 olle 88         String viewType = "dailyDistribution";
2303 02 Apr 14 olle 89         if ("labenvironmentweeklydistribution".equals(cmd))
2303 02 Apr 14 olle 90         {
2303 02 Apr 14 olle 91           viewType = "weeklyDistribution";
2303 02 Apr 14 olle 92         }
2303 02 Apr 14 olle 93         // Get query time interval
2303 02 Apr 14 olle 94         String startDateStr = Values.getString(req.getParameter("fdate"), null);
2303 02 Apr 14 olle 95         String startTimeStr = Values.getString(req.getParameter("ftime"), null);
2303 02 Apr 14 olle 96         String endDateStr = Values.getString(req.getParameter("tdate"), null);
2303 02 Apr 14 olle 97         String endTimeStr = Values.getString(req.getParameter("ttime"), null);
2303 02 Apr 14 olle 98         String startDateTimeStr = dateAndTimeStringsToDateTimeString(startDateStr, startTimeStr);
2303 02 Apr 14 olle 99         String endDateTimeStr = dateAndTimeStringsToDateTimeString(endDateStr, endTimeStr);
2303 02 Apr 14 olle 100         Date startTime = dateTimeStringToDate(startDateTimeStr);
2303 02 Apr 14 olle 101         Date endTime = dateTimeStringToDate(endDateTimeStr);
2395 29 Apr 14 olle 102         // Optional weekday filter
2303 02 Apr 14 olle 103         String weekdayFilter = null;
2303 02 Apr 14 olle 104         String weekdayFilterParameter = Values.getString(req.getParameter("weekdayfilter"), null);
2303 02 Apr 14 olle 105         if (weekdayFilterParameter != null)
2303 02 Apr 14 olle 106         {
2303 02 Apr 14 olle 107           weekdayFilter = weekdayFilterParameter;
2303 02 Apr 14 olle 108         }
2303 02 Apr 14 olle 109         log.debug("weekdayFilter = " + weekdayFilter);
2395 29 Apr 14 olle 110         // Optional daytime filter
2395 29 Apr 14 olle 111         String filterFromTime = null;
2395 29 Apr 14 olle 112         String filterFromTimeParameter = Values.getString(req.getParameter("filterfromtime"), null);
2395 29 Apr 14 olle 113         if (filterFromTimeParameter != null)
2395 29 Apr 14 olle 114         {
2395 29 Apr 14 olle 115           filterFromTime = filterFromTimeParameter;
2395 29 Apr 14 olle 116         }
2395 29 Apr 14 olle 117         log.debug("filterFromTime = " + filterFromTime);
2395 29 Apr 14 olle 118         String filterToTime = null;
2395 29 Apr 14 olle 119         String filterToTimeParameter = Values.getString(req.getParameter("filtertotime"), null);
2395 29 Apr 14 olle 120         if (filterToTimeParameter != null)
2395 29 Apr 14 olle 121         {
2395 29 Apr 14 olle 122           filterToTime = filterToTimeParameter;
2395 29 Apr 14 olle 123         }
2395 29 Apr 14 olle 124         log.debug("filterToTime = " + filterToTime);
2303 02 Apr 14 olle 125         String chartVariant = "all";
2303 02 Apr 14 olle 126         String chartVariantParameter = Values.getString(req.getParameter("cvariant"), null);
2303 02 Apr 14 olle 127         if (chartVariantParameter != null)
2303 02 Apr 14 olle 128         {
2303 02 Apr 14 olle 129           chartVariant = chartVariantParameter;
2303 02 Apr 14 olle 130         }
2303 02 Apr 14 olle 131         log.debug("chartVariant = " + chartVariant);
2303 02 Apr 14 olle 132         // Get lab environment configuration from singleton LabEnvironment
2303 02 Apr 14 olle 133         LabEnvironment labEnvironment = LabEnvironment.getInstance();
2303 02 Apr 14 olle 134         LabEnvironmentConfiguration labEnvironmentConfiguration = labEnvironment.getLabEnvironmentConfiguration();
2303 02 Apr 14 olle 135         // Create sensor URL list
2303 02 Apr 14 olle 136         List<String> sensorUrlList = new ArrayList<String>();
2303 02 Apr 14 olle 137         if (chartVariant.equals("all"))
2303 02 Apr 14 olle 138         {
2303 02 Apr 14 olle 139           List<LabSensorConfig> labSensorConfigList = labEnvironmentConfiguration.getLabSensorConfigList();
2303 02 Apr 14 olle 140           for (LabSensorConfig labSensorConf: labSensorConfigList)
2303 02 Apr 14 olle 141           {
2303 02 Apr 14 olle 142             String startDate = labSensorConf.getStartDate();
2303 02 Apr 14 olle 143             if (startDate != null && !startDate.equals(""))
2303 02 Apr 14 olle 144             {
2303 02 Apr 14 olle 145               sensorUrlList.add(labSensorConf.getUrl());
2303 02 Apr 14 olle 146             }
2303 02 Apr 14 olle 147           }
2303 02 Apr 14 olle 148         }
2303 02 Apr 14 olle 149         else
2303 02 Apr 14 olle 150         {
2303 02 Apr 14 olle 151           sensorUrlList.add(chartVariant);
2303 02 Apr 14 olle 152         }
2303 02 Apr 14 olle 153         log.debug("chartVariant = " + chartVariant + " sensorUrlList = " + sensorUrlList);
2303 02 Apr 14 olle 154         // Create JSON array for plot data
2303 02 Apr 14 olle 155         JSONArray jsonStatisticsPlotArray = new JSONArray();
3018 09 Dec 14 nicklas 156         LabEnvironmentStorageUtil storage = new LabEnvironmentStorageUtil();
2303 02 Apr 14 olle 157         for (String sensorUrl: sensorUrlList)
2303 02 Apr 14 olle 158         {
2303 02 Apr 14 olle 159           // Get lab sensor number from lab sensor url
2303 02 Apr 14 olle 160           LabSensorConfig labSensorConfig = labEnvironmentConfiguration.findByUrl(sensorUrl);
2303 02 Apr 14 olle 161           Integer labSensorNumber = null;
2303 02 Apr 14 olle 162           String sensorName = "Sensor";
2303 02 Apr 14 olle 163           if (labSensorConfig != null)
2303 02 Apr 14 olle 164           {
2303 02 Apr 14 olle 165             labSensorNumber = labSensorConfig.getNumber();
2303 02 Apr 14 olle 166             sensorName = labSensorConfig.getName();
2303 02 Apr 14 olle 167           }
2303 02 Apr 14 olle 168           log.debug("labSensorNumber = " + labSensorNumber + " startTime = " + startTime + " endTime = " + endTime);
2303 02 Apr 14 olle 169           // Perform database query
3018 09 Dec 14 nicklas 170           List<LabEnvironmentData> lthdList = storage.queryLabEnvDb(labSensorNumber, startTime, endTime);
2303 02 Apr 14 olle 171           // Apply optional weekday filter
2395 29 Apr 14 olle 172           if ("labenvironmentdailydistribution".equals(cmd) || "labenvironmentweeklydistribution".equals(cmd))
2303 02 Apr 14 olle 173           {
2395 29 Apr 14 olle 174             lthdList = applyWeekdayFilter(weekdayFilter, lthdList);
2303 02 Apr 14 olle 175           }
2395 29 Apr 14 olle 176           // Apply optional daytime filter
2395 29 Apr 14 olle 177           if ("labenvironmentweeklydistribution".equals(cmd))
2303 02 Apr 14 olle 178           {
2395 29 Apr 14 olle 179             lthdList = applyDaytimeFilter(filterFromTime, filterToTime, lthdList);
2303 02 Apr 14 olle 180           }
2303 02 Apr 14 olle 181           // Create JSON statistics for daily distribution
2395 29 Apr 14 olle 182           jsonStatisticsPlotArray = createLabEnvironmentDailyDistributionReport(jsonStatisticsPlotArray, lthdList, startTime, endTime, chartVariant, viewType, sensorName, weekdayFilter, filterFromTime, filterToTime);
2303 02 Apr 14 olle 183         }
2303 02 Apr 14 olle 184         // Create JSON report
2303 02 Apr 14 olle 185         JSONObject jsonReport = new JSONObject();
2303 02 Apr 14 olle 186         // Add JSON statistics plot array to report
2303 02 Apr 14 olle 187         jsonReport.put("plotStatistics", jsonStatisticsPlotArray);
2303 02 Apr 14 olle 188 /*
2303 02 Apr 14 olle 189         // Appended info
2303 02 Apr 14 olle 190         String appendedInfoText = "";
2303 02 Apr 14 olle 191         // Add info on special samples if chart for min to RNAlater is selected
2303 02 Apr 14 olle 192         if (chartVariantList.contains(minutesToRnaLaterChart))
2303 02 Apr 14 olle 193         {
2303 02 Apr 14 olle 194           appendedInfoText += "<h2 class=\"pagebreak\">Appended Info</h2>";
2303 02 Apr 14 olle 195           appendedInfoText += "<br>";
2303 02 Apr 14 olle 196         }
2303 02 Apr 14 olle 197         // Add JSON appended info to report
2303 02 Apr 14 olle 198         jsonReport.put("appendedInfo", appendedInfoText);
2303 02 Apr 14 olle 199 */
2303 02 Apr 14 olle 200         // Add other data to report
2303 02 Apr 14 olle 201         DateToStringConverter date2StringConverter = LabEnv.CONVERTER_DATE_TO_STRING;
2303 02 Apr 14 olle 202         jsonReport.put("beginDate", date2StringConverter.convert(startTime));
2303 02 Apr 14 olle 203         jsonReport.put("endDate", date2StringConverter.convert(endTime));
2303 02 Apr 14 olle 204         //
2303 02 Apr 14 olle 205         json.put("report", jsonReport);
2303 02 Apr 14 olle 206       }
2303 02 Apr 14 olle 207     }
2303 02 Apr 14 olle 208     catch (Throwable t)
2303 02 Apr 14 olle 209     {
2303 02 Apr 14 olle 210       t.printStackTrace();
2303 02 Apr 14 olle 211       json.clear();
2303 02 Apr 14 olle 212       json.put("status", "error");
2303 02 Apr 14 olle 213       json.put("message", t.getMessage());
2303 02 Apr 14 olle 214       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
2303 02 Apr 14 olle 215     }
2303 02 Apr 14 olle 216     finally
2303 02 Apr 14 olle 217     {
2303 02 Apr 14 olle 218       json.writeJSONString(resp.getWriter());
2303 02 Apr 14 olle 219     }
2303 02 Apr 14 olle 220   }
2303 02 Apr 14 olle 221
2303 02 Apr 14 olle 222
2303 02 Apr 14 olle 223   /**
2303 02 Apr 14 olle 224    * Apply weekday filter to raw lab environment data list.
2303 02 Apr 14 olle 225    * 
2303 02 Apr 14 olle 226    * @param weekdayFilter String Weekday filter option.
2303 02 Apr 14 olle 227    * @param lthdRawList List<LabEnvironmentData> Raw lab environment data list.
2395 29 Apr 14 olle 228    * @return List<LabEnvironmentData> Lab environment data list after applying weekday filter. 
2303 02 Apr 14 olle 229    */
2303 02 Apr 14 olle 230   private List<LabEnvironmentData> applyWeekdayFilter(String weekdayFilter, List<LabEnvironmentData> lthdRawList)
2303 02 Apr 14 olle 231   {    
2303 02 Apr 14 olle 232     // Apply optional weekday filter
2303 02 Apr 14 olle 233     List<LabEnvironmentData> lthdList = new ArrayList<LabEnvironmentData>(); 
2303 02 Apr 14 olle 234     if (weekdayFilter == null || weekdayFilter.equals(weekdayFilterAll))
2303 02 Apr 14 olle 235     {
2303 02 Apr 14 olle 236       lthdList = lthdRawList;
2303 02 Apr 14 olle 237     }
2303 02 Apr 14 olle 238     else if (weekdayFilter.equals(weekdayFilterMondayToFriday))
2303 02 Apr 14 olle 239     {
2303 02 Apr 14 olle 240       for (LabEnvironmentData lthd: lthdRawList)
2303 02 Apr 14 olle 241       {
2303 02 Apr 14 olle 242         if (lthd != null)
2303 02 Apr 14 olle 243         {
2303 02 Apr 14 olle 244           long unixTimeInSeconds = lthd.getUnixTime();
2303 02 Apr 14 olle 245           Calendar cal = GregorianCalendar.getInstance();
2303 02 Apr 14 olle 246           cal.setTimeInMillis(unixTimeInSeconds*1000L);
2303 02 Apr 14 olle 247           int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
2303 02 Apr 14 olle 248           if (dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY)
2303 02 Apr 14 olle 249           {
2303 02 Apr 14 olle 250             lthdList.add(lthd);
2303 02 Apr 14 olle 251           }
2303 02 Apr 14 olle 252         }
2303 02 Apr 14 olle 253       }
2303 02 Apr 14 olle 254     }
2303 02 Apr 14 olle 255     else if (weekdayFilter.equals(weekdayFilterSaturdayToSunday))
2303 02 Apr 14 olle 256     {
2303 02 Apr 14 olle 257       for (LabEnvironmentData lthd: lthdRawList)
2303 02 Apr 14 olle 258       {
2303 02 Apr 14 olle 259         if (lthd != null)
2303 02 Apr 14 olle 260         {
2303 02 Apr 14 olle 261           long unixTimeInSeconds = lthd.getUnixTime();
2303 02 Apr 14 olle 262           Calendar cal = GregorianCalendar.getInstance();
2303 02 Apr 14 olle 263           cal.setTimeInMillis(unixTimeInSeconds*1000L);
2303 02 Apr 14 olle 264           int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
2303 02 Apr 14 olle 265           if (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY)
2303 02 Apr 14 olle 266           {
2303 02 Apr 14 olle 267             lthdList.add(lthd);
2303 02 Apr 14 olle 268           }
2303 02 Apr 14 olle 269         }
2303 02 Apr 14 olle 270       }
2303 02 Apr 14 olle 271     }
2395 29 Apr 14 olle 272     else if (weekdayFilter.equals(weekdayFilterWorkdays))
2395 29 Apr 14 olle 273     {
2395 29 Apr 14 olle 274       for (LabEnvironmentData lthd: lthdRawList)
2395 29 Apr 14 olle 275       {
2395 29 Apr 14 olle 276         if (lthd != null)
2395 29 Apr 14 olle 277         {
2395 29 Apr 14 olle 278           long unixTimeInSeconds = lthd.getUnixTime();
2395 29 Apr 14 olle 279           Date date = new Date(unixTimeInSeconds*1000L);
2395 29 Apr 14 olle 280           if (dayIsWorkday(date, "se"))
2395 29 Apr 14 olle 281           {
2395 29 Apr 14 olle 282             lthdList.add(lthd);
2395 29 Apr 14 olle 283           }
2395 29 Apr 14 olle 284         }
2395 29 Apr 14 olle 285       }
2395 29 Apr 14 olle 286     }
2395 29 Apr 14 olle 287     else if (weekdayFilter.equals(weekdayFilterNonWorkdays))
2395 29 Apr 14 olle 288     {
2395 29 Apr 14 olle 289       for (LabEnvironmentData lthd: lthdRawList)
2395 29 Apr 14 olle 290       {
2395 29 Apr 14 olle 291         if (lthd != null)
2395 29 Apr 14 olle 292         {
2395 29 Apr 14 olle 293           long unixTimeInSeconds = lthd.getUnixTime();
2395 29 Apr 14 olle 294           Date date = new Date(unixTimeInSeconds*1000L);
2395 29 Apr 14 olle 295           if (!dayIsWorkday(date, "se"))
2395 29 Apr 14 olle 296           {
2395 29 Apr 14 olle 297             lthdList.add(lthd);
2395 29 Apr 14 olle 298           }
2395 29 Apr 14 olle 299         }
2395 29 Apr 14 olle 300       }
2395 29 Apr 14 olle 301     }
2303 02 Apr 14 olle 302     return lthdList;
2303 02 Apr 14 olle 303   }
2303 02 Apr 14 olle 304
2395 29 Apr 14 olle 305
2395 29 Apr 14 olle 306   /**
2415 09 May 14 olle 307    * Check if a date passes an optional weekday filter.
2415 09 May 14 olle 308    * Returns `false` if date is `null`.
2415 09 May 14 olle 309    * 
2415 09 May 14 olle 310    * @param date Date The date to check.
2415 09 May 14 olle 311    * @param weekdayFilter String Weekday filter option.
2415 09 May 14 olle 312    * @return boolean Returns `true` if date should be included according to optional weekday filter, else `false`. 
2415 09 May 14 olle 313    */
2415 09 May 14 olle 314   public boolean includeWeekday(Date date, String weekdayFilter)
2415 09 May 14 olle 315   {
2415 09 May 14 olle 316     if (date == null)
2415 09 May 14 olle 317     {
2415 09 May 14 olle 318       return false;
2415 09 May 14 olle 319     }
2415 09 May 14 olle 320     // Apply optional weekday filter
2415 09 May 14 olle 321     boolean includeDate = false;
2415 09 May 14 olle 322     if (weekdayFilter == null || weekdayFilter.equals(weekdayFilterAll))
2415 09 May 14 olle 323     {
2415 09 May 14 olle 324       includeDate = true;
2415 09 May 14 olle 325     }
2415 09 May 14 olle 326     else if (weekdayFilter.equals(weekdayFilterMondayToFriday))
2415 09 May 14 olle 327     {
2415 09 May 14 olle 328       Calendar cal = GregorianCalendar.getInstance();
2415 09 May 14 olle 329       cal.setTime(date);
2415 09 May 14 olle 330       int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
2415 09 May 14 olle 331       if (dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY)
2415 09 May 14 olle 332       {
2415 09 May 14 olle 333         includeDate = true;
2415 09 May 14 olle 334       }
2415 09 May 14 olle 335     }
2415 09 May 14 olle 336     else if (weekdayFilter.equals(weekdayFilterSaturdayToSunday))
2415 09 May 14 olle 337     {
2415 09 May 14 olle 338       Calendar cal = GregorianCalendar.getInstance();
2415 09 May 14 olle 339       cal.setTime(date);
2415 09 May 14 olle 340       int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
2415 09 May 14 olle 341       if (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY)
2415 09 May 14 olle 342       {
2415 09 May 14 olle 343         includeDate = true;
2415 09 May 14 olle 344       }
2415 09 May 14 olle 345     }
2415 09 May 14 olle 346     else if (weekdayFilter.equals(weekdayFilterWorkdays))
2415 09 May 14 olle 347     {
2415 09 May 14 olle 348       if (dayIsWorkday(date, "se"))
2415 09 May 14 olle 349       {
2415 09 May 14 olle 350         includeDate = true;
2415 09 May 14 olle 351       }
2415 09 May 14 olle 352     }
2415 09 May 14 olle 353     else if (weekdayFilter.equals(weekdayFilterNonWorkdays))
2415 09 May 14 olle 354     {
2415 09 May 14 olle 355       if (!dayIsWorkday(date, "se"))
2415 09 May 14 olle 356       {
2415 09 May 14 olle 357         includeDate = true;
2415 09 May 14 olle 358       }
2415 09 May 14 olle 359     }
2415 09 May 14 olle 360     return includeDate;
2415 09 May 14 olle 361   }
2415 09 May 14 olle 362
2415 09 May 14 olle 363
2415 09 May 14 olle 364   /**
2395 29 Apr 14 olle 365    * Checks if a date is a work day.
2395 29 Apr 14 olle 366    * 
2395 29 Apr 14 olle 367    * @param date Date Date to check for work day status.
2395 29 Apr 14 olle 368    * @param countryCode String Code for country when checking for work day status ("se" -> Sweden).
2395 29 Apr 14 olle 369    * @return Boolean Returns `true` if day is work day, else `false`, or `null` if status could not be determined.
2395 29 Apr 14 olle 370    */
2395 29 Apr 14 olle 371   public Boolean dayIsWorkday(Date date, String countryCode)
2395 29 Apr 14 olle 372   {
2395 29 Apr 14 olle 373     Boolean dayIsWorkday = null;
2395 29 Apr 14 olle 374     if (date != null && countryCode != null && !countryCode.equals(""))
2395 29 Apr 14 olle 375     {
2395 29 Apr 14 olle 376       if (countryCode.equals("se"))
2395 29 Apr 14 olle 377       {
2395 29 Apr 14 olle 378         // Check if result is stored for day of interest
2395 29 Apr 14 olle 379         String yearMonthDayStr = yearMonthDayFormat.format(date);
2395 29 Apr 14 olle 380         if (workdayFlagSeHashMap.containsKey(yearMonthDayStr))
2395 29 Apr 14 olle 381         {
2395 29 Apr 14 olle 382           dayIsWorkday = workdayFlagSeHashMap.get(yearMonthDayStr);
2395 29 Apr 14 olle 383         }
2395 29 Apr 14 olle 384         if (dayIsWorkday == null)
2395 29 Apr 14 olle 385         {
2395 29 Apr 14 olle 386           dayIsWorkday = true;
2395 29 Apr 14 olle 387           String debugStr = "";
2395 29 Apr 14 olle 388           // Check for Saturdays and Sundays
2395 29 Apr 14 olle 389           Calendar cal = GregorianCalendar.getInstance();
2395 29 Apr 14 olle 390           cal.setTime(date);
2395 29 Apr 14 olle 391           int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
2395 29 Apr 14 olle 392           if (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY)
2395 29 Apr 14 olle 393           {
2395 29 Apr 14 olle 394             dayIsWorkday = false;
2395 29 Apr 14 olle 395             if (dayOfWeek == Calendar.SATURDAY)
2395 29 Apr 14 olle 396             {
2395 29 Apr 14 olle 397               debugStr = "Saturday";
2395 29 Apr 14 olle 398             }
2395 29 Apr 14 olle 399             else if (dayOfWeek == Calendar.SUNDAY)
2395 29 Apr 14 olle 400             {
2395 29 Apr 14 olle 401               debugStr = "Sunday";
2395 29 Apr 14 olle 402             }
2395 29 Apr 14 olle 403           }
2395 29 Apr 14 olle 404           if (dayIsWorkday)
2395 29 Apr 14 olle 405           {
2395 29 Apr 14 olle 406             // Check for fixed date holidays
2395 29 Apr 14 olle 407             String monthDayStr = monthDayFormat.format(date);
2395 29 Apr 14 olle 408             if (monthDayStr.equals("0101"))
2395 29 Apr 14 olle 409             {
2395 29 Apr 14 olle 410               // New Year's Day
2395 29 Apr 14 olle 411               dayIsWorkday = false;
2395 29 Apr 14 olle 412               debugStr = "New Year's Day";
2395 29 Apr 14 olle 413             }
2395 29 Apr 14 olle 414             else if (monthDayStr.equals("0106"))
2395 29 Apr 14 olle 415             {
2395 29 Apr 14 olle 416               // Epiphany ("Trettondagen")
2395 29 Apr 14 olle 417               dayIsWorkday = false;
2395 29 Apr 14 olle 418               debugStr = "Epiphany";
2395 29 Apr 14 olle 419             }
2395 29 Apr 14 olle 420             else if (monthDayStr.equals("0501"))
2395 29 Apr 14 olle 421             {
2395 29 Apr 14 olle 422               // May 1st
2395 29 Apr 14 olle 423               dayIsWorkday = false;
2395 29 Apr 14 olle 424               debugStr = "May 1st";
2395 29 Apr 14 olle 425             }
2395 29 Apr 14 olle 426             else if (monthDayStr.equals("0606"))
2395 29 Apr 14 olle 427             {
2395 29 Apr 14 olle 428               // National Day of Sweden ("Sveriges nationaldag och svenska flaggans dag")
2395 29 Apr 14 olle 429               dayIsWorkday = false;
2395 29 Apr 14 olle 430               debugStr = "National Day of Sweden";
2395 29 Apr 14 olle 431             }
2395 29 Apr 14 olle 432             else if (monthDayStr.equals("1224"))
2395 29 Apr 14 olle 433             {
2395 29 Apr 14 olle 434               // Christmas Eve
2395 29 Apr 14 olle 435               dayIsWorkday = false;
2395 29 Apr 14 olle 436               debugStr = "Cristmas Eve";
2395 29 Apr 14 olle 437             }
2395 29 Apr 14 olle 438             else if (monthDayStr.equals("1225"))
2395 29 Apr 14 olle 439             {
2395 29 Apr 14 olle 440               // Christmas Day
2395 29 Apr 14 olle 441               dayIsWorkday = false;
2395 29 Apr 14 olle 442               debugStr = "Cristmas Day";
2395 29 Apr 14 olle 443             }
2395 29 Apr 14 olle 444             else if (monthDayStr.equals("1226"))
2395 29 Apr 14 olle 445             {
2395 29 Apr 14 olle 446               // Boxing Day ("Annandag jul")
2395 29 Apr 14 olle 447               dayIsWorkday = false;
2395 29 Apr 14 olle 448               debugStr = "Boxing Day";
2395 29 Apr 14 olle 449             }
2395 29 Apr 14 olle 450             else if (monthDayStr.equals("1231"))
2395 29 Apr 14 olle 451             {
2395 29 Apr 14 olle 452               // New Year's Eve
2395 29 Apr 14 olle 453               dayIsWorkday = false;
2395 29 Apr 14 olle 454               debugStr = "New Year's Eve";
2395 29 Apr 14 olle 455             }
2395 29 Apr 14 olle 456             if (dayIsWorkday)
2395 29 Apr 14 olle 457             {
2395 29 Apr 14 olle 458               // Check for holidays related to Easter
2395 29 Apr 14 olle 459               int year = cal.get(Calendar.YEAR);
2395 29 Apr 14 olle 460               Date easterSundayDate = easterSundayDateGregorianCalendar(year);
2395 29 Apr 14 olle 461               //log.debug("year = " + year + " Easter Sunday date = " + easterSundayDate);
2395 29 Apr 14 olle 462               Calendar easterSundayCal = GregorianCalendar.getInstance();
2395 29 Apr 14 olle 463               easterSundayCal.setTime(easterSundayDate);
2395 29 Apr 14 olle 464               // Good Friday ("Långfredag")
2395 29 Apr 14 olle 465               Date goodFridayDate = addDays(easterSundayDate, -2);
2395 29 Apr 14 olle 466               String goodFridayStr = yearMonthDayFormat.format(goodFridayDate);
2395 29 Apr 14 olle 467               if (yearMonthDayStr.equals(goodFridayStr))
2395 29 Apr 14 olle 468               {
2395 29 Apr 14 olle 469                 dayIsWorkday = false;
2395 29 Apr 14 olle 470                 debugStr = "Good Friday";
2395 29 Apr 14 olle 471               }
2395 29 Apr 14 olle 472               else
2395 29 Apr 14 olle 473               {
2395 29 Apr 14 olle 474                 // Easter Monday ("Annandag påsk")
2395 29 Apr 14 olle 475                 Date easterMondayDate = addDays(easterSundayDate, 1);
2395 29 Apr 14 olle 476                 String easterMondayStr = yearMonthDayFormat.format(easterMondayDate);
2395 29 Apr 14 olle 477                 if (yearMonthDayStr.equals(easterMondayStr))
2395 29 Apr 14 olle 478                 {
2395 29 Apr 14 olle 479                   dayIsWorkday = false;
2395 29 Apr 14 olle 480                   debugStr = "Easter Monday";
2395 29 Apr 14 olle 481                 }
2395 29 Apr 14 olle 482                 else
2395 29 Apr 14 olle 483                 {
2395 29 Apr 14 olle 484                   // Ascension Day ("Kristi Himmelsfärdsdag")
2395 29 Apr 14 olle 485                   Date ascensionDayDate = addDays(easterSundayDate, 39);
2395 29 Apr 14 olle 486                   String ascensionDayStr = yearMonthDayFormat.format(ascensionDayDate);
2395 29 Apr 14 olle 487                   if (yearMonthDayStr.equals(ascensionDayStr))
2395 29 Apr 14 olle 488                   {
2395 29 Apr 14 olle 489                     dayIsWorkday = false;
2395 29 Apr 14 olle 490                     debugStr = "Ascension Day";
2395 29 Apr 14 olle 491                   }              
2395 29 Apr 14 olle 492                 }
2395 29 Apr 14 olle 493               }
2395 29 Apr 14 olle 494               if (dayIsWorkday)
2395 29 Apr 14 olle 495               {
2395 29 Apr 14 olle 496                 // Check for Midsummer's Eve
2395 29 Apr 14 olle 497                 // In Sweden since 1953 Midsummer's Eve is the Friday in the 7-day period June 19th - 25th
2395 29 Apr 14 olle 498                 // Get day in week of June 19th
2395 29 Apr 14 olle 499                 Calendar tmpCal = GregorianCalendar.getInstance();
2395 29 Apr 14 olle 500                 tmpCal.set(Calendar.YEAR, year);
2395 29 Apr 14 olle 501                 tmpCal.set(Calendar.MONTH, 6-1);
2395 29 Apr 14 olle 502                 tmpCal.set(Calendar.DATE, 19);
2395 29 Apr 14 olle 503                 // Day of week is 1 for Sunday, 2 for Monday, ... , 6 for Friday, 7 for Saturday 
2395 29 Apr 14 olle 504                 dayOfWeek = tmpCal.get(Calendar.DAY_OF_WEEK);
2395 29 Apr 14 olle 505                 int daysToFriday = 6 - dayOfWeek;
2395 29 Apr 14 olle 506                 if (daysToFriday < 0)
2395 29 Apr 14 olle 507                 {
2395 29 Apr 14 olle 508                   daysToFriday += 7;
2395 29 Apr 14 olle 509                 }
2395 29 Apr 14 olle 510                 // Get date for Midsummer's Eve Friday
2395 29 Apr 14 olle 511                 tmpCal.add(Calendar.DATE, daysToFriday);
2395 29 Apr 14 olle 512                 Date midsummersEveDate = tmpCal.getTime();
2395 29 Apr 14 olle 513                 String midsummersEveStr = yearMonthDayFormat.format(midsummersEveDate);
2395 29 Apr 14 olle 514                 if (yearMonthDayStr.equals(midsummersEveStr))
2395 29 Apr 14 olle 515                 {
2395 29 Apr 14 olle 516                   dayIsWorkday = false;
2395 29 Apr 14 olle 517                   debugStr = "Midsummer's Eve";  
2395 29 Apr 14 olle 518                 }
2395 29 Apr 14 olle 519               }
2395 29 Apr 14 olle 520             }
2395 29 Apr 14 olle 521           }
2395 29 Apr 14 olle 522           // Store value for current day
2395 29 Apr 14 olle 523           workdayFlagSeHashMap.put(yearMonthDayStr, dayIsWorkday);
2395 29 Apr 14 olle 524           if (debugStr != null && !debugStr.equals(""))
2395 29 Apr 14 olle 525           {            
2395 29 Apr 14 olle 526             log.debug("date = " + yearMonthDayStr + " is " + debugStr);
2395 29 Apr 14 olle 527           }
2395 29 Apr 14 olle 528         }
2395 29 Apr 14 olle 529       }
2395 29 Apr 14 olle 530     }
2395 29 Apr 14 olle 531     return dayIsWorkday;
2395 29 Apr 14 olle 532   }
2395 29 Apr 14 olle 533
2395 29 Apr 14 olle 534
2395 29 Apr 14 olle 535   /**
2395 29 Apr 14 olle 536    * Returns the date of Easter Sunday in the Gregorian calendar
2395 29 Apr 14 olle 537    * for a specified year. The “Meeus/Jones/Butcher” algorithm
2395 29 Apr 14 olle 538    * is used for the date calculation.
2395 29 Apr 14 olle 539    * 
2395 29 Apr 14 olle 540    * @param year int The year to calculate Easter Sunday date for.
2395 29 Apr 14 olle 541    * @return Date Date for Easter Sunday in the Gregorian calendar for the specified year.
2395 29 Apr 14 olle 542    */
2395 29 Apr 14 olle 543   public Date easterSundayDateGregorianCalendar(int year)
2395 29 Apr 14 olle 544   {
2395 29 Apr 14 olle 545     int a = year % 19;
2395 29 Apr 14 olle 546     int b = year/100;
2395 29 Apr 14 olle 547     int c = year % 100;
2395 29 Apr 14 olle 548     int d = b/4;
2395 29 Apr 14 olle 549     int e = b % 4;
2395 29 Apr 14 olle 550     int f = ((b + 8)/25);
2395 29 Apr 14 olle 551     int g = ((b - f + 1)/3);
2395 29 Apr 14 olle 552     int h = (19*a + b - d - g + 15) % 30;
2395 29 Apr 14 olle 553     int i = c/4;
2395 29 Apr 14 olle 554     int k = c % 4;
2395 29 Apr 14 olle 555     int L = (32 + 2*e + 2*i -h -k) % 7;
2395 29 Apr 14 olle 556     int m = ((a + 11*h + 22*L)/451);
2395 29 Apr 14 olle 557     int month = ((h + L - 7*m + 114)/31);
2395 29 Apr 14 olle 558     int day = ((h + L - 7*m + 114) % 31) + 1;
2395 29 Apr 14 olle 559     Calendar cal = GregorianCalendar.getInstance();
2395 29 Apr 14 olle 560     cal.set(Calendar.YEAR, year);
2395 29 Apr 14 olle 561     cal.set(Calendar.MONTH, month - 1);
2395 29 Apr 14 olle 562     cal.set(Calendar.DAY_OF_MONTH, day);
2395 29 Apr 14 olle 563     return cal.getTime();
2395 29 Apr 14 olle 564   }
2395 29 Apr 14 olle 565
2395 29 Apr 14 olle 566
2395 29 Apr 14 olle 567   /**
2395 29 Apr 14 olle 568    * Apply daytime filter to raw lab environment data list.
2395 29 Apr 14 olle 569    * 
2395 29 Apr 14 olle 570    * @param filterFromTime String Daytime filter from time in "HHmm" format, or empty string.
2395 29 Apr 14 olle 571    * @param filterToTime String Daytime filter from time in "HHmm" format, or empty string.
2395 29 Apr 14 olle 572    * @param lthdRawList List<LabEnvironmentData> Raw lab environment data list.
2395 29 Apr 14 olle 573    * @return List<LabEnvironmentData> Lab environment data list after applying daytime filter. 
2395 29 Apr 14 olle 574    */
2395 29 Apr 14 olle 575   private List<LabEnvironmentData> applyDaytimeFilter(String filterFromTime, String filterToTime, List<LabEnvironmentData> lthdRawList)
2395 29 Apr 14 olle 576   {
2395 29 Apr 14 olle 577     // Apply optional daytime filter
2395 29 Apr 14 olle 578     List<LabEnvironmentData> lthdList = new ArrayList<LabEnvironmentData>(); 
2395 29 Apr 14 olle 579     if ((filterFromTime == null || filterFromTime.equals("")) && (filterToTime == null || filterToTime.equals("")))
2395 29 Apr 14 olle 580     {
2395 29 Apr 14 olle 581       lthdList = lthdRawList;
2395 29 Apr 14 olle 582     }
2395 29 Apr 14 olle 583     else
2395 29 Apr 14 olle 584     {
2395 29 Apr 14 olle 585       // Note: The procedure below may seem to give bad performance,
2395 29 Apr 14 olle 586       // since dates are converted to strings for comparison, but it
2395 29 Apr 14 olle 587       // should work also on dates when daylight saving time starts
2395 29 Apr 14 olle 588       // or ends.
2395 29 Apr 14 olle 589       if (filterFromTime == null || filterFromTime.equals(""))
2395 29 Apr 14 olle 590       {
2395 29 Apr 14 olle 591         filterFromTime = "0000";
2395 29 Apr 14 olle 592       }
2395 29 Apr 14 olle 593       if (filterToTime == null || filterToTime.equals(""))
2395 29 Apr 14 olle 594       {
2395 29 Apr 14 olle 595         filterToTime = "2359";
2395 29 Apr 14 olle 596       }
2395 29 Apr 14 olle 597       DateFormat hourMinuteDateFormat = new SimpleDateFormat("HHmm");
2395 29 Apr 14 olle 598       for (LabEnvironmentData lthd: lthdRawList)
2395 29 Apr 14 olle 599       {
2395 29 Apr 14 olle 600         if (lthd != null)
2395 29 Apr 14 olle 601         {
2395 29 Apr 14 olle 602           long unixTimeInSeconds = lthd.getUnixTime();
2395 29 Apr 14 olle 603           Calendar cal = GregorianCalendar.getInstance();
2395 29 Apr 14 olle 604           cal.setTimeInMillis(unixTimeInSeconds*1000L);
2395 29 Apr 14 olle 605           Date date = cal.getTime();
2395 29 Apr 14 olle 606           String hourMinutesStr = hourMinuteDateFormat.format(date);
2395 29 Apr 14 olle 607           if (filterFromTime.compareTo(filterToTime) <= 0)
2395 29 Apr 14 olle 608           {
2395 29 Apr 14 olle 609             // filterFromTime <= hourMinutesStr <= filterToTime e.g. 08:00 - 16:00
2395 29 Apr 14 olle 610             if (filterFromTime.compareTo(hourMinutesStr) <= 0 && filterToTime.compareTo(hourMinutesStr) >= 0)
2395 29 Apr 14 olle 611             {
2395 29 Apr 14 olle 612               lthdList.add(lthd);
2395 29 Apr 14 olle 613             }
2395 29 Apr 14 olle 614           }
2395 29 Apr 14 olle 615           else
2395 29 Apr 14 olle 616           {
2395 29 Apr 14 olle 617             // hourMinutesStr <= filterToTime || filterFromTime <= hourMinutesStr e.g. 16:00 - 08:00
2395 29 Apr 14 olle 618             if (filterFromTime.compareTo(hourMinutesStr) <= 0 || filterToTime.compareTo(hourMinutesStr) >= 0)
2395 29 Apr 14 olle 619             {
2395 29 Apr 14 olle 620               lthdList.add(lthd);
2395 29 Apr 14 olle 621             }
2395 29 Apr 14 olle 622           }
2395 29 Apr 14 olle 623         }
2395 29 Apr 14 olle 624       }
2395 29 Apr 14 olle 625     }
2395 29 Apr 14 olle 626     return lthdList;
2395 29 Apr 14 olle 627   }
2395 29 Apr 14 olle 628
2303 02 Apr 14 olle 629   
2395 29 Apr 14 olle 630   private JSONArray createLabEnvironmentDailyDistributionReport(JSONArray jsonStatisticsPlotArray, List<LabEnvironmentData> lthdList, Date startDate, Date endDate, String chartVariant, String viewType, String sensorName, String weekdayFilter, String daytimeFilterFromTime, String daytimeFilterToTime)
2303 02 Apr 14 olle 631     throws ServletException, IOException 
2303 02 Apr 14 olle 632   {  
2303 02 Apr 14 olle 633     JSONObject jsonReport = new JSONObject();
2303 02 Apr 14 olle 634
2303 02 Apr 14 olle 635     Date date = null;
2303 02 Apr 14 olle 636     // Converter to check timestamps against midnight: 00:00:00
2303 02 Apr 14 olle 637     DateToStringConverter timeConverter = new DateToStringConverter(new SimpleDateFormat("HH:mm:ss"));
2303 02 Apr 14 olle 638     // Create list of view types for plots
2303 02 Apr 14 olle 639     List<String> viewTypeList = new ArrayList<String>();
2303 02 Apr 14 olle 640     // Get lab environment configuration from singleton LabEnvironment
2326 07 Apr 14 olle 641     LabEnvironment labEnvironment = LabEnvironment.getInstance();
2303 02 Apr 14 olle 642     LabEnvironmentConfiguration labEnvironmentConfiguration = labEnvironment.getLabEnvironmentConfiguration();
2303 02 Apr 14 olle 643     List<LabSensorConfig> labSensorConfigList = labEnvironmentConfiguration.getLabSensorConfigList();
2303 02 Apr 14 olle 644     // Prepare additional data
2303 02 Apr 14 olle 645     String chartSite = sensorName;
2303 02 Apr 14 olle 646     List<String> variableTypeList = new ArrayList<String>();
2303 02 Apr 14 olle 647     variableTypeList.add(variableTypeTemperature);
2303 02 Apr 14 olle 648     variableTypeList.add(variableTypeHumidity);
2303 02 Apr 14 olle 649     // Create plot statistics data and put in JSON statistics plot array
2303 02 Apr 14 olle 650     for (String variableType: variableTypeList)
2303 02 Apr 14 olle 651     {
2303 02 Apr 14 olle 652       // Get JSON statistics data
2303 02 Apr 14 olle 653       String cVariant = "labEnvironmentDailyDistribution";
2395 29 Apr 14 olle 654       JSONObject plotJsonData = createJsonPlot(cVariant, lthdList, startDate, endDate, viewType, chartSite, variableType, weekdayFilter, daytimeFilterFromTime, daytimeFilterToTime);
2303 02 Apr 14 olle 655       //
2303 02 Apr 14 olle 656       plotJsonData = addExtraInfo(plotJsonData, cVariant);
2303 02 Apr 14 olle 657       JSONObject plotJsonDataContainer = new JSONObject();
2303 02 Apr 14 olle 658       plotJsonDataContainer.put("chartSite", chartSite);
2303 02 Apr 14 olle 659       plotJsonDataContainer.put("chartVariant", cVariant);
2303 02 Apr 14 olle 660       plotJsonDataContainer.put("viewType", viewType);
2303 02 Apr 14 olle 661       plotJsonDataContainer.put("plotData", plotJsonData);
2303 02 Apr 14 olle 662       String optionalHeadline = "";
2303 02 Apr 14 olle 663       plotJsonDataContainer.put("optionalHeadline", optionalHeadline);
2303 02 Apr 14 olle 664       jsonStatisticsPlotArray.add(plotJsonDataContainer);
2303 02 Apr 14 olle 665     }
2303 02 Apr 14 olle 666     return jsonStatisticsPlotArray;
2303 02 Apr 14 olle 667   }
2303 02 Apr 14 olle 668
2303 02 Apr 14 olle 669
2303 02 Apr 14 olle 670   /**
2303 02 Apr 14 olle 671    * Returns a Date object from input dateTime string in format (yyyyMMdd HHmm).
2303 02 Apr 14 olle 672    * Returns `null` if input dateTime string is
2303 02 Apr 14 olle 673    * `null` or blank.
2303 02 Apr 14 olle 674    * 
2303 02 Apr 14 olle 675    * @param dateTimeStr String Input dateTime string in (yyyyMMdd HHmm) format.
2303 02 Apr 14 olle 676    * @return Date Date object from input dateTime string.
2303 02 Apr 14 olle 677    */
2303 02 Apr 14 olle 678   private Date dateTimeStringToDate(String dateTimeStr)
2303 02 Apr 14 olle 679   {
2303 02 Apr 14 olle 680     Date date = null;
2303 02 Apr 14 olle 681     if (dateTimeStr != null && !dateTimeStr.equals(""))
2303 02 Apr 14 olle 682     {
2303 02 Apr 14 olle 683       date = CONVERTER_STRING_TO_DATETIME.convert(dateTimeStr);
2303 02 Apr 14 olle 684     }
2303 02 Apr 14 olle 685     return date;
2303 02 Apr 14 olle 686   }
2303 02 Apr 14 olle 687
2303 02 Apr 14 olle 688
2303 02 Apr 14 olle 689   /**
2303 02 Apr 14 olle 690    * Returns a Date object from input date string in format (yyyy-MM-dd).
2303 02 Apr 14 olle 691    * Returns `null` if input string is `null` or blank.
2303 02 Apr 14 olle 692    * 
2303 02 Apr 14 olle 693    * @param dateStr String Input date string in (yyyy-MM-dd) format.
2303 02 Apr 14 olle 694    * @return Date Date object from input date string.
2303 02 Apr 14 olle 695    */
2303 02 Apr 14 olle 696   private Date dateStringToDate(String dateStr)
2303 02 Apr 14 olle 697   {
2303 02 Apr 14 olle 698     Date date = null;
2303 02 Apr 14 olle 699     if (dateStr != null && !dateStr.equals(""))
2303 02 Apr 14 olle 700     {
2303 02 Apr 14 olle 701       date = CONVERTER_STRING_TO_DATE.convert(dateStr);
2303 02 Apr 14 olle 702     }
2303 02 Apr 14 olle 703     return date;
2303 02 Apr 14 olle 704   }
2303 02 Apr 14 olle 705
2303 02 Apr 14 olle 706
2303 02 Apr 14 olle 707   /**
2303 02 Apr 14 olle 708    * Returns a dateTime string in format (yyyyMMdd HHmm) from input
2303 02 Apr 14 olle 709    * date and time strings. Returns `null` if input date string is
2303 02 Apr 14 olle 710    * `null` or blank. Provided input date string is OK; if input time
2303 02 Apr 14 olle 711    * string is `null` or blank, time is set to "0000".
2303 02 Apr 14 olle 712    * 
2303 02 Apr 14 olle 713    * @param dateStr String Input date string in (yyyyMMdd) format.
2303 02 Apr 14 olle 714    * @param timeStr String Input time string in (HHmm) format.
2303 02 Apr 14 olle 715    * @return String DateTime string in format (yyyyMMdd HHmm) from input date and time strings.
2303 02 Apr 14 olle 716    */
2303 02 Apr 14 olle 717   private String dateAndTimeStringsToDateTimeString(String dateStr, String timeStr)
2303 02 Apr 14 olle 718   {
2303 02 Apr 14 olle 719     String dateTimeStr = null;
2303 02 Apr 14 olle 720     if (dateStr != null && !dateStr.equals(""))
2303 02 Apr 14 olle 721     {
2303 02 Apr 14 olle 722       dateStr.replaceAll("-", "");
2303 02 Apr 14 olle 723       dateTimeStr = "" + dateStr;
2303 02 Apr 14 olle 724       if (timeStr != null && !timeStr.equals(""))
2303 02 Apr 14 olle 725       {
2303 02 Apr 14 olle 726         timeStr.replaceAll(":", "");
2303 02 Apr 14 olle 727       }
2303 02 Apr 14 olle 728       else
2303 02 Apr 14 olle 729       {
2303 02 Apr 14 olle 730         timeStr = "0000";
2303 02 Apr 14 olle 731       }
2303 02 Apr 14 olle 732       dateTimeStr += " " + timeStr;    
2303 02 Apr 14 olle 733     }
2303 02 Apr 14 olle 734     return dateTimeStr;
2303 02 Apr 14 olle 735   }
2303 02 Apr 14 olle 736
2303 02 Apr 14 olle 737
2395 29 Apr 14 olle 738   /**
2395 29 Apr 14 olle 739    * Returns the date obtained by adding a specified number
2395 29 Apr 14 olle 740    * of days to an input date in the Gregorian calendar
2395 29 Apr 14 olle 741    * (a negative number of days to add equals subtraction of
2395 29 Apr 14 olle 742    * the number of days). Returns `null` if input date is `null`.
2395 29 Apr 14 olle 743    * 
2395 29 Apr 14 olle 744    * @param date Date The date to add a number of days to.
2395 29 Apr 14 olle 745    * @param daysToAdd int The number of days to add.
2395 29 Apr 14 olle 746    * @return The date after adding a number of days, or `null` if input date is `null`.
2395 29 Apr 14 olle 747    */
2395 29 Apr 14 olle 748   private Date addDays(Date date, int daysToAdd)
2395 29 Apr 14 olle 749   {
2395 29 Apr 14 olle 750     if (date == null)
2395 29 Apr 14 olle 751     {
2395 29 Apr 14 olle 752       return null;
2395 29 Apr 14 olle 753     }
2395 29 Apr 14 olle 754     Calendar cal = GregorianCalendar.getInstance();
2395 29 Apr 14 olle 755     cal.setTimeInMillis(date.getTime());
2395 29 Apr 14 olle 756     cal.add(Calendar.DAY_OF_MONTH, daysToAdd);
2395 29 Apr 14 olle 757     return cal.getTime();
2395 29 Apr 14 olle 758   }
2395 29 Apr 14 olle 759
2395 29 Apr 14 olle 760   private JSONObject createJsonPlot(String chartVariant, List<LabEnvironmentData> lthdList, Date startDate, Date endDate, String viewType, String chartSite, String variableType, String weekdayFilter, String daytimeFilterFromTime, String daytimeFilterToTime)
2303 02 Apr 14 olle 761     throws ServletException, IOException 
2303 02 Apr 14 olle 762   {
2303 02 Apr 14 olle 763     if (lthdList != null)
2303 02 Apr 14 olle 764     {
2303 02 Apr 14 olle 765       log.debug("lthdList.size() = " + lthdList.size());
2303 02 Apr 14 olle 766     }
2303 02 Apr 14 olle 767     else
2303 02 Apr 14 olle 768     {
2303 02 Apr 14 olle 769       log.debug("lthdList == null");
2303 02 Apr 14 olle 770     }
2303 02 Apr 14 olle 771     // Get JSON statistics data
2395 29 Apr 14 olle 772     String chartHeaderTitle = fetchChartHeaderTitle(chartVariant, viewType, chartSite, variableType, weekdayFilter);
2395 29 Apr 14 olle 773     String chartTitle = fetchChartTitle(viewType, variableType, startDate, endDate, daytimeFilterFromTime, daytimeFilterToTime);
2303 02 Apr 14 olle 774     String chartYAxisTitle = fetchChartYAxisTitle(variableType);
2303 02 Apr 14 olle 775     // Get HashMap with lists of samples for chosen time periods 
4526 19 Jun 17 nicklas 776     HashMap<String,List<Float>> periodStringFloatListHashMap = createPeriodStringFloatListHashMap(chartVariant, lthdList, viewType, variableType, startDate);
2395 29 Apr 14 olle 777     //log.debug("periodStringFloatListHashMap = " + periodStringFloatListHashMap);
2395 29 Apr 14 olle 778     JSONObject jsonPlot = null;
2395 29 Apr 14 olle 779     if (viewType != null && viewType.equals("dailyDistribution") || viewType.equals("weeklyDistribution"))
2395 29 Apr 14 olle 780     {
2395 29 Apr 14 olle 781       jsonPlot = createJSONPlotStatistics(chartVariant, chartHeaderTitle, chartTitle, chartYAxisTitle, periodStringFloatListHashMap, viewType);
2395 29 Apr 14 olle 782     }
2395 29 Apr 14 olle 783     return jsonPlot;
2303 02 Apr 14 olle 784   }
2303 02 Apr 14 olle 785
2303 02 Apr 14 olle 786
2303 02 Apr 14 olle 787   private JSONObject createJSONPlotStatistics(String chartVariant, String headerTitle, String title, String variableTitle, HashMap<String,List<Float>> periodStringFloatListHashMap, String viewType)
2303 02 Apr 14 olle 788     throws ServletException, IOException 
2303 02 Apr 14 olle 789   {
2303 02 Apr 14 olle 790     // Calculate statistics for all samples
2303 02 Apr 14 olle 791     List<Float> floatList = singleFloatList(periodStringFloatListHashMap);
2303 02 Apr 14 olle 792     int numItems = floatList.size();
2303 02 Apr 14 olle 793     Float floatMin = calculateMinValue(floatList);
2303 02 Apr 14 olle 794     Float floatMax = calculateMaxValue(floatList);
2303 02 Apr 14 olle 795     Float floatMean = calculateMeanValue(floatList);
2303 02 Apr 14 olle 796     Float floatSDev = calculateSDev(floatList);
2303 02 Apr 14 olle 797     Collections.sort(floatList);
2303 02 Apr 14 olle 798     Float floatPct25 = calculatePercentile(floatList, 0.25f);
2303 02 Apr 14 olle 799     Float floatPct50 = calculatePercentile(floatList, 0.50f);
2303 02 Apr 14 olle 800     Float floatPct75 = calculatePercentile(floatList, 0.75f);
2303 02 Apr 14 olle 801     int localNumberOfDecimals = numberOfDecimals;
2303 02 Apr 14 olle 802     if (floatPct25 != null && floatPct25 < 1)
2303 02 Apr 14 olle 803     {
2303 02 Apr 14 olle 804       localNumberOfDecimals = numberOfDecimals + 1;
2303 02 Apr 14 olle 805     }
2303 02 Apr 14 olle 806     // Create JSON object with sample statistics
2303 02 Apr 14 olle 807     JSONObject jsonStat = new JSONObject();
2303 02 Apr 14 olle 808     jsonStat.put("headerTitleTop", headerTitle);
2303 02 Apr 14 olle 809     jsonStat.put("titleTop", title);
2303 02 Apr 14 olle 810     jsonStat.put("titleBottom", "");
2303 02 Apr 14 olle 811     jsonStat.put("subTitleRight", "n = " + numItems);
2303 02 Apr 14 olle 812     jsonStat.put("subTitleLeft01", "mean, " + Values.formatNumber(floatMean, localNumberOfDecimals));
2303 02 Apr 14 olle 813     jsonStat.put("subTitleLeft02", "sd, " + Values.formatNumber(floatSDev, localNumberOfDecimals));
2303 02 Apr 14 olle 814     jsonStat.put("subTitleLeft03", "range, " + Values.formatNumber(floatMin, localNumberOfDecimals) + ", " + Values.formatNumber(floatMax, localNumberOfDecimals));
2303 02 Apr 14 olle 815     jsonStat.put("yAxisTitleLeft", variableTitle);
2303 02 Apr 14 olle 816     jsonStat.put("yAxisTitleRight", "");
2303 02 Apr 14 olle 817     // Create JSON array of sample statistics for time periods
2303 02 Apr 14 olle 818     JSONArray jsonPeriodPercentilesArray = new JSONArray();
2303 02 Apr 14 olle 819     List<String> periodList = new ArrayList<String>();
2303 02 Apr 14 olle 820     for (String period: periodStringFloatListHashMap.keySet())
2303 02 Apr 14 olle 821     {
2303 02 Apr 14 olle 822       periodList.add(period);
2303 02 Apr 14 olle 823     }
2303 02 Apr 14 olle 824     Collections.sort(periodList);
2303 02 Apr 14 olle 825     for (String period: periodList)
2303 02 Apr 14 olle 826     {
2303 02 Apr 14 olle 827       if (periodStringFloatListHashMap.get(period).size() >= minItemsForStatisticsCalculation)
2303 02 Apr 14 olle 828       {
2303 02 Apr 14 olle 829         List<Float> periodFloatList = periodStringFloatListHashMap.get(period);
2303 02 Apr 14 olle 830         // Get name of time period in standard format for plot
2303 02 Apr 14 olle 831         String periodName = fetchPeriodNameForPlot(period, viewType);
2303 02 Apr 14 olle 832         JSONObject jsonPeriodData = createSamplePeriodJSONStatistics(periodFloatList, periodName);
2303 02 Apr 14 olle 833         jsonPeriodPercentilesArray.add(jsonPeriodData);
2303 02 Apr 14 olle 834       }
2303 02 Apr 14 olle 835     }
2303 02 Apr 14 olle 836     jsonStat.put("percentileData", jsonPeriodPercentilesArray);
2303 02 Apr 14 olle 837     // Create JSON array of percentile data for all samples
2303 02 Apr 14 olle 838     JSONArray jsonPercentilesArray = new JSONArray();
2303 02 Apr 14 olle 839     JSONObject jsonPct25 = createValueWithText(floatPct25, localNumberOfDecimals);
2303 02 Apr 14 olle 840     jsonPercentilesArray.add(jsonPct25);
2303 02 Apr 14 olle 841     JSONObject jsonPct50 = createValueWithText(floatPct50, localNumberOfDecimals);
2303 02 Apr 14 olle 842     jsonPercentilesArray.add(jsonPct50);
2303 02 Apr 14 olle 843     JSONObject jsonPct75 = createValueWithText(floatPct75, localNumberOfDecimals);
2303 02 Apr 14 olle 844     jsonPercentilesArray.add(jsonPct75);
2303 02 Apr 14 olle 845     jsonStat.put("valueGuideLinesY", jsonPercentilesArray);
2303 02 Apr 14 olle 846     return jsonStat;        
2303 02 Apr 14 olle 847   }
2303 02 Apr 14 olle 848
2395 29 Apr 14 olle 849
2395 29 Apr 14 olle 850
2303 02 Apr 14 olle 851   private JSONObject createValueWithText(Float value, int numberOfDecimalsShown)
2303 02 Apr 14 olle 852   {
2303 02 Apr 14 olle 853     if (value == null)
2303 02 Apr 14 olle 854     {
2303 02 Apr 14 olle 855       return null;
2303 02 Apr 14 olle 856     }
2303 02 Apr 14 olle 857     JSONObject jsonValueWithText = createValueWithText(value, Values.formatNumber(value, numberOfDecimalsShown));
2303 02 Apr 14 olle 858     return jsonValueWithText;
2303 02 Apr 14 olle 859   }
2303 02 Apr 14 olle 860
2303 02 Apr 14 olle 861   private JSONObject createValueWithText(Float value, String text)
2303 02 Apr 14 olle 862   {
2303 02 Apr 14 olle 863     if (value == null)
2303 02 Apr 14 olle 864     {
2303 02 Apr 14 olle 865       return null;
2303 02 Apr 14 olle 866     }
2303 02 Apr 14 olle 867     JSONObject jsonValueWithText = new JSONObject();
2303 02 Apr 14 olle 868     jsonValueWithText.put("value", value);
2303 02 Apr 14 olle 869     jsonValueWithText.put("text", text);    
2303 02 Apr 14 olle 870     return jsonValueWithText;
2303 02 Apr 14 olle 871   }
2303 02 Apr 14 olle 872
2303 02 Apr 14 olle 873   private JSONObject createSamplePeriodJSONStatistics(List<Float> floatList, String periodName)
2303 02 Apr 14 olle 874       throws ServletException, IOException 
2303 02 Apr 14 olle 875     {  
2303 02 Apr 14 olle 876       // Calculate statistics for samples
2303 02 Apr 14 olle 877       int numItems = floatList.size();
2303 02 Apr 14 olle 878       Collections.sort(floatList);
2303 02 Apr 14 olle 879       //Float floatPct05 = calculatePercentile(floatList, 0.05f);
2303 02 Apr 14 olle 880       Float floatPct25 = calculatePercentile(floatList, 0.25f);
2303 02 Apr 14 olle 881       Float floatPct50 = calculatePercentile(floatList, 0.50f);
2303 02 Apr 14 olle 882       Float floatPct75 = calculatePercentile(floatList, 0.75f);
2303 02 Apr 14 olle 883       //Float floatPct95 = calculatePercentile(floatList, 0.95f);
2303 02 Apr 14 olle 884       // Inter-percentile range ipr = pct75 - pct25
2303 02 Apr 14 olle 885       // Calculate whisker values as lowest and highest data values within coef*ipr from box ends
2303 02 Apr 14 olle 886       float coef = 1.5f;
2303 02 Apr 14 olle 887       Float w1 = calculateBoxPlotWhiskerValue(floatList, floatPct25, floatPct75, coef, "lower");
2303 02 Apr 14 olle 888       Float w2 = calculateBoxPlotWhiskerValue(floatList, floatPct25, floatPct75, coef, "upper");
2303 02 Apr 14 olle 889       // Create JSON object with sample statistics for period
2303 02 Apr 14 olle 890       JSONObject jsonStat = new JSONObject();
2303 02 Apr 14 olle 891       jsonStat.put("name", periodName);
2303 02 Apr 14 olle 892       jsonStat.put("numItems", numItems);
2303 02 Apr 14 olle 893       jsonStat.put("v1", w1);
2303 02 Apr 14 olle 894       jsonStat.put("v2", floatPct25);
2303 02 Apr 14 olle 895       jsonStat.put("v3", floatPct50);
2303 02 Apr 14 olle 896       jsonStat.put("v4", floatPct75);
2303 02 Apr 14 olle 897       jsonStat.put("v5", w2);
2303 02 Apr 14 olle 898       return jsonStat;        
2303 02 Apr 14 olle 899     }
2303 02 Apr 14 olle 900
2303 02 Apr 14 olle 901   /**
2303 02 Apr 14 olle 902    *  Returns a period string intended for use as label in box plot.
2303 02 Apr 14 olle 903    *  The period string will be modified as follows for different view types:<br>
2303 02 Apr 14 olle 904    *  Year view:    yyyy  ->  yyyy    (no change)<br>
2303 02 Apr 14 olle 905    *  Quarter view: yyyyq  -> yyyy-Qq (e.g. 20123  -> 2012-Q3)<br>
2303 02 Apr 14 olle 906    *  Month view:   yyyymm -> yyyy-mm (e.g. 201203 -> 2012-03)<br>
2303 02 Apr 14 olle 907    *  Week view:    yyyyww -> yyyy-ww (e.g. 201203 -> 2012-03)<br>
2303 02 Apr 14 olle 908    * 
2303 02 Apr 14 olle 909    *  @param period String The period string in pure number format.
2303 02 Apr 14 olle 910    *  @param viewType String The view type.
2303 02 Apr 14 olle 911    *  @return String A period string intended for use as label in box plot.
2303 02 Apr 14 olle 912    */
2303 02 Apr 14 olle 913   private String fetchPeriodNameForPlot(String period, String viewType)
2303 02 Apr 14 olle 914   {
2303 02 Apr 14 olle 915     if (viewType != null && viewType.equals("weeklyDistribution"))
2303 02 Apr 14 olle 916     {
2303 02 Apr 14 olle 917       // Strip of two first characters, e.g. "1_Mon" -> "Mon"
2303 02 Apr 14 olle 918       if (period != null && period.length() > 2)
2303 02 Apr 14 olle 919       {
2303 02 Apr 14 olle 920         period = period.substring(2);
2303 02 Apr 14 olle 921       }
2303 02 Apr 14 olle 922       return period;
2303 02 Apr 14 olle 923     }
2303 02 Apr 14 olle 924     if (period == null || period.length() < 4)
2303 02 Apr 14 olle 925     {
2303 02 Apr 14 olle 926       return period;
2303 02 Apr 14 olle 927     }
2303 02 Apr 14 olle 928     String yearStr = period.substring(0,4);
2303 02 Apr 14 olle 929     String residueStr = period.substring(4);
2303 02 Apr 14 olle 930     // Add year string
2303 02 Apr 14 olle 931     String periodName = yearStr;
2303 02 Apr 14 olle 932     if (residueStr.length() > 0)
2303 02 Apr 14 olle 933     {
2303 02 Apr 14 olle 934       // Add hyphen after year string
2303 02 Apr 14 olle 935       periodName += "-";
2303 02 Apr 14 olle 936       if (viewType.equals(ReportTableUtil.quarterView))
2303 02 Apr 14 olle 937       {
2303 02 Apr 14 olle 938         // Add 'Q' after year string
2303 02 Apr 14 olle 939         periodName += "Q";
2303 02 Apr 14 olle 940       }
2303 02 Apr 14 olle 941       // Add residue string (quarter, month, or week string)
2303 02 Apr 14 olle 942       periodName += residueStr;
2303 02 Apr 14 olle 943     }
2303 02 Apr 14 olle 944     return periodName;
2303 02 Apr 14 olle 945   }
2303 02 Apr 14 olle 946
2395 29 Apr 14 olle 947
4526 19 Jun 17 nicklas 948   private HashMap<String, List<Float>> createPeriodStringFloatListHashMap(String chartVariant, List<LabEnvironmentData> lthdList, String viewType, String variableType, Date startDate)
2303 02 Apr 14 olle 949     throws ServletException, IOException 
2303 02 Apr 14 olle 950   {
2303 02 Apr 14 olle 951     // Default variable is temperature
2303 02 Apr 14 olle 952     if (variableType == null || variableType.equals(""))
2303 02 Apr 14 olle 953     {
2303 02 Apr 14 olle 954       variableType = variableTypeTemperature;
2303 02 Apr 14 olle 955     }
2303 02 Apr 14 olle 956     // Create HashMap to keep track of values for each time period
2303 02 Apr 14 olle 957     HashMap<String, List<Float>> periodStringFloatListHashMap = new HashMap<String, List<Float>>();
2303 02 Apr 14 olle 958     
2303 02 Apr 14 olle 959     for (LabEnvironmentData lthd: lthdList)
2303 02 Apr 14 olle 960     {
2303 02 Apr 14 olle 961       Date dateTime = lthd.getDateTime();
2303 02 Apr 14 olle 962       // Get current period
4526 19 Jun 17 nicklas 963       String currentPeriod = tableUtil.getCurrentPeriod(dateTime, viewType, startDate);
2395 29 Apr 14 olle 964       //log.debug("dateTime = " + dateTime + " currentPeriod = " + currentPeriod + " viewType = " + viewType);
2303 02 Apr 14 olle 965       // Update period value hash map
2303 02 Apr 14 olle 966       Float value = null;
2303 02 Apr 14 olle 967       // Get value of desired variable
2303 02 Apr 14 olle 968       if (variableType.equals(variableTypeTemperature))
2303 02 Apr 14 olle 969       {
2303 02 Apr 14 olle 970         value = Double.valueOf(lthd.getTemperature()).floatValue();
2303 02 Apr 14 olle 971       }
2303 02 Apr 14 olle 972       else if (variableType.equals(variableTypeHumidity))
2303 02 Apr 14 olle 973       {
2303 02 Apr 14 olle 974         value = Double.valueOf(lthd.getHumidity()).floatValue();
2303 02 Apr 14 olle 975       }
2303 02 Apr 14 olle 976       updateStringFloatListHashMap(periodStringFloatListHashMap, currentPeriod, value);
2395 29 Apr 14 olle 977 /*
2303 02 Apr 14 olle 978       //
2303 02 Apr 14 olle 979       long unixTimeInSeconds = lthd.getUnixTime();
2303 02 Apr 14 olle 980       Calendar cal = GregorianCalendar.getInstance();
2303 02 Apr 14 olle 981       cal.setTimeInMillis(unixTimeInSeconds*1000L);
2395 29 Apr 14 olle 982 */
2303 02 Apr 14 olle 983     }
2303 02 Apr 14 olle 984     return periodStringFloatListHashMap;        
2303 02 Apr 14 olle 985   }
2303 02 Apr 14 olle 986
2303 02 Apr 14 olle 987   private JSONObject addExtraInfo(JSONObject plotJsonData, String chartVariant)
2303 02 Apr 14 olle 988   {
2303 02 Apr 14 olle 989     if (plotJsonData != null && chartVariant != null)
2303 02 Apr 14 olle 990     {
2303 02 Apr 14 olle 991 /*
2303 02 Apr 14 olle 992       if (chartVariant.equals(remainingQuantityForScanBSpecimenChart))
2303 02 Apr 14 olle 993       {
2303 02 Apr 14 olle 994         String subTitleRight = (String) plotJsonData.get("subTitleRight");
2303 02 Apr 14 olle 995         subTitleRight += "; > 1 mg, n = " + getNumRemainingTissueItemsGT1Mg();
2303 02 Apr 14 olle 996         plotJsonData.put("subTitleRight", subTitleRight);
2303 02 Apr 14 olle 997       }
2303 02 Apr 14 olle 998 */    
2303 02 Apr 14 olle 999     }
2303 02 Apr 14 olle 1000     return plotJsonData;
2303 02 Apr 14 olle 1001   }
2303 02 Apr 14 olle 1002
2303 02 Apr 14 olle 1003   private HashMap<String, List<Float>> updateStringFloatListHashMap(HashMap<String, List<Float>> stringFloatListHashMap, String string, Float value)
2303 02 Apr 14 olle 1004   {
2303 02 Apr 14 olle 1005     if (stringFloatListHashMap == null)
2303 02 Apr 14 olle 1006     {
2303 02 Apr 14 olle 1007       stringFloatListHashMap = new HashMap<String, List<Float>>();
2303 02 Apr 14 olle 1008     }
2303 02 Apr 14 olle 1009     if (string != null && !string.equals("") && value != null)
2303 02 Apr 14 olle 1010     {
2303 02 Apr 14 olle 1011       List<Float> floatList = stringFloatListHashMap.get(string);
2303 02 Apr 14 olle 1012       if (floatList == null)
2303 02 Apr 14 olle 1013       {
2303 02 Apr 14 olle 1014         floatList = new ArrayList<Float>();
2303 02 Apr 14 olle 1015       }
2303 02 Apr 14 olle 1016       floatList.add(value);
2303 02 Apr 14 olle 1017       stringFloatListHashMap.put(string,  floatList);
2303 02 Apr 14 olle 1018     }
2303 02 Apr 14 olle 1019     return stringFloatListHashMap;
2303 02 Apr 14 olle 1020   }
2303 02 Apr 14 olle 1021
2303 02 Apr 14 olle 1022   /**
2303 02 Apr 14 olle 1023    *  Returns a single List<Float> with all values in all the
2303 02 Apr 14 olle 1024    *  lists in the HashMap<String, List<Float>>.
2303 02 Apr 14 olle 1025    *
2303 02 Apr 14 olle 1026    *  @param stringFloatListHashMap HashMap<String, List<Float>> The HashMap to use.
2303 02 Apr 14 olle 1027    *  @return List<Float> The list of float values in all the lists in the HashMap<String, List<Float>>.
2303 02 Apr 14 olle 1028    */
2303 02 Apr 14 olle 1029   private List<Float> singleFloatList(HashMap<String, List<Float>> stringFloatListHashMap)
2303 02 Apr 14 olle 1030   {
2303 02 Apr 14 olle 1031     List<Float> singleFloatList = new ArrayList<Float>();
2303 02 Apr 14 olle 1032     for (List<Float> floatList: stringFloatListHashMap.values())
2303 02 Apr 14 olle 1033     {
2303 02 Apr 14 olle 1034       for (Float value: floatList)
2303 02 Apr 14 olle 1035       {
2303 02 Apr 14 olle 1036         singleFloatList.add(value);
2303 02 Apr 14 olle 1037       }
2303 02 Apr 14 olle 1038     }
2303 02 Apr 14 olle 1039     return singleFloatList;
2303 02 Apr 14 olle 1040   }
2303 02 Apr 14 olle 1041
2303 02 Apr 14 olle 1042   private Float calculateMinValue(List<Float> floatList)
2303 02 Apr 14 olle 1043   {
2303 02 Apr 14 olle 1044     Float floatMin = Float.valueOf("1000000000.0");
2303 02 Apr 14 olle 1045     for (Float value: floatList)
2303 02 Apr 14 olle 1046     {
2303 02 Apr 14 olle 1047       if (value != null && value < floatMin)
2303 02 Apr 14 olle 1048       {
2303 02 Apr 14 olle 1049         floatMin = value;
2303 02 Apr 14 olle 1050       }
2303 02 Apr 14 olle 1051     }
2303 02 Apr 14 olle 1052     return floatMin;
2303 02 Apr 14 olle 1053   }
2303 02 Apr 14 olle 1054
2303 02 Apr 14 olle 1055   private Float calculateMaxValue(List<Float> floatList)
2303 02 Apr 14 olle 1056   {
2303 02 Apr 14 olle 1057     Float floatMax = Float.valueOf("-1000000000.0");
2303 02 Apr 14 olle 1058     for (Float value: floatList)
2303 02 Apr 14 olle 1059     {
2303 02 Apr 14 olle 1060       if (value != null && value > floatMax)
2303 02 Apr 14 olle 1061       {
2303 02 Apr 14 olle 1062         floatMax = value;
2303 02 Apr 14 olle 1063       }
2303 02 Apr 14 olle 1064     }
2303 02 Apr 14 olle 1065     return floatMax;
2303 02 Apr 14 olle 1066   }
2303 02 Apr 14 olle 1067
2303 02 Apr 14 olle 1068   private Float calculateMeanValue(List<Float> floatList)
2303 02 Apr 14 olle 1069   {
2303 02 Apr 14 olle 1070     Float mean = Float.valueOf("0.0");
2303 02 Apr 14 olle 1071     int n = 0;
2303 02 Apr 14 olle 1072     for (Float value: floatList)
2303 02 Apr 14 olle 1073     {
2303 02 Apr 14 olle 1074       if (value != null)
2303 02 Apr 14 olle 1075       {
2303 02 Apr 14 olle 1076         mean += value;
2303 02 Apr 14 olle 1077         n++;
2303 02 Apr 14 olle 1078       }
2303 02 Apr 14 olle 1079     }
2303 02 Apr 14 olle 1080     if (n > 0)
2303 02 Apr 14 olle 1081     {
2303 02 Apr 14 olle 1082       mean /= n;
2303 02 Apr 14 olle 1083     }
2303 02 Apr 14 olle 1084     return mean;
2303 02 Apr 14 olle 1085   }
2303 02 Apr 14 olle 1086
2303 02 Apr 14 olle 1087   private Float calculateSDev(List<Float> floatList)
2303 02 Apr 14 olle 1088   {
2303 02 Apr 14 olle 1089     Float var = Float.valueOf("0.0");
2303 02 Apr 14 olle 1090     Float mean = calculateMeanValue(floatList);
2303 02 Apr 14 olle 1091     int n = 0;
2303 02 Apr 14 olle 1092     Float dist = Float.valueOf("0.0");
2303 02 Apr 14 olle 1093     for (Float value: floatList)
2303 02 Apr 14 olle 1094     {
2303 02 Apr 14 olle 1095       if (value != null)
2303 02 Apr 14 olle 1096       {
2303 02 Apr 14 olle 1097         dist = (value - mean);
2303 02 Apr 14 olle 1098         var += dist*dist;
2303 02 Apr 14 olle 1099         n++;
2303 02 Apr 14 olle 1100       }
2303 02 Apr 14 olle 1101     }
2303 02 Apr 14 olle 1102     if (n > 1)
2303 02 Apr 14 olle 1103     {
2303 02 Apr 14 olle 1104       var /= (n - 1);
2303 02 Apr 14 olle 1105     }
2303 02 Apr 14 olle 1106     Float sDev = Double.valueOf(Math.sqrt(var)).floatValue();
2303 02 Apr 14 olle 1107     return sDev;
2303 02 Apr 14 olle 1108   }
2303 02 Apr 14 olle 1109
2303 02 Apr 14 olle 1110   private Float calculatePercentile(List<Float> sortedAscFloatList, float fraction)
2303 02 Apr 14 olle 1111   {
2303 02 Apr 14 olle 1112     Float percentileValue = null;
2303 02 Apr 14 olle 1113     if (sortedAscFloatList == null || sortedAscFloatList.size() < 1 || fraction <= 0.0 || fraction >= 1.0)
2303 02 Apr 14 olle 1114     {
2303 02 Apr 14 olle 1115       return null;
2303 02 Apr 14 olle 1116     }
2303 02 Apr 14 olle 1117     int len = sortedAscFloatList.size();
2303 02 Apr 14 olle 1118     // List index values goes from 0 to (len - 1)
2303 02 Apr 14 olle 1119     float indexVal = fraction*(len - 1);
2303 02 Apr 14 olle 1120     float floorVal = Double.valueOf(Math.floor(indexVal)).floatValue();
2303 02 Apr 14 olle 1121     float ceilVal = Double.valueOf(Math.ceil(indexVal)).floatValue();
2303 02 Apr 14 olle 1122     if (floorVal == ceilVal)
2303 02 Apr 14 olle 1123     {
2303 02 Apr 14 olle 1124       percentileValue = sortedAscFloatList.get((int) indexVal);
2303 02 Apr 14 olle 1125     }
2303 02 Apr 14 olle 1126     else
2303 02 Apr 14 olle 1127     {
2303 02 Apr 14 olle 1128       // Calculate percentile value as weighted value of two list values
2303 02 Apr 14 olle 1129       float d0 = sortedAscFloatList.get((int) floorVal) * (ceilVal - indexVal);
2303 02 Apr 14 olle 1130       float d1 = sortedAscFloatList.get((int) ceilVal)  * (indexVal - floorVal);
2303 02 Apr 14 olle 1131       percentileValue = d0 + d1;
2303 02 Apr 14 olle 1132     }
2303 02 Apr 14 olle 1133     return percentileValue;
2303 02 Apr 14 olle 1134   }
2303 02 Apr 14 olle 1135
2303 02 Apr 14 olle 1136   private Float calculateBoxPlotWhiskerValue(List<Float> sortedAscFloatList, Float pct25, Float pct75, float coef, String plotEnd)
2303 02 Apr 14 olle 1137   {
2303 02 Apr 14 olle 1138     Float whiskerValue = null;
2303 02 Apr 14 olle 1139     if (sortedAscFloatList == null || sortedAscFloatList.size() < 1 || pct25 == null || pct75 == null || coef <= 0.0 || plotEnd == null || !(plotEnd.equals("lower") || plotEnd.equals("upper")))
2303 02 Apr 14 olle 1140     {
2303 02 Apr 14 olle 1141       return null;
2303 02 Apr 14 olle 1142     }
2303 02 Apr 14 olle 1143     int len = sortedAscFloatList.size();
2303 02 Apr 14 olle 1144     // List index values goes from 0 to (len - 1)
2303 02 Apr 14 olle 1145     float ipr = pct75 - pct25;
2303 02 Apr 14 olle 1146     float limit = 0.0f;
2303 02 Apr 14 olle 1147     if (plotEnd.equals("lower"))
2303 02 Apr 14 olle 1148     {
2303 02 Apr 14 olle 1149       limit = pct25 - ipr*coef;
2303 02 Apr 14 olle 1150       float value = 1000000000.0f;
2303 02 Apr 14 olle 1151       for (int i=(len-1); i >= 0; i--)
2303 02 Apr 14 olle 1152       {
2303 02 Apr 14 olle 1153         value = sortedAscFloatList.get(i);
2303 02 Apr 14 olle 1154         if (value < limit)
2303 02 Apr 14 olle 1155         {
2303 02 Apr 14 olle 1156           break;
2303 02 Apr 14 olle 1157         }
2303 02 Apr 14 olle 1158         whiskerValue = value;
2303 02 Apr 14 olle 1159       }
2303 02 Apr 14 olle 1160     }
2303 02 Apr 14 olle 1161     else if (plotEnd.equals("upper"))
2303 02 Apr 14 olle 1162     {
2303 02 Apr 14 olle 1163       limit = pct75 + ipr*coef;
2303 02 Apr 14 olle 1164       float value = -1000000000.0f;
2303 02 Apr 14 olle 1165       for (int i=0; i < len; i++)
2303 02 Apr 14 olle 1166       {
2303 02 Apr 14 olle 1167         value = sortedAscFloatList.get(i);
2303 02 Apr 14 olle 1168         if (value > limit)
2303 02 Apr 14 olle 1169         {
2303 02 Apr 14 olle 1170           break;
2303 02 Apr 14 olle 1171         }
2303 02 Apr 14 olle 1172         whiskerValue = value;
2303 02 Apr 14 olle 1173       }
2303 02 Apr 14 olle 1174     }
2303 02 Apr 14 olle 1175     return whiskerValue;
2303 02 Apr 14 olle 1176   }
2303 02 Apr 14 olle 1177
2303 02 Apr 14 olle 1178   /**
2303 02 Apr 14 olle 1179    *  Returns a chart header title given a chart variant string.
2303 02 Apr 14 olle 1180    *  If a plot is shown, this is normally the header title
2303 02 Apr 14 olle 1181    *  printed over the plot itself.
2303 02 Apr 14 olle 1182    *
2303 02 Apr 14 olle 1183    *  @param chartVariant String The chart variant to get a plot title for.
2303 02 Apr 14 olle 1184    *  @param viewType String The view type used for the period selection for the plot.
2303 02 Apr 14 olle 1185    *  @param chartSite String The site used for the data selection for the plot.
2303 02 Apr 14 olle 1186    *  @param variableType String The variable used for the data selection for the plot.
2395 29 Apr 14 olle 1187    *  @param weekdayFilter String Optional weekday filter.
2303 02 Apr 14 olle 1188    *  @return String A plot title for the given chart variant string.
2303 02 Apr 14 olle 1189    */
2395 29 Apr 14 olle 1190   private String fetchChartHeaderTitle(String chartVariant, String viewType, String chartSite, String variableType, String weekdayFilter)
2303 02 Apr 14 olle 1191   {
2303 02 Apr 14 olle 1192     // Get time period name for title
2303 02 Apr 14 olle 1193     String periodName = fetchTimePeriodName(viewType);
2303 02 Apr 14 olle 1194     // Get plot title
2303 02 Apr 14 olle 1195     String title = "New chart";
2303 02 Apr 14 olle 1196     if (chartVariant != null)
2303 02 Apr 14 olle 1197     {
2303 02 Apr 14 olle 1198       // String "\u00B5" is the micro character in unicode
2303 02 Apr 14 olle 1199       // String "\u223C" is the tilde character in unicode
2395 29 Apr 14 olle 1200       String chartContents = null;
2303 02 Apr 14 olle 1201       if (viewType.equals("dailyDistribution"))
2303 02 Apr 14 olle 1202       {
2395 29 Apr 14 olle 1203         chartContents = "daily distribution";
2303 02 Apr 14 olle 1204       }
2303 02 Apr 14 olle 1205       else if (viewType.equals("weeklyDistribution"))
2303 02 Apr 14 olle 1206       {
2395 29 Apr 14 olle 1207         chartContents = "weekly distribution";
2303 02 Apr 14 olle 1208       }
2395 29 Apr 14 olle 1209       String weekdayStr = "";
2395 29 Apr 14 olle 1210       if (weekdayFilter != null)
2395 29 Apr 14 olle 1211       {
2395 29 Apr 14 olle 1212         if (weekdayFilter.equals(weekdayFilterMondayToFriday))
2395 29 Apr 14 olle 1213         {
2395 29 Apr 14 olle 1214           weekdayStr = "Mon-Fri";
2395 29 Apr 14 olle 1215         }
2395 29 Apr 14 olle 1216         else if (weekdayFilter.equals(weekdayFilterSaturdayToSunday))
2395 29 Apr 14 olle 1217         {
2395 29 Apr 14 olle 1218           weekdayStr = "Sat-Sun";
2395 29 Apr 14 olle 1219         }
2395 29 Apr 14 olle 1220         else if (weekdayFilter.equals(weekdayFilterWorkdays))
2395 29 Apr 14 olle 1221         {
2395 29 Apr 14 olle 1222           weekdayStr = "Workdays";
2395 29 Apr 14 olle 1223         }
2395 29 Apr 14 olle 1224         else if (weekdayFilter.equals(weekdayFilterNonWorkdays))
2395 29 Apr 14 olle 1225         {
2395 29 Apr 14 olle 1226           weekdayStr = "Non-workdays";
2395 29 Apr 14 olle 1227         }
2395 29 Apr 14 olle 1228       }
2395 29 Apr 14 olle 1229       if (chartContents != null)
2395 29 Apr 14 olle 1230       {
2395 29 Apr 14 olle 1231         if (weekdayStr.equals(""))
2395 29 Apr 14 olle 1232         {
2395 29 Apr 14 olle 1233           title = chartSite + " " + chartContents + " of " + variableType;
2395 29 Apr 14 olle 1234         }
2395 29 Apr 14 olle 1235         else
2395 29 Apr 14 olle 1236         {
2395 29 Apr 14 olle 1237           title = chartSite + " " + chartContents + " of " + variableType + " (" + weekdayStr + ")";
2395 29 Apr 14 olle 1238         }
2395 29 Apr 14 olle 1239       }
2303 02 Apr 14 olle 1240     }
2303 02 Apr 14 olle 1241     return title;
2303 02 Apr 14 olle 1242   }
2303 02 Apr 14 olle 1243
2303 02 Apr 14 olle 1244   /**
2303 02 Apr 14 olle 1245    *  Returns a chart header title given a chart variant string.
2303 02 Apr 14 olle 1246    *  If a plot is shown, this is normally the header title
2303 02 Apr 14 olle 1247    *  printed over the plot itself.
2303 02 Apr 14 olle 1248    *
2303 02 Apr 14 olle 1249    *  @param chartVariant String The chart variant to get a plot title for.
2303 02 Apr 14 olle 1250    *  @param viewType String The view type used for the period selection for the plot.
2303 02 Apr 14 olle 1251    *  @param chartSite String The site used for the data selection for the plot.
2303 02 Apr 14 olle 1252    *  @param variableType String The variable used for the data selection for the plot.
2303 02 Apr 14 olle 1253    *  @param startDate Date The start date/time for the data selection for the plot.
2303 02 Apr 14 olle 1254    *  @param endDate Date The end date/time for the data selection for the plot.
2303 02 Apr 14 olle 1255    *  @return String A plot title for the given chart variant string.
2303 02 Apr 14 olle 1256    */
2303 02 Apr 14 olle 1257   private String fetchChartHeaderTitle(String viewType, Date startDate, Date endDate)
2303 02 Apr 14 olle 1258   {
2303 02 Apr 14 olle 1259     // Get plot title
2303 02 Apr 14 olle 1260     String title = "New chart";
2303 02 Apr 14 olle 1261     DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd HH:mm");
2303 02 Apr 14 olle 1262     String startDateStr = "Start";
2303 02 Apr 14 olle 1263     String endDateStr = "Current";
2303 02 Apr 14 olle 1264     if (startDate != null)
2303 02 Apr 14 olle 1265     {
2303 02 Apr 14 olle 1266       startDateStr = dateFormat.format(startDate);
2303 02 Apr 14 olle 1267     }
2303 02 Apr 14 olle 1268     if (endDate != null)
2303 02 Apr 14 olle 1269     {
2303 02 Apr 14 olle 1270       endDateStr = dateFormat.format(endDate);
2303 02 Apr 14 olle 1271     }
2303 02 Apr 14 olle 1272     if (viewType != null)
2303 02 Apr 14 olle 1273     {
2303 02 Apr 14 olle 1274       // String "\u00B5" is the micro character in unicode
2303 02 Apr 14 olle 1275       // String "\u223C" is the tilde character in unicode
2395 29 Apr 14 olle 1276       String chartContents = null;
2303 02 Apr 14 olle 1277       if (viewType.equals("dailyDistribution"))
2303 02 Apr 14 olle 1278       {
2395 29 Apr 14 olle 1279         chartContents = "Daily distribution";
2303 02 Apr 14 olle 1280       }
2303 02 Apr 14 olle 1281       else if (viewType.equals("weeklyDistribution"))
2303 02 Apr 14 olle 1282       {
2395 29 Apr 14 olle 1283         chartContents = "Weekly distribution";
2303 02 Apr 14 olle 1284       }
2395 29 Apr 14 olle 1285       if (chartContents != null)
2395 29 Apr 14 olle 1286       {
2395 29 Apr 14 olle 1287         title = chartContents + " for period " + startDateStr + " - " + endDateStr;
2395 29 Apr 14 olle 1288       }
2303 02 Apr 14 olle 1289     }
2303 02 Apr 14 olle 1290     return title;
2303 02 Apr 14 olle 1291   }
2303 02 Apr 14 olle 1292
2303 02 Apr 14 olle 1293   /**
2303 02 Apr 14 olle 1294    *  Returns the time period name for a view type string.
2303 02 Apr 14 olle 1295    *
2303 02 Apr 14 olle 1296    *  @param viewType String The view type used for time period selection.
2303 02 Apr 14 olle 1297    *  @return String The time period name.
2303 02 Apr 14 olle 1298    */
2303 02 Apr 14 olle 1299   private String fetchTimePeriodName(String viewType)
2303 02 Apr 14 olle 1300   {
2303 02 Apr 14 olle 1301     // Get time period name
2303 02 Apr 14 olle 1302     String periodName = "year";
2303 02 Apr 14 olle 1303     if (viewType.equals(ReportTableUtil.quarterView))
2303 02 Apr 14 olle 1304     {
2303 02 Apr 14 olle 1305       periodName = "quarter";
2303 02 Apr 14 olle 1306     }
2303 02 Apr 14 olle 1307     else if (viewType.equals(ReportTableUtil.monthView))
2303 02 Apr 14 olle 1308     {
2303 02 Apr 14 olle 1309       periodName = "month";
2303 02 Apr 14 olle 1310     }
2303 02 Apr 14 olle 1311     else if (viewType.equals(ReportTableUtil.weekView))
2303 02 Apr 14 olle 1312     {
2303 02 Apr 14 olle 1313       periodName = "week";
2303 02 Apr 14 olle 1314     }
2303 02 Apr 14 olle 1315     return periodName;
2303 02 Apr 14 olle 1316   }
2303 02 Apr 14 olle 1317
2303 02 Apr 14 olle 1318   /**
2303 02 Apr 14 olle 1319    *  Returns a chart title given mixed information.
2303 02 Apr 14 olle 1320    *
2303 02 Apr 14 olle 1321    *  @param viewType String The view type used.
2303 02 Apr 14 olle 1322    *  @param chartSite String The chart site used.
2303 02 Apr 14 olle 1323    *  @param variableType String The variable type used.
2303 02 Apr 14 olle 1324    *  @return String A chart title for the given input.
2303 02 Apr 14 olle 1325    */
2303 02 Apr 14 olle 1326   private String fetchChartTitle(String viewType, String chartSite, String variableType)
2303 02 Apr 14 olle 1327   {
2303 02 Apr 14 olle 1328     String title = "New chart";
2303 02 Apr 14 olle 1329     if (viewType != null)
2303 02 Apr 14 olle 1330     {
2303 02 Apr 14 olle 1331       // String "\u00B5" is the micro character in unicode
2303 02 Apr 14 olle 1332       // String "\u223C" is the tilde character in unicode
2303 02 Apr 14 olle 1333       if (viewType.equals("dailyDistribution"))
2303 02 Apr 14 olle 1334       {
2303 02 Apr 14 olle 1335         title = chartSite + " daily distribution of " + variableType;
2303 02 Apr 14 olle 1336       }
2303 02 Apr 14 olle 1337       else if (viewType.equals("weeklyDistribution"))
2303 02 Apr 14 olle 1338       {
2303 02 Apr 14 olle 1339         title = chartSite + " weekly distribution of " + variableType;
2303 02 Apr 14 olle 1340       }
2303 02 Apr 14 olle 1341     }
2303 02 Apr 14 olle 1342     return title;
2303 02 Apr 14 olle 1343   }
2303 02 Apr 14 olle 1344
2303 02 Apr 14 olle 1345   /**
2303 02 Apr 14 olle 1346    *  Returns a chart title given mixed information.
2303 02 Apr 14 olle 1347    *
2303 02 Apr 14 olle 1348    *  @param viewType String The view type used.
2303 02 Apr 14 olle 1349    *  @param variableType String The variable used for the data selection for the plot.
2303 02 Apr 14 olle 1350    *  @param startDate Date The start date/time for the data selection for the plot.
2303 02 Apr 14 olle 1351    *  @param endDate Date The end date/time for the data selection for the plot.
2395 29 Apr 14 olle 1352    *  @param daytimeFilterFromTime String Optional daytime filter start time.
2395 29 Apr 14 olle 1353    *  @param daytimeFilterToTime String Optional daytime filter end time.
2303 02 Apr 14 olle 1354    *  @return String A chart title for the given input.
2303 02 Apr 14 olle 1355    */
2395 29 Apr 14 olle 1356   private String fetchChartTitle(String viewType, String variableType, Date startDate, Date endDate, String daytimeFilterFromTime, String daytimeFilterToTime)
2321 04 Apr 14 olle 1357     throws ServletException
2303 02 Apr 14 olle 1358   {
2303 02 Apr 14 olle 1359     // Get plot title
2303 02 Apr 14 olle 1360     String title = "New chart";
2303 02 Apr 14 olle 1361     DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd HH:mm");
2303 02 Apr 14 olle 1362     // Get report start date
2303 02 Apr 14 olle 1363     Date reportStartDate = null;
2303 02 Apr 14 olle 1364     if (startDate != null)
2303 02 Apr 14 olle 1365     {
2303 02 Apr 14 olle 1366       reportStartDate = startDate;
2303 02 Apr 14 olle 1367     }
2303 02 Apr 14 olle 1368     else
2303 02 Apr 14 olle 1369     {
2303 02 Apr 14 olle 1370       // Set report start date to earliest configured sensor start date
2303 02 Apr 14 olle 1371       // Get lab environment configuration from singleton LabEnvironment
2326 07 Apr 14 olle 1372       LabEnvironment labEnvironment = LabEnvironment.getInstance();
2303 02 Apr 14 olle 1373       LabEnvironmentConfiguration labEnvironmentConfiguration = labEnvironment.getLabEnvironmentConfiguration();
2303 02 Apr 14 olle 1374       List<LabSensorConfig> labSensorConfigList = labEnvironmentConfiguration.getLabSensorConfigList();
2303 02 Apr 14 olle 1375       for (LabSensorConfig labSensorConfig: labSensorConfigList)
2303 02 Apr 14 olle 1376       {
2303 02 Apr 14 olle 1377         String sensorStartDateStr = labSensorConfig.getStartDate();
2303 02 Apr 14 olle 1378         // Skip sensors with start date not set
2303 02 Apr 14 olle 1379         if (sensorStartDateStr != null && !sensorStartDateStr.equals(""))
2303 02 Apr 14 olle 1380         {
2303 02 Apr 14 olle 1381           // Set report start date to earliest sensor date
2303 02 Apr 14 olle 1382           Date sensorDate = dateStringToDate(sensorStartDateStr);
2303 02 Apr 14 olle 1383           if (reportStartDate == null || reportStartDate.compareTo(sensorDate) > 0)
2303 02 Apr 14 olle 1384           {
2303 02 Apr 14 olle 1385             reportStartDate = sensorDate;
2303 02 Apr 14 olle 1386           }
2303 02 Apr 14 olle 1387         }
2303 02 Apr 14 olle 1388       }
2303 02 Apr 14 olle 1389     }
2303 02 Apr 14 olle 1390     // Get report end date
2303 02 Apr 14 olle 1391     Date reportEndDate = null;
2303 02 Apr 14 olle 1392     if (endDate != null)
2303 02 Apr 14 olle 1393     {
2303 02 Apr 14 olle 1394       reportEndDate = endDate;
2303 02 Apr 14 olle 1395     }
2303 02 Apr 14 olle 1396     else
2303 02 Apr 14 olle 1397     {
2303 02 Apr 14 olle 1398       // Set report end date to current date/time
2303 02 Apr 14 olle 1399       reportEndDate = new Date();
2303 02 Apr 14 olle 1400     }
2303 02 Apr 14 olle 1401     // Get report start and end date strings
2303 02 Apr 14 olle 1402     String reportStartDateStr = "Start";
2303 02 Apr 14 olle 1403     String reportEndDateStr = "Current";
2303 02 Apr 14 olle 1404     if (reportStartDate != null)
2303 02 Apr 14 olle 1405     {
2303 02 Apr 14 olle 1406       reportStartDateStr = dateFormat.format(reportStartDate);
2303 02 Apr 14 olle 1407     }
2303 02 Apr 14 olle 1408     if (reportEndDate != null)
2303 02 Apr 14 olle 1409     {
2303 02 Apr 14 olle 1410       reportEndDateStr = dateFormat.format(reportEndDate);
2303 02 Apr 14 olle 1411     }
2303 02 Apr 14 olle 1412     // Start variable type string with capital
2303 02 Apr 14 olle 1413     String varTypeStr = "Variable";
2303 02 Apr 14 olle 1414     if (variableType != null && variableType.length() > 0)
2303 02 Apr 14 olle 1415     {
2303 02 Apr 14 olle 1416       String firstChar = variableType.substring(0,1).toUpperCase();
2303 02 Apr 14 olle 1417       varTypeStr = firstChar + variableType.substring(1);
2303 02 Apr 14 olle 1418     }
2395 29 Apr 14 olle 1419     // Optional daytime filter
2395 29 Apr 14 olle 1420     String daytimeFilterStr = null;
2395 29 Apr 14 olle 1421     if ((daytimeFilterFromTime != null && !daytimeFilterFromTime.equals("")) ||
2395 29 Apr 14 olle 1422       (daytimeFilterToTime != null && !daytimeFilterToTime.equals("")))
2303 02 Apr 14 olle 1423     {
2395 29 Apr 14 olle 1424       if (daytimeFilterFromTime == null || daytimeFilterFromTime.equals(""))
2303 02 Apr 14 olle 1425       {
2395 29 Apr 14 olle 1426         daytimeFilterFromTime = "0000";
2303 02 Apr 14 olle 1427       }
2395 29 Apr 14 olle 1428       if (daytimeFilterToTime == null || daytimeFilterToTime.equals(""))
2303 02 Apr 14 olle 1429       {
2395 29 Apr 14 olle 1430         daytimeFilterToTime = "2359";
2303 02 Apr 14 olle 1431       }
2395 29 Apr 14 olle 1432       daytimeFilterStr = daytimeFilterFromTime + " - " + daytimeFilterToTime;
2303 02 Apr 14 olle 1433     }
2395 29 Apr 14 olle 1434     if (daytimeFilterStr == null)
2303 02 Apr 14 olle 1435     {
2395 29 Apr 14 olle 1436       title = varTypeStr + " (" + reportStartDateStr + " - " + reportEndDateStr + ")";
2303 02 Apr 14 olle 1437     }
2395 29 Apr 14 olle 1438     else
2395 29 Apr 14 olle 1439     {
2395 29 Apr 14 olle 1440       title = "(" + reportStartDateStr + " - " + reportEndDateStr + ") " + daytimeFilterStr;
2395 29 Apr 14 olle 1441     }
2303 02 Apr 14 olle 1442     return title;
2303 02 Apr 14 olle 1443   }
2303 02 Apr 14 olle 1444
2303 02 Apr 14 olle 1445   /**
2303 02 Apr 14 olle 1446    *  Returns a chart y-axis title given a variable type string.
2303 02 Apr 14 olle 1447    *
2303 02 Apr 14 olle 1448    *  @param variableType String The variable type to get a y-axis title for.
2303 02 Apr 14 olle 1449    *  @return String A chart y-axis title for the given variable type string.
2303 02 Apr 14 olle 1450    */
2303 02 Apr 14 olle 1451   private String fetchChartYAxisTitle(String variableType)
2303 02 Apr 14 olle 1452   {
2303 02 Apr 14 olle 1453     String title = "New chart";
2303 02 Apr 14 olle 1454     if (variableType != null)
2303 02 Apr 14 olle 1455     {
2303 02 Apr 14 olle 1456       // String "\u00B5" is the micro character in unicode
2303 02 Apr 14 olle 1457       // String "\u223C" is the tilde character in unicode
2303 02 Apr 14 olle 1458       // String "\u00B0" is the degree character in unicode
2303 02 Apr 14 olle 1459       if (variableType.equals(variableTypeTemperature))
2303 02 Apr 14 olle 1460       {
2303 02 Apr 14 olle 1461         title = "Temperature (\u00B0C)";
2303 02 Apr 14 olle 1462       }
2303 02 Apr 14 olle 1463       else if (variableType.equals(variableTypeHumidity))
2303 02 Apr 14 olle 1464       {
2303 02 Apr 14 olle 1465         title = "Humidity (%)";
2303 02 Apr 14 olle 1466       }
2303 02 Apr 14 olle 1467     }
2303 02 Apr 14 olle 1468     return title;
2303 02 Apr 14 olle 1469   }
2395 29 Apr 14 olle 1470
2395 29 Apr 14 olle 1471
2303 02 Apr 14 olle 1472 }