extensions/net.sf.basedb.meludi/trunk/src/net/sf/basedb/meludi/servlet/BaseLineRegistrationServlet.java

Code
Comments
Other
Rev Date Author Line
4832 05 Jun 18 olle 1 package net.sf.basedb.meludi.servlet;
4832 05 Jun 18 olle 2
5149 28 Nov 18 olle 3 import java.io.BufferedReader;
4832 05 Jun 18 olle 4 import java.io.IOException;
5149 28 Nov 18 olle 5 import java.io.InputStream;
5149 28 Nov 18 olle 6 import java.io.InputStreamReader;
5149 28 Nov 18 olle 7 import java.io.OutputStream;
5149 28 Nov 18 olle 8 import java.io.OutputStreamWriter;
4832 05 Jun 18 olle 9 import java.text.SimpleDateFormat;
4832 05 Jun 18 olle 10 import java.util.ArrayList;
4832 05 Jun 18 olle 11 import java.util.Date;
4832 05 Jun 18 olle 12 import java.util.HashMap;
4832 05 Jun 18 olle 13 import java.util.List;
4832 05 Jun 18 olle 14
4832 05 Jun 18 olle 15 import javax.servlet.ServletException;
4832 05 Jun 18 olle 16 import javax.servlet.http.HttpServlet;
4832 05 Jun 18 olle 17 import javax.servlet.http.HttpServletRequest;
4832 05 Jun 18 olle 18 import javax.servlet.http.HttpServletResponse;
4832 05 Jun 18 olle 19
4832 05 Jun 18 olle 20 import org.json.simple.JSONArray;
4832 05 Jun 18 olle 21 import org.json.simple.JSONObject;
4832 05 Jun 18 olle 22 import org.json.simple.parser.JSONParser;
4832 05 Jun 18 olle 23
4832 05 Jun 18 olle 24 import net.sf.basedb.core.Annotatable;
5114 20 Nov 18 olle 25 import net.sf.basedb.core.AnnotationType;
4832 05 Jun 18 olle 26 import net.sf.basedb.core.Application;
4832 05 Jun 18 olle 27 import net.sf.basedb.core.BioMaterialEvent;
4832 05 Jun 18 olle 28 import net.sf.basedb.core.BioPlate;
5114 20 Nov 18 olle 29 import net.sf.basedb.core.BioPlateEvent;
5114 20 Nov 18 olle 30 import net.sf.basedb.core.BioPlateEventParticipant;
5114 20 Nov 18 olle 31 import net.sf.basedb.core.BioPlateEventType;
4832 05 Jun 18 olle 32 import net.sf.basedb.core.BioPlateType;
4832 05 Jun 18 olle 33 import net.sf.basedb.core.BioSource;
4832 05 Jun 18 olle 34 import net.sf.basedb.core.BioWell;
4832 05 Jun 18 olle 35 import net.sf.basedb.core.DbControl;
4832 05 Jun 18 olle 36 import net.sf.basedb.core.Extract;
5149 28 Nov 18 olle 37 import net.sf.basedb.core.File;
4832 05 Jun 18 olle 38 import net.sf.basedb.core.InvalidDataException;
4832 05 Jun 18 olle 39 import net.sf.basedb.core.ItemQuery;
4832 05 Jun 18 olle 40 import net.sf.basedb.core.ItemResultList;
5114 20 Nov 18 olle 41 import net.sf.basedb.core.MeasuredBioMaterial;
5149 28 Nov 18 olle 42 import net.sf.basedb.core.Path;
4862 19 Jun 18 olle 43 import net.sf.basedb.core.Permission;
4832 05 Jun 18 olle 44 import net.sf.basedb.core.PlateGeometry;
4832 05 Jun 18 olle 45 import net.sf.basedb.core.Sample;
4832 05 Jun 18 olle 46 import net.sf.basedb.core.SessionControl;
5848 02 Mar 20 olle 47 import net.sf.basedb.core.Type;
4832 05 Jun 18 olle 48 import net.sf.basedb.core.query.Expressions;
4832 05 Jun 18 olle 49 import net.sf.basedb.core.query.Hql;
4832 05 Jun 18 olle 50 import net.sf.basedb.core.query.Orders;
4832 05 Jun 18 olle 51 import net.sf.basedb.core.query.Restrictions;
5060 29 Oct 18 olle 52 import net.sf.basedb.core.snapshot.SnapshotManager;
4832 05 Jun 18 olle 53 import net.sf.basedb.meludi.JsonUtil;
4832 05 Jun 18 olle 54 import net.sf.basedb.meludi.Meludi;
4832 05 Jun 18 olle 55 import net.sf.basedb.meludi.Site;
4832 05 Jun 18 olle 56 import net.sf.basedb.meludi.converter.StringToDateConverter;
4832 05 Jun 18 olle 57 import net.sf.basedb.meludi.dao.Annotationtype;
5114 20 Nov 18 olle 58 import net.sf.basedb.meludi.dao.BioplateType;
4862 19 Jun 18 olle 59 import net.sf.basedb.meludi.dao.Blood;
4832 05 Jun 18 olle 60 import net.sf.basedb.meludi.dao.Case;
4832 05 Jun 18 olle 61 import net.sf.basedb.meludi.dao.Consent;
4832 05 Jun 18 olle 62 import net.sf.basedb.meludi.dao.Dna;
5044 19 Oct 18 olle 63 import net.sf.basedb.meludi.dao.FfpeBlock;
5114 20 Nov 18 olle 64 import net.sf.basedb.meludi.dao.HeGlass;
4832 05 Jun 18 olle 65 import net.sf.basedb.meludi.dao.Patient;
4832 05 Jun 18 olle 66 import net.sf.basedb.meludi.dao.MeludiRole;
4832 05 Jun 18 olle 67 import net.sf.basedb.meludi.dao.Rna;
4832 05 Jun 18 olle 68 import net.sf.basedb.meludi.dao.SpecimenTube;
4832 05 Jun 18 olle 69 import net.sf.basedb.meludi.dao.StoragePlate;
4832 05 Jun 18 olle 70 import net.sf.basedb.meludi.dao.Subtype;
4832 05 Jun 18 olle 71 import net.sf.basedb.meludi.counter.CounterService;
4832 05 Jun 18 olle 72 import net.sf.basedb.util.MD5;
4832 05 Jun 18 olle 73 import net.sf.basedb.util.Values;
4832 05 Jun 18 olle 74 import net.sf.basedb.util.error.ThrowableUtil;
4832 05 Jun 18 olle 75 import net.sf.basedb.util.formatter.WellCoordinateFormatter;
4832 05 Jun 18 olle 76
4832 05 Jun 18 olle 77
4832 05 Jun 18 olle 78 public class BaseLineRegistrationServlet 
4832 05 Jun 18 olle 79   extends HttpServlet 
4832 05 Jun 18 olle 80 {
4832 05 Jun 18 olle 81
4832 05 Jun 18 olle 82   private static final long serialVersionUID = 8670173686061080429L;
4832 05 Jun 18 olle 83   
4832 05 Jun 18 olle 84   public BaseLineRegistrationServlet()
4832 05 Jun 18 olle 85   {}
4832 05 Jun 18 olle 86
4832 05 Jun 18 olle 87   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 88   @Override
4832 05 Jun 18 olle 89   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
4832 05 Jun 18 olle 90     throws ServletException, IOException 
4832 05 Jun 18 olle 91   {
4832 05 Jun 18 olle 92
4832 05 Jun 18 olle 93     String ID = req.getParameter("ID");
4832 05 Jun 18 olle 94     String cmd = req.getParameter("cmd");
4832 05 Jun 18 olle 95     JsonUtil.setJsonResponseHeaders(resp);
4832 05 Jun 18 olle 96     
4832 05 Jun 18 olle 97     JSONObject json = new JSONObject();
4832 05 Jun 18 olle 98     json.put("status", "ok");
4832 05 Jun 18 olle 99   
5468 04 Jun 19 olle 100     //final SessionControl sc = Application.getSessionControl(ID, req.getRemoteAddr());
5744 20 Nov 19 olle 101     //final SessionControl sc  = Application.getSessionControl(ID, "", req.getRemoteAddr(), true);
5744 20 Nov 19 olle 102     final SessionControl sc  = Application.getSessionControl(ID, null, req.getRemoteAddr(), true);
4832 05 Jun 18 olle 103     DbControl dc = null;
4832 05 Jun 18 olle 104     try
4832 05 Jun 18 olle 105     {
4832 05 Jun 18 olle 106       if ("GetCaseInfo".equals(cmd))
4832 05 Jun 18 olle 107       {
4832 05 Jun 18 olle 108         /*
4832 05 Jun 18 olle 109           Load information about a single case when given the case name/barcode
4832 05 Jun 18 olle 110           If a case is found we will load annotations, the patient it is associated with
4832 05 Jun 18 olle 111           and specimen tubes for the case. If no case is found we check to see
4832 05 Jun 18 olle 112           if there are any specimen tubes that have the case name as prefix and
4832 05 Jun 18 olle 113           load information about them.
4832 05 Jun 18 olle 114         */
4832 05 Jun 18 olle 115         dc = sc.newDbControl();
4832 05 Jun 18 olle 116         
4832 05 Jun 18 olle 117         // Find a case by name
4832 05 Jun 18 olle 118         String caseName = req.getParameter("caseName");
4832 05 Jun 18 olle 119         Site site = Site.findByCaseName(caseName);
4832 05 Jun 18 olle 120         Case theCase = Case.findByName(dc, caseName);
4832 05 Jun 18 olle 121         
4832 05 Jun 18 olle 122         List<SpecimenTube> specimenTubes = null;
4832 05 Jun 18 olle 123         List<Dna> dnaTubes = null;
4832 05 Jun 18 olle 124         List<Rna> rnaTubes = null;
4832 05 Jun 18 olle 125         JSONObject jsonCase = null;
4832 05 Jun 18 olle 126         
4832 05 Jun 18 olle 127         int numExisting = 0;
4832 05 Jun 18 olle 128         if (theCase != null)
4832 05 Jun 18 olle 129         {
4870 25 Jun 18 olle 130           theCase.loadAnnotations(dc, "referralId", Annotationtype.REFERRAL_ID, null);
4832 05 Jun 18 olle 131           theCase.loadAnnotations(dc, "tubeContentType", Annotationtype.TUBE_CONTENT_TYPE, null);
4832 05 Jun 18 olle 132
4832 05 Jun 18 olle 133           // Load specimen tubes for the case
4832 05 Jun 18 olle 134           specimenTubes = SpecimenTube.findByCase(dc, theCase, caseName);
4832 05 Jun 18 olle 135           if (specimenTubes.size() == 0)
4832 05 Jun 18 olle 136           {
4832 05 Jun 18 olle 137             // No specimen tubes are linked with the case -- see if we can find some unlinked
4832 05 Jun 18 olle 138             specimenTubes = SpecimenTube.findByCaseName(dc, caseName);
4832 05 Jun 18 olle 139           }
4832 05 Jun 18 olle 140           
4832 05 Jun 18 olle 141           // Load DNA tubes for the case
4832 05 Jun 18 olle 142           dnaTubes = Dna.findByCaseName(dc, caseName);
4832 05 Jun 18 olle 143           
4832 05 Jun 18 olle 144           // Load RNA tubes for the case
4832 05 Jun 18 olle 145           rnaTubes = Rna.findByCaseName(dc, caseName);
4832 05 Jun 18 olle 146           
4832 05 Jun 18 olle 147           // Wrap what we have so far up into JSON objects
4832 05 Jun 18 olle 148           jsonCase = theCase.asJSONObject();
4832 05 Jun 18 olle 149           
4832 05 Jun 18 olle 150           // Load the patient associated with the case
4832 05 Jun 18 olle 151           Patient patient = Patient.findByCase(dc, theCase);
4832 05 Jun 18 olle 152           // The patient can be null if (for example) we have only registered consent=yes so far
4832 05 Jun 18 olle 153           if (patient != null) 
4832 05 Jun 18 olle 154           {
4832 05 Jun 18 olle 155             patient.loadDefaultAnnotations(dc);
4832 05 Jun 18 olle 156             jsonCase.put("patient", patient.asJSONObject());
4832 05 Jun 18 olle 157           }
4832 05 Jun 18 olle 158         }
4832 05 Jun 18 olle 159         else
4832 05 Jun 18 olle 160         {
4832 05 Jun 18 olle 161           // Could not find the registered case -- see if we can find any specimen tubes
4832 05 Jun 18 olle 162           specimenTubes = SpecimenTube.findByCaseName(dc, caseName);
4832 05 Jun 18 olle 163           // Get rid of suffix in the case name
4832 05 Jun 18 olle 164           caseName = Meludi.fetchRootItemName(caseName, sc.getActiveProjectId());
4832 05 Jun 18 olle 165           jsonCase = new JSONObject();
4832 05 Jun 18 olle 166           jsonCase.put("name", caseName);
4832 05 Jun 18 olle 167           jsonCase.put("originalName", caseName);
4832 05 Jun 18 olle 168
4832 05 Jun 18 olle 169           // Check if site should be found from site prefix
4832 05 Jun 18 olle 170           String siteDefault = null;
4832 05 Jun 18 olle 171           Boolean usesSitePrefix = Meludi.fetchUsesSitePrefix(sc.getActiveProjectId());
4832 05 Jun 18 olle 172           if (usesSitePrefix)
4832 05 Jun 18 olle 173           {
4832 05 Jun 18 olle 174             String caseNameDigits = Meludi.fetchRootDigits(caseName, sc.getActiveProjectId());
4832 05 Jun 18 olle 175             String sitePrefix = caseNameDigits.substring(0, 2);
4832 05 Jun 18 olle 176             HashMap<String,String> sitePrefixSiteKeyHashMap = Meludi.fetchSitePrefixSiteKeyHashMap(sc.getActiveProjectId());
4832 05 Jun 18 olle 177             if (sitePrefixSiteKeyHashMap != null)
4832 05 Jun 18 olle 178             {
4832 05 Jun 18 olle 179               siteDefault = sitePrefixSiteKeyHashMap.get(sitePrefix);
4832 05 Jun 18 olle 180               if (siteDefault == null)
4832 05 Jun 18 olle 181               {
4832 05 Jun 18 olle 182                 siteDefault = "";
4832 05 Jun 18 olle 183               }
4832 05 Jun 18 olle 184             }
4832 05 Jun 18 olle 185           }
4832 05 Jun 18 olle 186           jsonCase.put("siteDefault", siteDefault);
4832 05 Jun 18 olle 187         }
4832 05 Jun 18 olle 188
4832 05 Jun 18 olle 189         // Load 'Specimen' annotations
4832 05 Jun 18 olle 190         JSONArray jsonTubes = new JSONArray();
4832 05 Jun 18 olle 191         if (specimenTubes != null && specimenTubes.size() > 0)
4832 05 Jun 18 olle 192         {
4832 05 Jun 18 olle 193           for (SpecimenTube tube : specimenTubes)
4832 05 Jun 18 olle 194           {
4832 05 Jun 18 olle 195             tube.loadAnnotations(dc, "plNumber", Annotationtype.PL_NUMBER, null);
4832 05 Jun 18 olle 196             tube.loadAnnotations(dc, "pad", Annotationtype.PAD, null);
4832 05 Jun 18 olle 197             tube.loadAnnotations(dc, "samplingDate", Annotationtype.SAMPLING_DATE, Meludi.CONVERTER_DATE_TO_STRING);
4832 05 Jun 18 olle 198             tube.loadAnnotations(dc, "specimenType", Annotationtype.SPECIMEN_TYPE, null);
4832 05 Jun 18 olle 199             tube.loadAnnotations(dc, "specimenInputType", Annotationtype.SPECIMEN_INPUT_TYPE, null);
4832 05 Jun 18 olle 200             tube.loadAnnotations(dc, "viableTumourCellsPercent", Annotationtype.VIABLE_TUMOUR_CELLS_PERCENT, null);
4832 05 Jun 18 olle 201             jsonTubes.add(tube.asJSONObject());
4832 05 Jun 18 olle 202           }
4832 05 Jun 18 olle 203         }
4832 05 Jun 18 olle 204         jsonCase.put("specimen", jsonTubes);
4832 05 Jun 18 olle 205         jsonCase.put("specimenFirstIndex", numExisting+1);
4832 05 Jun 18 olle 206
4832 05 Jun 18 olle 207         // Load 'DNA' annotations
4832 05 Jun 18 olle 208         JSONArray jsonDna = new JSONArray();
4832 05 Jun 18 olle 209         if (dnaTubes != null && dnaTubes.size() > 0)
4832 05 Jun 18 olle 210         {
4832 05 Jun 18 olle 211           for (Dna d : dnaTubes)
4832 05 Jun 18 olle 212           {
4832 05 Jun 18 olle 213             Extract e = d.getExtract();
4832 05 Jun 18 olle 214             BioMaterialEvent created = e.getCreationEvent();
4832 05 Jun 18 olle 215             d.setAnnotation("extractionDate", Meludi.CONVERTER_DATE_TO_STRING.convert(created.getEventDate()));
4832 05 Jun 18 olle 216             jsonDna.add(d.asJSONObject());
4832 05 Jun 18 olle 217           }
4832 05 Jun 18 olle 218         }
4832 05 Jun 18 olle 219         jsonCase.put("dna", jsonDna);
4832 05 Jun 18 olle 220
4832 05 Jun 18 olle 221         // Load 'RNA' annotations
4832 05 Jun 18 olle 222         JSONArray jsonRna = new JSONArray();
4832 05 Jun 18 olle 223         if (rnaTubes != null && rnaTubes.size() > 0)
4832 05 Jun 18 olle 224         {
4832 05 Jun 18 olle 225           for (Rna r : rnaTubes)
4832 05 Jun 18 olle 226           {
4832 05 Jun 18 olle 227             Extract e = r.getExtract();
4832 05 Jun 18 olle 228             BioMaterialEvent created = e.getCreationEvent();
4832 05 Jun 18 olle 229             r.setAnnotation("extractionDate", Meludi.CONVERTER_DATE_TO_STRING.convert(created.getEventDate()));
4832 05 Jun 18 olle 230             jsonRna.add(r.asJSONObject());
4832 05 Jun 18 olle 231           }
4832 05 Jun 18 olle 232         }
4832 05 Jun 18 olle 233         jsonCase.put("rna", jsonRna);
4832 05 Jun 18 olle 234
4958 03 Sep 18 olle 235         // Add highest blood item number
5044 19 Oct 18 olle 236         String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId());
5044 19 Oct 18 olle 237         int bloodItemNumDigits = Meludi.fetchBloodItemNumDigits(sc.getActiveProjectId());
5044 19 Oct 18 olle 238         int highestBloodItemNumber = fetchHighestItemNumber(dc, Subtype.BLOOD, bloodItemPrefix, bloodItemNumDigits);
4958 03 Sep 18 olle 239         jsonCase.put("highestBloodItemNumber", highestBloodItemNumber);
4958 03 Sep 18 olle 240
4832 05 Jun 18 olle 241         // This is what we send back to the browser
4832 05 Jun 18 olle 242         json.put("caseInfo", jsonCase);
4862 19 Jun 18 olle 243
4862 19 Jun 18 olle 244         // Load blood info
4862 19 Jun 18 olle 245         List<Blood> blood = null;
4862 19 Jun 18 olle 246         blood = Blood.findAllByCaseName(dc, caseName);
4862 19 Jun 18 olle 247     
4862 19 Jun 18 olle 248         if (blood.size() > 0) 
4862 19 Jun 18 olle 249         {
4862 19 Jun 18 olle 250           JSONArray jsonBlood = new JSONArray();
4862 19 Jun 18 olle 251           for (Blood b: blood)
4862 19 Jun 18 olle 252           {
4862 19 Jun 18 olle 253             loadBloodInfo(dc, b);
4862 19 Jun 18 olle 254             jsonBlood.add(b.asJSONObject());
4862 19 Jun 18 olle 255           }
4862 19 Jun 18 olle 256           //jsonSections.add(loadSectionInfo(sc, "blood"));
4862 19 Jun 18 olle 257           json.put("blood", jsonBlood);
4862 19 Jun 18 olle 258         }
4832 05 Jun 18 olle 259       }
4832 05 Jun 18 olle 260       
4832 05 Jun 18 olle 261       else if ("GetPatientInfo".equals(cmd))
4832 05 Jun 18 olle 262       {
4832 05 Jun 18 olle 263         /*
4832 05 Jun 18 olle 264           Load information about a single patient when given a personal number
4832 05 Jun 18 olle 265           If a patient is found we will load annotations and the cases associated 
4832 05 Jun 18 olle 266           with it. If no patient is found, we populate a new object with some
4832 05 Jun 18 olle 267           information (eg. birth date and gender) from the information we have.
4832 05 Jun 18 olle 268         */
4832 05 Jun 18 olle 269         dc = sc.newDbControl();
4832 05 Jun 18 olle 270         
4832 05 Jun 18 olle 271         // Request parameters
4832 05 Jun 18 olle 272         String pnr = req.getParameter("personalNumber");
4832 05 Jun 18 olle 273         boolean pnrIsValid = Values.getBoolean(req.getParameter("pnrIsValid"));
4832 05 Jun 18 olle 274
4832 05 Jun 18 olle 275         // Find a patient by personalNumber
4832 05 Jun 18 olle 276         Patient patient = Patient.findByPersonalNumber(dc, pnr);
4832 05 Jun 18 olle 277         JSONObject jsonPat = null;
4832 05 Jun 18 olle 278         
4832 05 Jun 18 olle 279         if (patient != null)
4832 05 Jun 18 olle 280         {
4832 05 Jun 18 olle 281           // Load patient annotations
4832 05 Jun 18 olle 282           patient.loadDefaultAnnotations(dc);
4832 05 Jun 18 olle 283
4832 05 Jun 18 olle 284           // Load cases associated with this patient
4832 05 Jun 18 olle 285           List<Case> cases = Case.findByPatient(dc, patient);
4832 05 Jun 18 olle 286           
4832 05 Jun 18 olle 287           // Load case annotations
4832 05 Jun 18 olle 288           JSONArray jsonCases = new JSONArray();
4832 05 Jun 18 olle 289           if (cases.size() > 0)
4832 05 Jun 18 olle 290           {
4832 05 Jun 18 olle 291             for (Case c : cases)
4832 05 Jun 18 olle 292             {
4832 05 Jun 18 olle 293               jsonCases.add(c.asJSONObject());
4832 05 Jun 18 olle 294             }
4832 05 Jun 18 olle 295           }
4832 05 Jun 18 olle 296           
4832 05 Jun 18 olle 297           jsonPat = patient.asJSONObject();
4832 05 Jun 18 olle 298           jsonPat.put("cases", jsonCases);
4832 05 Jun 18 olle 299
4832 05 Jun 18 olle 300         }
4832 05 Jun 18 olle 301         else
4832 05 Jun 18 olle 302         {
4832 05 Jun 18 olle 303           // No patient was found -- try to find the highest existing patient number
4832 05 Jun 18 olle 304           String patientItemPrefix = Meludi.fetchPatientItemPrefix(sc.getActiveProjectId());
4832 05 Jun 18 olle 305           jsonPat = new JSONObject();
4832 05 Jun 18 olle 306           jsonPat.put("personalNumber", pnr);
4832 05 Jun 18 olle 307           jsonPat.put("name", Patient.generateNextName(dc, patientItemPrefix, Subtype.PATIENT));
4832 05 Jun 18 olle 308           if (pnrIsValid)
4832 05 Jun 18 olle 309           {
4832 05 Jun 18 olle 310             // 'Samordningsnummer' have day-in-month + 60
4832 05 Jun 18 olle 311             int dayInMonth = Values.getInt(pnr.substring(6,8));
4832 05 Jun 18 olle 312             if (dayInMonth > 60) dayInMonth -= 60;
4832 05 Jun 18 olle 313             jsonPat.put("dateOfBirth", pnr.substring(0,4) + '-' + pnr.substring(4,6)+'-'+MD5.leftPad(Integer.toString(dayInMonth), '0', 2));
4832 05 Jun 18 olle 314             jsonPat.put("gender", Integer.parseInt(pnr.substring(10,11)) % 2 == 0 ? "F" : "M");
4832 05 Jun 18 olle 315           }
4832 05 Jun 18 olle 316         }
4832 05 Jun 18 olle 317
4832 05 Jun 18 olle 318         json.put("patientInfo", jsonPat);
4832 05 Jun 18 olle 319       }
5149 28 Nov 18 olle 320       else if ("ImportBaseLineFile".equals(cmd))
5149 28 Nov 18 olle 321       {
5149 28 Nov 18 olle 322         dc = sc.newDbControl();
5149 28 Nov 18 olle 323
5149 28 Nov 18 olle 324         String csvPath = req.getParameter("csvPath");
5149 28 Nov 18 olle 325         // Input file is placed in BASE user files directory
5149 28 Nov 18 olle 326         java.io.File userFilesDir = Application.getUserFilesDirectory();
5149 28 Nov 18 olle 327         String fileDir = userFilesDir.getAbsolutePath();
5149 28 Nov 18 olle 328         String baseFilePath = fileDir + "/" + csvPath;
5149 28 Nov 18 olle 329
5149 28 Nov 18 olle 330         // Copy contents from CSV file to JSON object
5149 28 Nov 18 olle 331         JSONArray jsonDataArray = new JSONArray();
5149 28 Nov 18 olle 332         File file = File.getByPath(dc, new Path(csvPath, Path.Type.FILE), false);
5149 28 Nov 18 olle 333         try
5149 28 Nov 18 olle 334         {
5149 28 Nov 18 olle 335           // Read and store current file contents
5149 28 Nov 18 olle 336           //List<String> lines = new ArrayList<String>();
5149 28 Nov 18 olle 337           InputStream in = file.getDownloadStream(0);
5149 28 Nov 18 olle 338           InputStreamReader ipsr = new InputStreamReader(in, "UTF-8");
5149 28 Nov 18 olle 339           BufferedReader br = new BufferedReader(ipsr);
5149 28 Nov 18 olle 340           // Read data lines
5149 28 Nov 18 olle 341           String line;
5149 28 Nov 18 olle 342           while ((line = br.readLine()) != null)
5149 28 Nov 18 olle 343           {
5149 28 Nov 18 olle 344             //System.out.println("BaseLineRegistrationServlet::doGet(): cmd = \"" + cmd + "\" line = \"" + line + "\"");
5149 28 Nov 18 olle 345             jsonDataArray.add(line);
5149 28 Nov 18 olle 346           }
5149 28 Nov 18 olle 347           br.close();
5149 28 Nov 18 olle 348           ipsr.close();
5149 28 Nov 18 olle 349           in.close();
5149 28 Nov 18 olle 350         }
5149 28 Nov 18 olle 351         catch(Exception e)
5149 28 Nov 18 olle 352         {
5149 28 Nov 18 olle 353           System.out.println(new Date() + " BaseLineRegistrationServlet::doGet(): cmd = \"" + cmd + "\"  Exception e: " + e);
5149 28 Nov 18 olle 354         }
5149 28 Nov 18 olle 355         json.put("baseLineData", jsonDataArray);
5149 28 Nov 18 olle 356       }
4958 03 Sep 18 olle 357       else if ("GetNewBloodItemName".equals(cmd))
4958 03 Sep 18 olle 358       {
4958 03 Sep 18 olle 359         dc = sc.newDbControl();
5044 19 Oct 18 olle 360         String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId());
5044 19 Oct 18 olle 361         int bloodItemNumDigits = Meludi.fetchBloodItemNumDigits(sc.getActiveProjectId());
5044 19 Oct 18 olle 362         String bloodItemName = fetchNewItemName(dc, Subtype.BLOOD, bloodItemPrefix, bloodItemNumDigits);
4958 03 Sep 18 olle 363         json.put("newBloodItemName", bloodItemName);
4958 03 Sep 18 olle 364       }
4832 05 Jun 18 olle 365       else if ("FindBloodStoragePositions".equals(cmd))
4832 05 Jun 18 olle 366       {
4832 05 Jun 18 olle 367         // Find a given number of blood storage positions.
4832 05 Jun 18 olle 368         // Boxes are of type 9x9, with rows marked A-I anc columns 1-9.
4832 05 Jun 18 olle 369         // Tubes will be placed in pairs row-wise, starting from position A1.
4832 05 Jun 18 olle 370         // It is desirable to keep a tube pair in the same row,
4832 05 Jun 18 olle 371         // so column 9 will always be empty. We need to find the
4832 05 Jun 18 olle 372         // first box of the right type that has position I7 empty.
4832 05 Jun 18 olle 373         // If no box with empty valid positions exist, a new
4832 05 Jun 18 olle 374         // box will be created.
4832 05 Jun 18 olle 375         Integer nofTubes = Values.getInt(req.getParameter("nofTubes"), 1);
4832 05 Jun 18 olle 376         String storageBoxSuffix = req.getParameter("storageBoxSuffix");
4832 05 Jun 18 olle 377         //Boolean extractsFromFirstSpecimenOnly = Values.getBoolean(req.getParameter("extractsFromFirstSpecimenOnly"), false);
4832 05 Jun 18 olle 378         int nofExtracts = nofTubes;
4832 05 Jun 18 olle 379         dc = sc.newDbControl();
4832 05 Jun 18 olle 380         
4832 05 Jun 18 olle 381         JSONArray jsonWells = new JSONArray();
4832 05 Jun 18 olle 382         Boolean fillGaps = false;
4832 05 Jun 18 olle 383         if (storageBoxSuffix.equals("_sp"))
4832 05 Jun 18 olle 384         {
4832 05 Jun 18 olle 385           // Find free wells for blood tubes
4832 05 Jun 18 olle 386           JSONArray jsonSpecWells = findFreeWells(dc, nofTubes, "_sp", fillGaps);
4832 05 Jun 18 olle 387           // Combine free well results for Specimen/DNA/RNA to JSONArray
4832 05 Jun 18 olle 388           for (int i = 0; i < nofTubes; i++)
4832 05 Jun 18 olle 389           {
4832 05 Jun 18 olle 390             // Find a free well for Specimen, except for first
4832 05 Jun 18 olle 391             JSONObject jsonSpecWell = new JSONObject();
4832 05 Jun 18 olle 392             if (i > 0)
4832 05 Jun 18 olle 393             {
4832 05 Jun 18 olle 394               if (jsonSpecWells.size() > (i-1))
4832 05 Jun 18 olle 395               {
4832 05 Jun 18 olle 396                 jsonSpecWell = (JSONObject)jsonSpecWells.get(i-1);
4832 05 Jun 18 olle 397               }              
4832 05 Jun 18 olle 398               jsonSpecWell = (JSONObject)jsonSpecWells.get(i-1);
4832 05 Jun 18 olle 399             }
4832 05 Jun 18 olle 400             // Combine free well results for Specimen/DNA/RNA to JSONArray for specimen i
4832 05 Jun 18 olle 401             jsonWells.add(jsonSpecWell);
4832 05 Jun 18 olle 402           }
4832 05 Jun 18 olle 403         }
4832 05 Jun 18 olle 404         else if (storageBoxSuffix.equals("_dna_rna"))
4832 05 Jun 18 olle 405         {
4832 05 Jun 18 olle 406           // Find a free well for DNA
4832 05 Jun 18 olle 407           JSONObject jsonDnaWell = new JSONObject();
4832 05 Jun 18 olle 408           JSONArray jsonDnaWells = findFreeWells(dc, 1, "_dna", fillGaps);
4832 05 Jun 18 olle 409           if (jsonDnaWells.size() > 0)
4832 05 Jun 18 olle 410           {
4832 05 Jun 18 olle 411             jsonDnaWell = (JSONObject)jsonDnaWells.get(0);
4832 05 Jun 18 olle 412           }
4832 05 Jun 18 olle 413           // Find a free well for RNA
4832 05 Jun 18 olle 414           JSONObject jsonRnaWell = new JSONObject();
4832 05 Jun 18 olle 415           JSONArray jsonRnaWells = findFreeWells(dc, 1, "_rna", fillGaps);
4832 05 Jun 18 olle 416           if (jsonRnaWells.size() > 0)
4832 05 Jun 18 olle 417           {
4832 05 Jun 18 olle 418             jsonRnaWell = (JSONObject)jsonRnaWells.get(0);
4832 05 Jun 18 olle 419           }
4832 05 Jun 18 olle 420           // Combine free well results for DNA and RNA to JSONArray
4832 05 Jun 18 olle 421           jsonWells.add(jsonDnaWell);
4832 05 Jun 18 olle 422           jsonWells.add(jsonRnaWell);
4832 05 Jun 18 olle 423         }
4832 05 Jun 18 olle 424         else
4832 05 Jun 18 olle 425         {
4832 05 Jun 18 olle 426           // Find free blood wells for storage
4832 05 Jun 18 olle 427           jsonWells = findFreeBloodWells(dc, nofTubes, storageBoxSuffix, fillGaps);
4832 05 Jun 18 olle 428         }
4832 05 Jun 18 olle 429         
4832 05 Jun 18 olle 430         json.put("wells", jsonWells);
4832 05 Jun 18 olle 431       }
5114 20 Nov 18 olle 432       else if ("FindStoragePositions".equals(cmd))
5114 20 Nov 18 olle 433       {
5114 20 Nov 18 olle 434         // Find a given number of storage positions. The process
5114 20 Nov 18 olle 435         // is complicated by the fact that "old" boxes still may have empty
5114 20 Nov 18 olle 436         // locations so we need to find the first box of the right type
5114 20 Nov 18 olle 437         // that has I9 empty.
5114 20 Nov 18 olle 438         Integer nofTubes = Values.getInt(req.getParameter("nofTubes"), 1);
5114 20 Nov 18 olle 439         String storageBoxSuffix = req.getParameter("storageBoxSuffix");
5114 20 Nov 18 olle 440         Boolean extractsFromFirstSpecimenOnly = Values.getBoolean(req.getParameter("extractsFromFirstSpecimenOnly"), false);
5114 20 Nov 18 olle 441         int nofExtracts = nofTubes;
5114 20 Nov 18 olle 442         if (extractsFromFirstSpecimenOnly)
5114 20 Nov 18 olle 443         {
5114 20 Nov 18 olle 444           nofExtracts = 1;
5114 20 Nov 18 olle 445         }
5114 20 Nov 18 olle 446 //System.out.println("BaseLineRegistrationServlet::doGet(): cmd = \"" + cmd + "\" nofTubes = " + nofTubes + " nofExtracts = " + nofExtracts + " storageBoxSuffix = \"" + storageBoxSuffix + "\"");
5114 20 Nov 18 olle 447         dc = sc.newDbControl();
5114 20 Nov 18 olle 448         
5114 20 Nov 18 olle 449         JSONArray jsonWells = new JSONArray();
5114 20 Nov 18 olle 450         Boolean fillGaps = false;
5114 20 Nov 18 olle 451         if (storageBoxSuffix.equals("_sp"))
5114 20 Nov 18 olle 452         {
5114 20 Nov 18 olle 453 /*
5114 20 Nov 18 olle 454           // Find free wells for specimen
5114 20 Nov 18 olle 455           JSONArray jsonSpecWells = findFreeWells(dc, nofTubes, "_sp", fillGaps);
5114 20 Nov 18 olle 456 */
5114 20 Nov 18 olle 457           // Find free wells for DNA extracts from specimen
5114 20 Nov 18 olle 458           JSONArray jsonDnaWells = findFreeWells(dc, nofExtracts, "_dna", fillGaps);
5114 20 Nov 18 olle 459           // Find free wells for RNA extracts from specimen
5114 20 Nov 18 olle 460           JSONArray jsonRnaWells = findFreeWells(dc, nofExtracts, "_rna", fillGaps);
5114 20 Nov 18 olle 461           // Combine free well results for Specimen/DNA/RNA to JSONArray
5114 20 Nov 18 olle 462           for (int i = 0; i < nofTubes; i++)
5114 20 Nov 18 olle 463           {
5114 20 Nov 18 olle 464 /*
5114 20 Nov 18 olle 465             // Find a free well for Specimen, except for first
5114 20 Nov 18 olle 466             JSONObject jsonSpecWell = new JSONObject();
5114 20 Nov 18 olle 467             if (i > 0)
5114 20 Nov 18 olle 468             {
5114 20 Nov 18 olle 469               if (jsonSpecWells.size() > (i-1))
5114 20 Nov 18 olle 470               {
5114 20 Nov 18 olle 471                 jsonSpecWell = (JSONObject)jsonSpecWells.get(i-1);
5114 20 Nov 18 olle 472               }              
5114 20 Nov 18 olle 473               jsonSpecWell = (JSONObject)jsonSpecWells.get(i-1);
5114 20 Nov 18 olle 474             }
5114 20 Nov 18 olle 475 */
5114 20 Nov 18 olle 476             // Find a free well for DNA
5114 20 Nov 18 olle 477             JSONObject jsonDnaWell = new JSONObject();
5114 20 Nov 18 olle 478             if (jsonDnaWells.size() > i)
5114 20 Nov 18 olle 479             {
5114 20 Nov 18 olle 480               jsonDnaWell = (JSONObject)jsonDnaWells.get(i);
5114 20 Nov 18 olle 481             }
5114 20 Nov 18 olle 482             // Find a free well for RNA
5114 20 Nov 18 olle 483             JSONObject jsonRnaWell = new JSONObject();
5114 20 Nov 18 olle 484             if (jsonRnaWells.size() > i)
5114 20 Nov 18 olle 485             {
5114 20 Nov 18 olle 486               jsonRnaWell = (JSONObject)jsonRnaWells.get(i);
5114 20 Nov 18 olle 487             }
5114 20 Nov 18 olle 488             // Combine free well results for Specimen/DNA/RNA to JSONArray for specimen i
5114 20 Nov 18 olle 489 /*
5114 20 Nov 18 olle 490             jsonWells.add(jsonSpecWell);
5114 20 Nov 18 olle 491 */
5114 20 Nov 18 olle 492             jsonWells.add(jsonDnaWell);
5114 20 Nov 18 olle 493             jsonWells.add(jsonRnaWell);
5114 20 Nov 18 olle 494           }
5114 20 Nov 18 olle 495         }
5114 20 Nov 18 olle 496         else if (storageBoxSuffix.equals("_dna_rna"))
5114 20 Nov 18 olle 497         {
5114 20 Nov 18 olle 498           // Find a free well for DNA
5114 20 Nov 18 olle 499           JSONObject jsonDnaWell = new JSONObject();
5114 20 Nov 18 olle 500           JSONArray jsonDnaWells = findFreeWells(dc, 1, "_dna", fillGaps);
5114 20 Nov 18 olle 501           if (jsonDnaWells.size() > 0)
5114 20 Nov 18 olle 502           {
5114 20 Nov 18 olle 503             jsonDnaWell = (JSONObject)jsonDnaWells.get(0);
5114 20 Nov 18 olle 504           }
5114 20 Nov 18 olle 505           // Find a free well for RNA
5114 20 Nov 18 olle 506           JSONObject jsonRnaWell = new JSONObject();
5114 20 Nov 18 olle 507           JSONArray jsonRnaWells = findFreeWells(dc, 1, "_rna", fillGaps);
5114 20 Nov 18 olle 508           if (jsonRnaWells.size() > 0)
5114 20 Nov 18 olle 509           {
5114 20 Nov 18 olle 510             jsonRnaWell = (JSONObject)jsonRnaWells.get(0);
5114 20 Nov 18 olle 511           }
5114 20 Nov 18 olle 512           // Combine free well results for DNA and RNA to JSONArray
5114 20 Nov 18 olle 513           jsonWells.add(jsonDnaWell);
5114 20 Nov 18 olle 514           jsonWells.add(jsonRnaWell);
5114 20 Nov 18 olle 515         }
5114 20 Nov 18 olle 516         else
5114 20 Nov 18 olle 517         {
5114 20 Nov 18 olle 518           // Find free wells for storage
5114 20 Nov 18 olle 519           jsonWells = findFreeWells(dc, nofTubes, storageBoxSuffix, fillGaps);
5114 20 Nov 18 olle 520         }
5114 20 Nov 18 olle 521         
5114 20 Nov 18 olle 522         json.put("wells", jsonWells);
5114 20 Nov 18 olle 523
5114 20 Nov 18 olle 524         // **************************************** //
5119 21 Nov 18 olle 525         // Find H&E glass box name[s] and positions in box[es]
5114 20 Nov 18 olle 526         String platePrefix = Meludi.fetchStorageBoxPrefix(dc.getSessionControl().getActiveProjectId());
5114 20 Nov 18 olle 527         Integer plateNumDigits = Meludi.fetchStorageBoxNumDigits(dc.getSessionControl().getActiveProjectId());
5114 20 Nov 18 olle 528         String heGlassBoxSuffix = "_he";
5114 20 Nov 18 olle 529         // Find last used HeGlass position
5114 20 Nov 18 olle 530         JSONArray jsonHeGlassArray = new JSONArray();
5119 21 Nov 18 olle 531         String heGlassBoxName = "";
5114 20 Nov 18 olle 532         int heGlassFirstBoxIndex = 0;
5114 20 Nov 18 olle 533         int heGlassFirstBoxPos = 0;
5114 20 Nov 18 olle 534         int heGlassBoxSize = 100;
5114 20 Nov 18 olle 535         int heGlassNofPosNeeded = 2*nofTubes;
5114 20 Nov 18 olle 536         ItemQuery<BioPlate> query = BioPlate.getQuery();
5114 20 Nov 18 olle 537         query.include(Meludi.INCLUDE_IN_CURRENT_PROJECT);
5114 20 Nov 18 olle 538         BioplateType.HE_GLASS.addFilter(dc, query, true);
5114 20 Nov 18 olle 539         query.order(Orders.desc(Hql.property("id")));
5114 20 Nov 18 olle 540         query.setMaxResults(1);
5114 20 Nov 18 olle 541         
5114 20 Nov 18 olle 542         List<BioPlate> result = query.list(dc);
5119 21 Nov 18 olle 543         BioPlate heGlass = null;
5114 20 Nov 18 olle 544         if (result.size() == 1)
5114 20 Nov 18 olle 545         {
5119 21 Nov 18 olle 546           heGlass = result.get(0);
5114 20 Nov 18 olle 547         }
5114 20 Nov 18 olle 548         else
5114 20 Nov 18 olle 549         {
5114 20 Nov 18 olle 550           // Create new H&E glass bioplate
5114 20 Nov 18 olle 551           int plateNumber = 1;
5119 21 Nov 18 olle 552           heGlass = createStorageBox(dc, platePrefix, plateNumDigits, heGlassBoxSuffix, plateNumber);
5119 21 Nov 18 olle 553           // Store H&E glass box name as "Tray" parameter instead of as "Name"
5119 21 Nov 18 olle 554           heGlass.setTray(heGlass.getName());
5121 21 Nov 18 olle 555           heGlass.setPosition("0");
5114 20 Nov 18 olle 556         }
5114 20 Nov 18 olle 557
5119 21 Nov 18 olle 558 //System.out.println("BaseLineRegistrationServlet::doGet(): cmd = \"" + cmd + "\" (1) result.size() = " + result.size() + " heGlass.getName() = " + heGlass.getName() + " heGlass.getTray() = " + heGlass.getTray() + " heGlass.getPosition() = " + heGlass.getPosition());
5119 21 Nov 18 olle 559         if (heGlass.getTray() != null && heGlass.getPosition() != null)
5114 20 Nov 18 olle 560         {
5119 21 Nov 18 olle 561           //heGlassBoxName = heGlassBox.getName();
5119 21 Nov 18 olle 562           heGlassBoxName = heGlass.getTray();
5119 21 Nov 18 olle 563           heGlassFirstBoxPos = Values.getInt(heGlass.getPosition());
5114 20 Nov 18 olle 564           int heGlassBoxPos = heGlassFirstBoxPos + 1;
5114 20 Nov 18 olle 565           while (heGlassNofPosNeeded > 0 && heGlassBoxPos <= 100)
5114 20 Nov 18 olle 566           {
5114 20 Nov 18 olle 567             JSONObject jsonHeGlass = new JSONObject();
5119 21 Nov 18 olle 568             jsonHeGlass.put("storageBox", heGlassBoxName);
5114 20 Nov 18 olle 569             jsonHeGlass.put("position", heGlassBoxPos);
5114 20 Nov 18 olle 570             jsonHeGlassArray.add(jsonHeGlass);
5114 20 Nov 18 olle 571             heGlassNofPosNeeded--;
5114 20 Nov 18 olle 572             heGlassBoxPos++;
5119 21 Nov 18 olle 573             // Check if box is full and new box needed
5119 21 Nov 18 olle 574             if (heGlassNofPosNeeded > 0 && heGlassBoxPos > 100)
5119 21 Nov 18 olle 575             {
5119 21 Nov 18 olle 576               // Remove plate prefix
5119 21 Nov 18 olle 577               String numString = heGlassBoxName.substring(platePrefix.length());
5119 21 Nov 18 olle 578               // Remove plate suffix
5119 21 Nov 18 olle 579               numString = numString.substring(0, plateNumDigits);
5119 21 Nov 18 olle 580               // Remove initial zeroes
5119 21 Nov 18 olle 581               while (numString.startsWith("0"))
5119 21 Nov 18 olle 582               {
5119 21 Nov 18 olle 583                 // Remove initial zero
5119 21 Nov 18 olle 584                 numString = numString.substring(1);
5119 21 Nov 18 olle 585               }
5119 21 Nov 18 olle 586               // Get plate number as integer
5119 21 Nov 18 olle 587               int num = Values.getInt(numString);
5119 21 Nov 18 olle 588               // Get new plate number as integer
5119 21 Nov 18 olle 589               num = num + 1;
5119 21 Nov 18 olle 590               numString = "" + num;
5119 21 Nov 18 olle 591               while (numString.length() < plateNumDigits)
5119 21 Nov 18 olle 592               {
5119 21 Nov 18 olle 593                 // Add initial zero
5119 21 Nov 18 olle 594                 numString = "0" + numString;
5119 21 Nov 18 olle 595               }
5119 21 Nov 18 olle 596               // Get new plate name by adding prefix and suffix
5119 21 Nov 18 olle 597               heGlassBoxName = platePrefix + numString + heGlassBoxSuffix;
5119 21 Nov 18 olle 598               // Reset box position to 1
5119 21 Nov 18 olle 599               heGlassBoxPos = 1;
5119 21 Nov 18 olle 600             }
5114 20 Nov 18 olle 601           }
5114 20 Nov 18 olle 602         }
5119 21 Nov 18 olle 603 //System.out.println("BaseLineRegistrationServlet::doGet(): cmd = \"" + cmd + "\" (2) jsonHeGlassArray = " + jsonHeGlassArray);
5114 20 Nov 18 olle 604         json.put("heglass", jsonHeGlassArray);
5114 20 Nov 18 olle 605         
5114 20 Nov 18 olle 606         AnnotationType ihc = Annotationtype.IHC.get(dc);
5114 20 Nov 18 olle 607         JSONArray jsonIhc = new JSONArray();
5114 20 Nov 18 olle 608         jsonIhc.addAll(ihc.getValues());
5114 20 Nov 18 olle 609         json.put("ihc", jsonIhc);
5114 20 Nov 18 olle 610       }
5114 20 Nov 18 olle 611       else if ("ValidateWell".equals(cmd))
5114 20 Nov 18 olle 612       {
5114 20 Nov 18 olle 613         dc = sc.newDbControl();
5114 20 Nov 18 olle 614         String box = Values.getStringOrNull(req.getParameter("box"));
5114 20 Nov 18 olle 615         
5114 20 Nov 18 olle 616         String msg = null;
5114 20 Nov 18 olle 617         StoragePlate plate = StoragePlate.findByName(dc, box);
5114 20 Nov 18 olle 618         BioPlate bioPlate = null;
5114 20 Nov 18 olle 619         if (plate != null)
5114 20 Nov 18 olle 620         {
5114 20 Nov 18 olle 621           bioPlate = plate.getBioPlate();
5114 20 Nov 18 olle 622         }
5114 20 Nov 18 olle 623         else
5114 20 Nov 18 olle 624         {
5114 20 Nov 18 olle 625           bioPlate = createStorageBox(dc, box);
5114 20 Nov 18 olle 626           if (bioPlate == null)
5114 20 Nov 18 olle 627           {
5114 20 Nov 18 olle 628             msg = "Can't find or create storage box with name '" + box + "'";
5114 20 Nov 18 olle 629             json.put("box", 1);
5114 20 Nov 18 olle 630           }
5114 20 Nov 18 olle 631         }
5114 20 Nov 18 olle 632         
5114 20 Nov 18 olle 633         if (msg == null)
5114 20 Nov 18 olle 634         {
5114 20 Nov 18 olle 635           int rows = bioPlate.getRows();
5114 20 Nov 18 olle 636           int columns = bioPlate.getColumns();
5114 20 Nov 18 olle 637           
5114 20 Nov 18 olle 638           WellCoordinateFormatter wcfRow = new WellCoordinateFormatter(true);        
5114 20 Nov 18 olle 639           String rowString = req.getParameter("row");
5114 20 Nov 18 olle 640           int rowNumber = wcfRow.parseString(rowString);
5114 20 Nov 18 olle 641                   
5114 20 Nov 18 olle 642           Integer columnIndex = Integer.parseInt(req.getParameter("column")) - 1;
5114 20 Nov 18 olle 643           WellCoordinateFormatter wcfColumn = new WellCoordinateFormatter(false);
5114 20 Nov 18 olle 644           
5114 20 Nov 18 olle 645           if (rowNumber < 1 || rowNumber > rows) 
5114 20 Nov 18 olle 646           {
5114 20 Nov 18 olle 647             msg = "The row must be between "+ wcfRow.format(0) +" and " + wcfRow.format(rows-1);
5114 20 Nov 18 olle 648           }
5114 20 Nov 18 olle 649           else if (columnIndex < 0 || columnIndex > columns)
5114 20 Nov 18 olle 650           {
5114 20 Nov 18 olle 651             msg = "The column must be between " +  1 + " and " + columns;
5114 20 Nov 18 olle 652           }
5114 20 Nov 18 olle 653           else if (bioPlate.getBioWell(rowNumber-1, columnIndex) != null && !bioPlate.getBioWell(rowNumber-1, columnIndex).isEmpty() )
5114 20 Nov 18 olle 654           {
5114 20 Nov 18 olle 655             msg = "Location '"+rowString+wcfColumn.format(columnIndex)+"' is already used.";
5114 20 Nov 18 olle 656           }
5114 20 Nov 18 olle 657           json.put("position", 1);
5114 20 Nov 18 olle 658         }
5114 20 Nov 18 olle 659         json.put("message", msg);
5114 20 Nov 18 olle 660       }
5114 20 Nov 18 olle 661     }
4832 05 Jun 18 olle 662     catch (Throwable t)
4832 05 Jun 18 olle 663     {
4832 05 Jun 18 olle 664       t.printStackTrace();
4832 05 Jun 18 olle 665       json.clear();
4832 05 Jun 18 olle 666       json.put("status", "error");
4832 05 Jun 18 olle 667       json.put("message", t.getMessage());
4832 05 Jun 18 olle 668       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
4832 05 Jun 18 olle 669     }
4832 05 Jun 18 olle 670     finally
4832 05 Jun 18 olle 671     {
4832 05 Jun 18 olle 672       if (dc != null) dc.close();
4832 05 Jun 18 olle 673       json.writeJSONString(resp.getWriter());
4832 05 Jun 18 olle 674     }
4832 05 Jun 18 olle 675   }
4832 05 Jun 18 olle 676
4862 19 Jun 18 olle 677   private void loadBloodInfo(DbControl dc, Blood blood)
4862 19 Jun 18 olle 678   {
4862 19 Jun 18 olle 679     Sample s = blood.getItem();
4862 19 Jun 18 olle 680     
4862 19 Jun 18 olle 681     blood.loadBioPlateLocation();
4862 19 Jun 18 olle 682     blood.setAnnotation("registrationDate", Meludi.CONVERTER_DATE_TO_STRING.convert(s.getEntryDate()));
4862 19 Jun 18 olle 683     blood.setAnnotation("editable", s.hasPermission(Permission.WRITE));
4862 19 Jun 18 olle 684     
4862 19 Jun 18 olle 685     Consent.loadConsentAnnotations(dc, blood);
4862 19 Jun 18 olle 686     //blood.loadAnnotations(dc, "samplingDate", Annotationtype.BLOOD_SAMPLING_DATETIME, Meludi.CONVERTER_DATETIME_TO_STRING);
4862 19 Jun 18 olle 687     blood.loadAnnotations(dc, "samplingDate", Annotationtype.SAMPLING_DATE, Meludi.CONVERTER_DATE_TO_STRING);
4862 19 Jun 18 olle 688     //blood.loadAnnotations(dc, "freezerDate", Annotationtype.BLOOD_FREEZER_DATETIME, Meludi.CONVERTER_DATETIME_TO_STRING);
4862 19 Jun 18 olle 689     //blood.loadAnnotations(dc, "serum", Annotationtype.BLOOD_SERUM, null);
4862 19 Jun 18 olle 690     //blood.loadAnnotations(dc, "bloodSample", Annotationtype.BLOOD_SAMPLE, null);
4862 19 Jun 18 olle 691     blood.setAnnotation("comment", s.getDescription());
4862 19 Jun 18 olle 692   }
4862 19 Jun 18 olle 693   
4832 05 Jun 18 olle 694   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 695   List<BioWell> findFreeWells2(DbControl dc, Integer nofTubes, String storageBoxSuffix)
4832 05 Jun 18 olle 696   {
4832 05 Jun 18 olle 697     String queryString = "%";
4832 05 Jun 18 olle 698     Integer nofWellsNeeded = 0;
4832 05 Jun 18 olle 699     if (storageBoxSuffix != null)
4832 05 Jun 18 olle 700     {
4832 05 Jun 18 olle 701       queryString = "%" + storageBoxSuffix;
4832 05 Jun 18 olle 702       if (storageBoxSuffix.equals("_sp"))
4832 05 Jun 18 olle 703       {
4832 05 Jun 18 olle 704         // No storage space  is allocated for first specimen,
4832 05 Jun 18 olle 705         // since all amount is expected to be used for analysis
4832 05 Jun 18 olle 706         if (nofTubes != null && nofTubes > 0)
4832 05 Jun 18 olle 707         {
4832 05 Jun 18 olle 708           nofWellsNeeded = nofTubes - 1;
4832 05 Jun 18 olle 709         }
4832 05 Jun 18 olle 710       }
4832 05 Jun 18 olle 711       else
4832 05 Jun 18 olle 712       {
4832 05 Jun 18 olle 713         // All amount is stored
4832 05 Jun 18 olle 714         nofWellsNeeded = nofTubes;
4832 05 Jun 18 olle 715       }
4832 05 Jun 18 olle 716     }
4832 05 Jun 18 olle 717
4832 05 Jun 18 olle 718     ItemQuery<BioPlate> boxQuery = BioPlate.getQuery();
4832 05 Jun 18 olle 719     boxQuery.join(Hql.innerJoin("bioWells", "bw"));
4832 05 Jun 18 olle 720     boxQuery.join(Hql.leftJoin("bw", "bioMaterial", "bm", null, false));
4832 05 Jun 18 olle 721     boxQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.string(queryString)));
4832 05 Jun 18 olle 722     boxQuery.restrict(Restrictions.eq(Hql.property("bw", "row"), Expressions.integer(8)));
4832 05 Jun 18 olle 723     boxQuery.restrict(Restrictions.eq(Hql.property("bw", "column"), Expressions.integer(8)));
4832 05 Jun 18 olle 724     boxQuery.restrict(Restrictions.eq(Hql.alias("bm"), null));
4832 05 Jun 18 olle 725     
4832 05 Jun 18 olle 726     boxQuery.order(Orders.asc(Hql.property("name")));
4832 05 Jun 18 olle 727     List<BioPlate> boxes = boxQuery.list(dc);
4832 05 Jun 18 olle 728     
4832 05 Jun 18 olle 729     List<BioWell> freeWells = new ArrayList<BioWell>();
4832 05 Jun 18 olle 730     if (nofWellsNeeded > 0)
4832 05 Jun 18 olle 731     {
4832 05 Jun 18 olle 732       for (BioPlate box : boxes)
4832 05 Jun 18 olle 733       {
4832 05 Jun 18 olle 734         BioWell free = getFirstFreeWell(box);
4832 05 Jun 18 olle 735         while (free != null)
4832 05 Jun 18 olle 736         {
4832 05 Jun 18 olle 737           freeWells.add(free);
4832 05 Jun 18 olle 738           if (freeWells.size() == nofWellsNeeded) break;
4832 05 Jun 18 olle 739           free = getNextFreeWell(free);
4832 05 Jun 18 olle 740         }
4832 05 Jun 18 olle 741         if (freeWells.size() == nofWellsNeeded) break;
4832 05 Jun 18 olle 742       }
4832 05 Jun 18 olle 743     }
4832 05 Jun 18 olle 744     return freeWells;
4832 05 Jun 18 olle 745   }
4832 05 Jun 18 olle 746
4832 05 Jun 18 olle 747   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 748   private JSONArray findFreeWells(DbControl dc, Integer nofTubes, String storageBoxSuffix)
4832 05 Jun 18 olle 749   {
4832 05 Jun 18 olle 750     Boolean fillGaps = true;
4832 05 Jun 18 olle 751     JSONArray jsonWells = findFreeWells(dc, nofTubes, storageBoxSuffix, fillGaps);
4832 05 Jun 18 olle 752     return jsonWells;
4832 05 Jun 18 olle 753   }
4832 05 Jun 18 olle 754
4832 05 Jun 18 olle 755   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 756   private JSONArray findFreeBloodWells(DbControl dc, Integer nofTubes, String storageBoxSuffix, Boolean fillGaps)
4832 05 Jun 18 olle 757   {
5172 03 Dec 18 olle 758     String platePrefix = Meludi.fetchStorageBoxPrefix(dc.getSessionControl().getActiveProjectId());
5172 03 Dec 18 olle 759     Integer plateNumDigits = Meludi.fetchStorageBoxNumDigits(dc.getSessionControl().getActiveProjectId());
4832 05 Jun 18 olle 760     // Default is to fill gaps in plates
4832 05 Jun 18 olle 761     if (fillGaps == null)
4832 05 Jun 18 olle 762     {
4832 05 Jun 18 olle 763       fillGaps = true;
4832 05 Jun 18 olle 764     }
4832 05 Jun 18 olle 765     String queryString = platePrefix + "%";
4832 05 Jun 18 olle 766     Integer nofWellsNeeded = 0;
4832 05 Jun 18 olle 767     if (storageBoxSuffix != null)
4832 05 Jun 18 olle 768     {
4832 05 Jun 18 olle 769       queryString = platePrefix + "%" + storageBoxSuffix;
4832 05 Jun 18 olle 770       // All amount is stored
4832 05 Jun 18 olle 771       nofWellsNeeded = nofTubes;
4832 05 Jun 18 olle 772     }
4832 05 Jun 18 olle 773
4832 05 Jun 18 olle 774     // Get all bioplates of the desired type, in ascending order by name
4832 05 Jun 18 olle 775     ItemQuery<BioPlate> boxQuery = BioPlate.getQuery();
4832 05 Jun 18 olle 776 /*
4832 05 Jun 18 olle 777     boxQuery.join(Hql.innerJoin("bioWells", "bw"));
4832 05 Jun 18 olle 778     boxQuery.join(Hql.leftJoin("bw", "bioMaterial", "bm", null, false));
4832 05 Jun 18 olle 779 */
4832 05 Jun 18 olle 780     boxQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.string(queryString)));
4832 05 Jun 18 olle 781 /*
4832 05 Jun 18 olle 782     boxQuery.restrict(Restrictions.eq(Hql.property("bw", "row"), Expressions.integer(8)));
4832 05 Jun 18 olle 783     boxQuery.restrict(Restrictions.eq(Hql.property("bw", "column"), Expressions.integer(8)));
4832 05 Jun 18 olle 784     boxQuery.restrict(Restrictions.eq(Hql.alias("bm"), null));
4832 05 Jun 18 olle 785 */
4832 05 Jun 18 olle 786     
4832 05 Jun 18 olle 787     boxQuery.order(Orders.asc(Hql.property("name")));
4832 05 Jun 18 olle 788     List<BioPlate> boxes = boxQuery.list(dc);
4832 05 Jun 18 olle 789     
4832 05 Jun 18 olle 790     // Find first box with free well to fill, according to scheme
4832 05 Jun 18 olle 791     int firstBoxIndex = -1;
4832 05 Jun 18 olle 792     if (fillGaps)
4832 05 Jun 18 olle 793     {      
4832 05 Jun 18 olle 794       // Find first box with a free well
4832 05 Jun 18 olle 795       // by checking forwards from first box
4832 05 Jun 18 olle 796       for (int i = 0; i < boxes.size() && firstBoxIndex < 0; i++)
4832 05 Jun 18 olle 797       {
4832 05 Jun 18 olle 798         BioPlate box = (BioPlate) boxes.get(i);
4832 05 Jun 18 olle 799         BioWell firstFreeWell = getFirstFreeWell(box);
4832 05 Jun 18 olle 800         if (firstFreeWell != null)
4832 05 Jun 18 olle 801         {
4832 05 Jun 18 olle 802           // Valid free well found in box
4832 05 Jun 18 olle 803           firstBoxIndex = i;
4832 05 Jun 18 olle 804         }
4832 05 Jun 18 olle 805       }
4832 05 Jun 18 olle 806     }
4832 05 Jun 18 olle 807     else
4832 05 Jun 18 olle 808     {      
4832 05 Jun 18 olle 809       // Find highest box with at least one well filled
4832 05 Jun 18 olle 810       // by checking backwards from highest box
4832 05 Jun 18 olle 811       for (int i = boxes.size() - 1; i >= 0 && firstBoxIndex < 0; i--)
4832 05 Jun 18 olle 812       {
4832 05 Jun 18 olle 813         BioPlate box = (BioPlate) boxes.get(i);
4832 05 Jun 18 olle 814         BioWell firstFilledWell = getFirstFilledWell(box);
4832 05 Jun 18 olle 815         // Skip to next lower box if this box is empty
4832 05 Jun 18 olle 816         if (firstFilledWell == null)
4832 05 Jun 18 olle 817         {
4832 05 Jun 18 olle 818           if (i > 0)
4832 05 Jun 18 olle 819           {
4832 05 Jun 18 olle 820             // Not first box, skip to next lower box
4832 05 Jun 18 olle 821             continue;
4832 05 Jun 18 olle 822           }
4832 05 Jun 18 olle 823           else
4832 05 Jun 18 olle 824           {
4832 05 Jun 18 olle 825             // First box, all boxes empty, select first box
4832 05 Jun 18 olle 826             firstBoxIndex = i;
4832 05 Jun 18 olle 827           }
4832 05 Jun 18 olle 828         }
4832 05 Jun 18 olle 829         // Find first free well followed by only free wells
4832 05 Jun 18 olle 830         BioWell firstFreeWell = getFirstFreeWellWithoutFillingGaps(box);
4832 05 Jun 18 olle 831         if (firstFreeWell != null)
4832 05 Jun 18 olle 832         {
4832 05 Jun 18 olle 833           // Valid free well found in box
4832 05 Jun 18 olle 834           firstBoxIndex = i;
4832 05 Jun 18 olle 835         }
4832 05 Jun 18 olle 836         else
4832 05 Jun 18 olle 837         {
4832 05 Jun 18 olle 838           // No valid free well found
4832 05 Jun 18 olle 839           // If not highest box, select next higher box, which is empty
4832 05 Jun 18 olle 840           if (i < (boxes.size() - 1))
4832 05 Jun 18 olle 841           {
4832 05 Jun 18 olle 842             // First empty box following highest box without valid free well
4832 05 Jun 18 olle 843             firstBoxIndex = i + 1;
4832 05 Jun 18 olle 844           }
4832 05 Jun 18 olle 845         }
4832 05 Jun 18 olle 846       }
4832 05 Jun 18 olle 847     }
4832 05 Jun 18 olle 848     
4832 05 Jun 18 olle 849     JSONArray jsonWells = new JSONArray();
4832 05 Jun 18 olle 850     if (firstBoxIndex >= 0 && nofWellsNeeded > 0)
4832 05 Jun 18 olle 851     {
4832 05 Jun 18 olle 852       for (int i = firstBoxIndex; i < boxes.size(); i++)
4832 05 Jun 18 olle 853       {
4832 05 Jun 18 olle 854         BioPlate box = (BioPlate) boxes.get(i);
4832 05 Jun 18 olle 855         // Get free wells
4832 05 Jun 18 olle 856         jsonWells = updateJsonWells(jsonWells, box, nofWellsNeeded, fillGaps);
4832 05 Jun 18 olle 857         if (jsonWells.size() == nofWellsNeeded) break;
4832 05 Jun 18 olle 858       }
4832 05 Jun 18 olle 859     }
4832 05 Jun 18 olle 860     // Check if more boxes needed
4832 05 Jun 18 olle 861     int plateNumber = 0;
4832 05 Jun 18 olle 862     if (boxes != null)
4832 05 Jun 18 olle 863     {
4832 05 Jun 18 olle 864       plateNumber = boxes.size();
4832 05 Jun 18 olle 865     }
4832 05 Jun 18 olle 866     while (jsonWells.size() < nofWellsNeeded)
4832 05 Jun 18 olle 867     {
4832 05 Jun 18 olle 868       // Get new storage plate
4832 05 Jun 18 olle 869       plateNumber++;
4832 05 Jun 18 olle 870       BioPlate box = createStorageBox(dc, platePrefix, plateNumDigits, storageBoxSuffix, plateNumber);
4832 05 Jun 18 olle 871       // Get free wells
4832 05 Jun 18 olle 872       jsonWells = updateJsonWells(jsonWells, box, nofWellsNeeded, fillGaps);
4832 05 Jun 18 olle 873     }
4832 05 Jun 18 olle 874     return jsonWells;
4832 05 Jun 18 olle 875   }
4832 05 Jun 18 olle 876
4832 05 Jun 18 olle 877   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 878   private JSONArray findFreeWells(DbControl dc, Integer nofTubes, String storageBoxSuffix, Boolean fillGaps)
4832 05 Jun 18 olle 879   {
4832 05 Jun 18 olle 880     String platePrefix = Meludi.fetchStorageBoxPrefix(dc.getSessionControl().getActiveProjectId());
4832 05 Jun 18 olle 881     Integer plateNumDigits = Meludi.fetchStorageBoxNumDigits(dc.getSessionControl().getActiveProjectId());
4832 05 Jun 18 olle 882     // Default is to fill gaps in plates
4832 05 Jun 18 olle 883     if (fillGaps == null)
4832 05 Jun 18 olle 884     {
4832 05 Jun 18 olle 885       fillGaps = true;
4832 05 Jun 18 olle 886     }
4832 05 Jun 18 olle 887     String queryString = platePrefix + "%";
4832 05 Jun 18 olle 888     Integer nofWellsNeeded = 0;
4832 05 Jun 18 olle 889     if (storageBoxSuffix != null)
4832 05 Jun 18 olle 890     {
4832 05 Jun 18 olle 891       queryString = platePrefix + "%" + storageBoxSuffix;
4832 05 Jun 18 olle 892       if (storageBoxSuffix.equals("_sp"))
4832 05 Jun 18 olle 893       {
4832 05 Jun 18 olle 894         // No storage space  is allocated for first specimen,
4832 05 Jun 18 olle 895         // since all amount is expected to be used for analysis
4832 05 Jun 18 olle 896         if (nofTubes != null && nofTubes > 0)
4832 05 Jun 18 olle 897         {
4832 05 Jun 18 olle 898           nofWellsNeeded = nofTubes - 1;
4832 05 Jun 18 olle 899         }
4832 05 Jun 18 olle 900       }
4832 05 Jun 18 olle 901       else
4832 05 Jun 18 olle 902       {
4832 05 Jun 18 olle 903         // All amount is stored
4832 05 Jun 18 olle 904         nofWellsNeeded = nofTubes;
4832 05 Jun 18 olle 905       }
4832 05 Jun 18 olle 906     }
4832 05 Jun 18 olle 907
4832 05 Jun 18 olle 908     // Get all bioplates of the desired type, in ascending order by name
4832 05 Jun 18 olle 909     ItemQuery<BioPlate> boxQuery = BioPlate.getQuery();
4832 05 Jun 18 olle 910 /*
4832 05 Jun 18 olle 911     boxQuery.join(Hql.innerJoin("bioWells", "bw"));
4832 05 Jun 18 olle 912     boxQuery.join(Hql.leftJoin("bw", "bioMaterial", "bm", null, false));
4832 05 Jun 18 olle 913 */
4832 05 Jun 18 olle 914     boxQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.string(queryString)));
4832 05 Jun 18 olle 915 /*
4832 05 Jun 18 olle 916     boxQuery.restrict(Restrictions.eq(Hql.property("bw", "row"), Expressions.integer(8)));
4832 05 Jun 18 olle 917     boxQuery.restrict(Restrictions.eq(Hql.property("bw", "column"), Expressions.integer(8)));
4832 05 Jun 18 olle 918     boxQuery.restrict(Restrictions.eq(Hql.alias("bm"), null));
4832 05 Jun 18 olle 919 */
4832 05 Jun 18 olle 920     
4832 05 Jun 18 olle 921     boxQuery.order(Orders.asc(Hql.property("name")));
4832 05 Jun 18 olle 922     List<BioPlate> boxes = boxQuery.list(dc);
4832 05 Jun 18 olle 923     
4832 05 Jun 18 olle 924     // Find first box with free well to fill, according to scheme
4832 05 Jun 18 olle 925     int firstBoxIndex = -1;
4832 05 Jun 18 olle 926     if (fillGaps)
4832 05 Jun 18 olle 927     {      
4832 05 Jun 18 olle 928       // Find first box with a free well
4832 05 Jun 18 olle 929       // by checking forwards from first box
4832 05 Jun 18 olle 930       for (int i = 0; i < boxes.size() && firstBoxIndex < 0; i++)
4832 05 Jun 18 olle 931       {
4832 05 Jun 18 olle 932         BioPlate box = (BioPlate) boxes.get(i);
4832 05 Jun 18 olle 933         BioWell firstFreeWell = getFirstFreeWell(box);
4832 05 Jun 18 olle 934         if (firstFreeWell != null)
4832 05 Jun 18 olle 935         {
4832 05 Jun 18 olle 936           // Valid free well found in box
4832 05 Jun 18 olle 937           firstBoxIndex = i;
4832 05 Jun 18 olle 938         }
4832 05 Jun 18 olle 939       }
4832 05 Jun 18 olle 940     }
4832 05 Jun 18 olle 941     else
4832 05 Jun 18 olle 942     {      
4832 05 Jun 18 olle 943       // Find highest box with at least one well filled
4832 05 Jun 18 olle 944       // by checking backwards from highest box
4832 05 Jun 18 olle 945       for (int i = boxes.size() - 1; i >= 0 && firstBoxIndex < 0; i--)
4832 05 Jun 18 olle 946       {
4832 05 Jun 18 olle 947         BioPlate box = (BioPlate) boxes.get(i);
4832 05 Jun 18 olle 948         BioWell firstFilledWell = getFirstFilledWell(box);
4832 05 Jun 18 olle 949         // Skip to next lower box if this box is empty
4832 05 Jun 18 olle 950         if (firstFilledWell == null)
4832 05 Jun 18 olle 951         {
4832 05 Jun 18 olle 952           if (i > 0)
4832 05 Jun 18 olle 953           {
4832 05 Jun 18 olle 954             // Not first box, skip to next lower box
4832 05 Jun 18 olle 955             continue;
4832 05 Jun 18 olle 956           }
4832 05 Jun 18 olle 957           else
4832 05 Jun 18 olle 958           {
4832 05 Jun 18 olle 959             // First box, all boxes empty, select first box
4832 05 Jun 18 olle 960             firstBoxIndex = i;
4832 05 Jun 18 olle 961           }
4832 05 Jun 18 olle 962         }
4832 05 Jun 18 olle 963         // Find first free well followed by only free wells
4832 05 Jun 18 olle 964         BioWell firstFreeWell = getFirstFreeWellWithoutFillingGaps(box);
4832 05 Jun 18 olle 965         if (firstFreeWell != null)
4832 05 Jun 18 olle 966         {
4832 05 Jun 18 olle 967           // Valid free well found in box
4832 05 Jun 18 olle 968           firstBoxIndex = i;
4832 05 Jun 18 olle 969         }
4832 05 Jun 18 olle 970         else
4832 05 Jun 18 olle 971         {
4832 05 Jun 18 olle 972           // No valid free well found
4832 05 Jun 18 olle 973           // If not highest box, select next higher box, which is empty
4832 05 Jun 18 olle 974           if (i < (boxes.size() - 1))
4832 05 Jun 18 olle 975           {
4832 05 Jun 18 olle 976             // First empty box following highest box without valid free well
4832 05 Jun 18 olle 977             firstBoxIndex = i + 1;
4832 05 Jun 18 olle 978           }
4832 05 Jun 18 olle 979         }
4832 05 Jun 18 olle 980       }
4832 05 Jun 18 olle 981     }
4832 05 Jun 18 olle 982     
4832 05 Jun 18 olle 983     JSONArray jsonWells = new JSONArray();
4832 05 Jun 18 olle 984     if (firstBoxIndex >= 0 && nofWellsNeeded > 0)
4832 05 Jun 18 olle 985     {
4832 05 Jun 18 olle 986       for (int i = firstBoxIndex; i < boxes.size(); i++)
4832 05 Jun 18 olle 987       {
4832 05 Jun 18 olle 988         BioPlate box = (BioPlate) boxes.get(i);
4832 05 Jun 18 olle 989         // Get free wells
4832 05 Jun 18 olle 990         jsonWells = updateJsonWells(jsonWells, box, nofWellsNeeded, fillGaps);
4832 05 Jun 18 olle 991         if (jsonWells.size() == nofWellsNeeded) break;
4832 05 Jun 18 olle 992       }
4832 05 Jun 18 olle 993     }
4832 05 Jun 18 olle 994     // Check if more boxes needed
4832 05 Jun 18 olle 995     int plateNumber = 0;
4832 05 Jun 18 olle 996     if (boxes != null)
4832 05 Jun 18 olle 997     {
4832 05 Jun 18 olle 998       plateNumber = boxes.size();
4832 05 Jun 18 olle 999     }
4832 05 Jun 18 olle 1000     while (jsonWells.size() < nofWellsNeeded)
4832 05 Jun 18 olle 1001     {
4832 05 Jun 18 olle 1002       // Get new storage plate
4832 05 Jun 18 olle 1003       plateNumber++;
4832 05 Jun 18 olle 1004       BioPlate box = createStorageBox(dc, platePrefix, plateNumDigits, storageBoxSuffix, plateNumber);
4832 05 Jun 18 olle 1005       // Get free wells
4832 05 Jun 18 olle 1006       jsonWells = updateJsonWells(jsonWells, box, nofWellsNeeded, fillGaps);
4832 05 Jun 18 olle 1007     }
4832 05 Jun 18 olle 1008     return jsonWells;
4832 05 Jun 18 olle 1009   }
4832 05 Jun 18 olle 1010
4832 05 Jun 18 olle 1011   /**
4832 05 Jun 18 olle 1012    * Updates a JSONArray with wells to use.
4832 05 Jun 18 olle 1013    * 
4832 05 Jun 18 olle 1014    * @param jsonWells JSONArray A JSONArray of wells
4832 05 Jun 18 olle 1015    * @param box BioPlate The bioplate to find wells in
4832 05 Jun 18 olle 1016    * @param nofWellsNeeded Integer Number of wells needed
4832 05 Jun 18 olle 1017    * @param fillGaps Boolean Flag indicating if gaps in the plate should be filled
4832 05 Jun 18 olle 1018    * @return JSONArray The input JSONArray updated with free wells to use
4832 05 Jun 18 olle 1019    */
4832 05 Jun 18 olle 1020   private JSONArray updateJsonWells(JSONArray jsonWells, BioPlate box, Integer nofWellsNeeded, Boolean fillGaps)
4832 05 Jun 18 olle 1021   {
4832 05 Jun 18 olle 1022     if (nofWellsNeeded == null)
4832 05 Jun 18 olle 1023     {
4832 05 Jun 18 olle 1024       nofWellsNeeded = 0;
4832 05 Jun 18 olle 1025     }
4832 05 Jun 18 olle 1026     // Default is to fill gaps in plates
4832 05 Jun 18 olle 1027     if (fillGaps == null)
4832 05 Jun 18 olle 1028     {
4832 05 Jun 18 olle 1029       fillGaps = true;
4832 05 Jun 18 olle 1030     }
4832 05 Jun 18 olle 1031     // Get free wells
4832 05 Jun 18 olle 1032     BioWell free = null;
4832 05 Jun 18 olle 1033     if (fillGaps)
4832 05 Jun 18 olle 1034     {
4832 05 Jun 18 olle 1035       free = getFirstFreeWell(box);
4832 05 Jun 18 olle 1036     }
4832 05 Jun 18 olle 1037     else
4832 05 Jun 18 olle 1038     {
4832 05 Jun 18 olle 1039       free = getFirstFreeWellWithoutFillingGaps(box);
4832 05 Jun 18 olle 1040     }
4832 05 Jun 18 olle 1041     while (free != null && jsonWells.size() < nofWellsNeeded)
4832 05 Jun 18 olle 1042     {
4832 05 Jun 18 olle 1043       jsonWells.add(JsonUtil.getBioWellAsJSON(free, true));
4832 05 Jun 18 olle 1044       free = getNextFreeWell(free);
4832 05 Jun 18 olle 1045     }
4832 05 Jun 18 olle 1046     return jsonWells;
4832 05 Jun 18 olle 1047   }
4832 05 Jun 18 olle 1048
4832 05 Jun 18 olle 1049   /**
4832 05 Jun 18 olle 1050    * Get first filled well for a bioplate.
4832 05 Jun 18 olle 1051    * 
4832 05 Jun 18 olle 1052    * @param plate BioPlate The storage plate/box to find first filled well in.
4832 05 Jun 18 olle 1053    * @return BioWell First filled well in the bioplate, or `null` if none found.
4832 05 Jun 18 olle 1054    */
4832 05 Jun 18 olle 1055   private BioWell getFirstFilledWell(BioPlate plate)
4832 05 Jun 18 olle 1056   {
4832 05 Jun 18 olle 1057     // First filled well in the plate. 
4832 05 Jun 18 olle 1058     BioWell firstFilledWell = null;    
4832 05 Jun 18 olle 1059     boolean foundNextFilled = false;          
4832 05 Jun 18 olle 1060     for (int row = 0; row < plate.getRows() && !foundNextFilled; row++)
4832 05 Jun 18 olle 1061     {
4832 05 Jun 18 olle 1062       for (int col = 0; col < plate.getColumns() && !foundNextFilled; col++)
4832 05 Jun 18 olle 1063       { 
4832 05 Jun 18 olle 1064         if (!plate.getBioWell(row, col).isEmpty())
4832 05 Jun 18 olle 1065         {
4832 05 Jun 18 olle 1066           firstFilledWell = plate.getBioWell(row, col);
4832 05 Jun 18 olle 1067           foundNextFilled = true;
4832 05 Jun 18 olle 1068         }
4832 05 Jun 18 olle 1069       }
4832 05 Jun 18 olle 1070     }    
4832 05 Jun 18 olle 1071     return firstFilledWell;
4832 05 Jun 18 olle 1072   }
4832 05 Jun 18 olle 1073   
4832 05 Jun 18 olle 1074   /**
4832 05 Jun 18 olle 1075    * Get first free well for a bioplate.
4832 05 Jun 18 olle 1076    * 
4832 05 Jun 18 olle 1077    * @param plate BioPlate The storage plate/box to find first free well in.
4832 05 Jun 18 olle 1078    * @return BioWell First free well in the bioplate, or `null` if none found.
4832 05 Jun 18 olle 1079    */
4832 05 Jun 18 olle 1080   private BioWell getFirstFreeWell(BioPlate plate)
4832 05 Jun 18 olle 1081   {
4832 05 Jun 18 olle 1082     // First free well in the plate. 
4832 05 Jun 18 olle 1083     BioWell firstFreeWell = null;
4832 05 Jun 18 olle 1084     boolean foundNextEmpty = false;          
4832 05 Jun 18 olle 1085     for (int row = 0; row < plate.getRows() && !foundNextEmpty; row++)
4832 05 Jun 18 olle 1086     {
4832 05 Jun 18 olle 1087       for (int col = 0; col < plate.getColumns() && !foundNextEmpty; col++)
4832 05 Jun 18 olle 1088       { 
4832 05 Jun 18 olle 1089         if (plate.getBioWell(row, col).isEmpty())
4832 05 Jun 18 olle 1090         {
4832 05 Jun 18 olle 1091           firstFreeWell = plate.getBioWell(row, col);
4832 05 Jun 18 olle 1092           foundNextEmpty = true;
4832 05 Jun 18 olle 1093         }
4832 05 Jun 18 olle 1094       }
4832 05 Jun 18 olle 1095     }    
4832 05 Jun 18 olle 1096     return firstFreeWell;
4832 05 Jun 18 olle 1097   }
4832 05 Jun 18 olle 1098   
4832 05 Jun 18 olle 1099   /**
4832 05 Jun 18 olle 1100    * Get first free well for a bioplate without filling gaps.
4832 05 Jun 18 olle 1101    * The well found is the first free well with only free wells
4832 05 Jun 18 olle 1102    * following until the end of the plate (lower right corner).
4832 05 Jun 18 olle 1103    * 
4832 05 Jun 18 olle 1104    * @param plate BioPlate The storage plate/box to find first free well in.
4832 05 Jun 18 olle 1105    * @return BioWell First free well in the bioplate, or `null` if none found.
4832 05 Jun 18 olle 1106    */
4832 05 Jun 18 olle 1107   private BioWell getFirstFreeWellWithoutFillingGaps(BioPlate plate)
4832 05 Jun 18 olle 1108   {
4832 05 Jun 18 olle 1109     // First free well in the plate, without filling gaps. 
4832 05 Jun 18 olle 1110     BioWell firstFreeWell = null;    
4832 05 Jun 18 olle 1111     boolean foundPreviousFilled = false;
4832 05 Jun 18 olle 1112     // Check wells backwards, starting at the lower right corner,
4832 05 Jun 18 olle 1113     // until a filled well or the first well is found.
4832 05 Jun 18 olle 1114     for (int row = plate.getRows() - 1; row >= 0 && !foundPreviousFilled; row--)
4832 05 Jun 18 olle 1115     {
4832 05 Jun 18 olle 1116       for (int col = plate.getColumns() - 1; col >= 0 && !foundPreviousFilled; col--)
4832 05 Jun 18 olle 1117       { 
4832 05 Jun 18 olle 1118         if (plate.getBioWell(row, col).isEmpty())
4832 05 Jun 18 olle 1119         {
4832 05 Jun 18 olle 1120           firstFreeWell = plate.getBioWell(row, col);
4832 05 Jun 18 olle 1121         }
4832 05 Jun 18 olle 1122         else
4832 05 Jun 18 olle 1123         {
4832 05 Jun 18 olle 1124           foundPreviousFilled = true;
4832 05 Jun 18 olle 1125         }
4832 05 Jun 18 olle 1126       }
4832 05 Jun 18 olle 1127     }    
4832 05 Jun 18 olle 1128     return firstFreeWell;
4832 05 Jun 18 olle 1129   }
4832 05 Jun 18 olle 1130   
4832 05 Jun 18 olle 1131   /**
4832 05 Jun 18 olle 1132    * Get next free well for a bioplate.
4832 05 Jun 18 olle 1133    * 
4832 05 Jun 18 olle 1134    * @param well BioWell The current well in the storage plate/box.
4832 05 Jun 18 olle 1135    * @return BioWell Next free well in the bioplate, or `null` if none found.
4832 05 Jun 18 olle 1136    */
4832 05 Jun 18 olle 1137   private BioWell getNextFreeWell(BioWell well)
4832 05 Jun 18 olle 1138   {
4832 05 Jun 18 olle 1139     // Next free well in the plate. 
4832 05 Jun 18 olle 1140     BioWell nextFreeWell = null;
4832 05 Jun 18 olle 1141     BioPlate plate = well.getPlate();
4832 05 Jun 18 olle 1142     int numColumns = plate.getColumns();
4832 05 Jun 18 olle 1143
4832 05 Jun 18 olle 1144     // Get position for next well
4832 05 Jun 18 olle 1145     int nextPos = well.getRow() * numColumns + well.getColumn()+1;
4832 05 Jun 18 olle 1146     int nextRow = nextPos / numColumns;
4832 05 Jun 18 olle 1147     int nextCol = nextPos % numColumns;
4832 05 Jun 18 olle 1148     
4832 05 Jun 18 olle 1149     boolean foundNextEmpty = false;          
4832 05 Jun 18 olle 1150     for (int row = nextRow; row < plate.getRows() && !foundNextEmpty; row++)
4832 05 Jun 18 olle 1151     {
4832 05 Jun 18 olle 1152       for (int col = nextCol; col < plate.getColumns() && !foundNextEmpty; col++)
4832 05 Jun 18 olle 1153       { 
4832 05 Jun 18 olle 1154         if (plate.getBioWell(row, col).isEmpty())
4832 05 Jun 18 olle 1155         {
4832 05 Jun 18 olle 1156           nextFreeWell = plate.getBioWell(row, col);
4832 05 Jun 18 olle 1157           foundNextEmpty = true;
4832 05 Jun 18 olle 1158         }
4832 05 Jun 18 olle 1159       }
4832 05 Jun 18 olle 1160     }    
4832 05 Jun 18 olle 1161     return nextFreeWell;
4832 05 Jun 18 olle 1162   }
4832 05 Jun 18 olle 1163
4832 05 Jun 18 olle 1164   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 1165   @Override
4832 05 Jun 18 olle 1166   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
4832 05 Jun 18 olle 1167     throws ServletException, IOException 
4832 05 Jun 18 olle 1168   {
4832 05 Jun 18 olle 1169     String ID = req.getParameter("ID");
4832 05 Jun 18 olle 1170     String cmd = req.getParameter("cmd");
4832 05 Jun 18 olle 1171     JsonUtil.setJsonResponseHeaders(resp);
4832 05 Jun 18 olle 1172     
4832 05 Jun 18 olle 1173     JSONObject json = new JSONObject();
4832 05 Jun 18 olle 1174     json.put("status", "ok");
4832 05 Jun 18 olle 1175     
4832 05 Jun 18 olle 1176     JSONArray jsonMessages = new JSONArray();
4832 05 Jun 18 olle 1177   
5468 04 Jun 19 olle 1178     //final SessionControl sc = Application.getSessionControl(ID, req.getRemoteAddr());
5744 20 Nov 19 olle 1179     //final SessionControl sc  = Application.getSessionControl(ID, "", req.getRemoteAddr(), true);
5744 20 Nov 19 olle 1180     final SessionControl sc  = Application.getSessionControl(ID, null, req.getRemoteAddr(), true);
4832 05 Jun 18 olle 1181     DbControl dc = null;
4832 05 Jun 18 olle 1182     try
4832 05 Jun 18 olle 1183     {
4832 05 Jun 18 olle 1184       if ("CreateCase".equals(cmd))
4832 05 Jun 18 olle 1185       {
4832 05 Jun 18 olle 1186         dc = sc.newDbControl();
4832 05 Jun 18 olle 1187
4832 05 Jun 18 olle 1188         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
4832 05 Jun 18 olle 1189
4832 05 Jun 18 olle 1190         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
4832 05 Jun 18 olle 1191         JSONObject jsonPat = (JSONObject)jsonReq.get("patientInfo");
4832 05 Jun 18 olle 1192         JSONObject jsonCase = (JSONObject)jsonReq.get("caseInfo");
4832 05 Jun 18 olle 1193
4832 05 Jun 18 olle 1194         BioSource patient = getOrCreatePatient(dc, jsonPat, jsonMessages);
4832 05 Jun 18 olle 1195         
4832 05 Jun 18 olle 1196         // If we already have a case with id it is probably due to an already registered consent=yes
4832 05 Jun 18 olle 1197         Number preCaseId = (Number)jsonCase.get("id");
4832 05 Jun 18 olle 1198
4832 05 Jun 18 olle 1199         // Load/create case
4832 05 Jun 18 olle 1200         String originalCaseName = (String)jsonCase.get("name");
4832 05 Jun 18 olle 1201
4832 05 Jun 18 olle 1202         Sample theCase = null;
4832 05 Jun 18 olle 1203         if (preCaseId != null)
4832 05 Jun 18 olle 1204         {
4832 05 Jun 18 olle 1205           // Load existing case
4832 05 Jun 18 olle 1206           theCase = Sample.getById(dc, preCaseId.intValue());
4832 05 Jun 18 olle 1207         }
4832 05 Jun 18 olle 1208         else
4832 05 Jun 18 olle 1209         {
4832 05 Jun 18 olle 1210           // Register a new case
4832 05 Jun 18 olle 1211           theCase = Sample.getNew(dc);
4832 05 Jun 18 olle 1212           dc.saveItem(theCase);
4832 05 Jun 18 olle 1213         }
4832 05 Jun 18 olle 1214         theCase.setItemSubtype(Subtype.CASE.load(dc));
4832 05 Jun 18 olle 1215         theCase.setName(originalCaseName);
4870 25 Jun 18 olle 1216         //theCase.getCreationEvent().setSource(patient);
4870 25 Jun 18 olle 1217         if (patient == null)
4870 25 Jun 18 olle 1218         {
4870 25 Jun 18 olle 1219           theCase.getCreationEvent().setSource(patient);
4870 25 Jun 18 olle 1220         }
4832 05 Jun 18 olle 1221         jsonMessages.add("Case '" + originalCaseName + "' created successfully.");
4832 05 Jun 18 olle 1222         
4832 05 Jun 18 olle 1223         String plNumber = Values.getStringOrNull((String)jsonCase.get("plNumber"));
4832 05 Jun 18 olle 1224         String pad = Values.getStringOrNull((String)jsonCase.get("pad"));
4832 05 Jun 18 olle 1225
4832 05 Jun 18 olle 1226         // Case and specimen tube registration
4832 05 Jun 18 olle 1227         // Load the case if we already know which case the specimen belong to
4832 05 Jun 18 olle 1228         Number caseId = (Number)jsonCase.get("id");
4832 05 Jun 18 olle 1229         String caseName = (String)jsonCase.get("name");
4832 05 Jun 18 olle 1230         int numTubes = 0;
4832 05 Jun 18 olle 1231         JSONArray jsonSpecimenTmp = (JSONArray)jsonCase.get("specimen");    
4832 05 Jun 18 olle 1232         if (jsonSpecimenTmp != null)
4832 05 Jun 18 olle 1233         {
4832 05 Jun 18 olle 1234           numTubes = jsonSpecimenTmp.size();
4832 05 Jun 18 olle 1235         }
4832 05 Jun 18 olle 1236         String arrivalDateStr = (String)jsonCase.get("arrivalDate");
4832 05 Jun 18 olle 1237         String samplingDateStr = (String)jsonCase.get("samplingDate");
4832 05 Jun 18 olle 1238         List<String> mutationAnalysisList = new ArrayList<String>();
4832 05 Jun 18 olle 1239         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisKras", "KRAS", mutationAnalysisList);
4832 05 Jun 18 olle 1240         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisNras", "NRAS", mutationAnalysisList);
4832 05 Jun 18 olle 1241         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisBraf", "BRAF", mutationAnalysisList);
4832 05 Jun 18 olle 1242         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisEgfr", "EGFR", mutationAnalysisList);
4832 05 Jun 18 olle 1243         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisAlkEml4", "ALKEML4", mutationAnalysisList);
4832 05 Jun 18 olle 1244         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisPdgfra", "PDGFRA", mutationAnalysisList);
4832 05 Jun 18 olle 1245         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisKit", "KIT", mutationAnalysisList);
4832 05 Jun 18 olle 1246         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisTst170", "TST170", mutationAnalysisList);
4832 05 Jun 18 olle 1247         mutationAnalysisList = fetchMutationAnalysisList(jsonCase, "mutationAnalysisOther", "Other", mutationAnalysisList);
4832 05 Jun 18 olle 1248         String siteStr = replaceBlankWithNull((String)jsonCase.get("site"));
4832 05 Jun 18 olle 1249         String tubeContentType = Values.getStringOrNull((String)jsonCase.get("tubeContentType"));
4832 05 Jun 18 olle 1250         String specimenType = Values.getStringOrNull((String)jsonCase.get("specimenType"));
4832 05 Jun 18 olle 1251         String specimenInputType = Values.getStringOrNull((String)jsonCase.get("specimenInputType"));
4832 05 Jun 18 olle 1252         String projectFocus = replaceBlankWithNull((String)jsonCase.get("projectFocus"));
4832 05 Jun 18 olle 1253         String metastasisSite = Values.getStringOrNull((String)jsonCase.get("metastasisSite"));
4832 05 Jun 18 olle 1254         String otherPathNote = Values.getStringOrNull((String)jsonCase.get("otherPathNote"));
4832 05 Jun 18 olle 1255         Boolean extractsFromFirstSpecimenOnly = (Boolean)jsonCase.get("extractsFromFirstSpecimenOnly");
4832 05 Jun 18 olle 1256         if (extractsFromFirstSpecimenOnly == null)
4832 05 Jun 18 olle 1257         {
4832 05 Jun 18 olle 1258           extractsFromFirstSpecimenOnly = false;
4832 05 Jun 18 olle 1259         }
4832 05 Jun 18 olle 1260
4832 05 Jun 18 olle 1261         if (caseId != null)
4832 05 Jun 18 olle 1262         {
4832 05 Jun 18 olle 1263           theCase = Sample.getById(dc, caseId.intValue());
4832 05 Jun 18 olle 1264           // If the Case doesn't belong to a patient yet
4832 05 Jun 18 olle 1265           // it is a free-floating consent registration only and
4832 05 Jun 18 olle 1266           // we should not link the specimen since the case may
4832 05 Jun 18 olle 1267           // have to be merged with another case of the same patient
4832 05 Jun 18 olle 1268           if (!theCase.hasSingleParent()) theCase = null;
4832 05 Jun 18 olle 1269         }
4832 05 Jun 18 olle 1270         else if (caseName != null && !caseName.equals(""))
4832 05 Jun 18 olle 1271         {
4832 05 Jun 18 olle 1272           Annotationtype.MUTATION_ANALYSIS.setAnnotationValues(dc, theCase, mutationAnalysisList);
4832 05 Jun 18 olle 1273           Annotationtype.SITE.setAnnotationValue(dc, theCase, siteStr);
4832 05 Jun 18 olle 1274           Annotationtype.TUBE_CONTENT_TYPE.setAnnotationValue(dc, theCase, tubeContentType);
4832 05 Jun 18 olle 1275           Annotationtype.PROJECT_FOCUS.setAnnotationValue(dc, theCase, projectFocus);
4832 05 Jun 18 olle 1276           Annotationtype.METASTASIS_SITE.setAnnotationValue(dc, theCase, metastasisSite);
4832 05 Jun 18 olle 1277           Annotationtype.NOF_DELIVERED_TUBES.setAnnotationValue(dc, theCase, numTubes);
4832 05 Jun 18 olle 1278           Annotationtype.OTHER_PATH_NOTE.setAnnotationValue(dc, theCase, otherPathNote);
4832 05 Jun 18 olle 1279         }
4832 05 Jun 18 olle 1280
4832 05 Jun 18 olle 1281         StringToDateConverter dateConverter = new StringToDateConverter(new SimpleDateFormat("yyyyMMdd"));        
4832 05 Jun 18 olle 1282         Date arrivalDate = dateConverter.convert((String)jsonCase.get("arrivalDate"));        
4832 05 Jun 18 olle 1283         Date samplingDate = dateConverter.convert((String)jsonCase.get("samplingDate"));
4832 05 Jun 18 olle 1284         Date createDate = dateConverter.convert((String)jsonCase.get("samplingDate"));
4832 05 Jun 18 olle 1285         
4832 05 Jun 18 olle 1286         JSONArray jsonSpecimen = (JSONArray)jsonCase.get("specimen");
4832 05 Jun 18 olle 1287                 
4832 05 Jun 18 olle 1288         if (jsonSpecimen != null && jsonSpecimen.size() > 0)
4832 05 Jun 18 olle 1289         {
4832 05 Jun 18 olle 1290           HashMap<String, BioPlate> bioPlateNamePlateHashMap = new HashMap<String, BioPlate>();
4832 05 Jun 18 olle 1291           int nofTubes = jsonSpecimen.size();
4832 05 Jun 18 olle 1292           for (int i=0; i < jsonSpecimen.size(); i++)
4832 05 Jun 18 olle 1293           {
4832 05 Jun 18 olle 1294             JSONObject jsonSpec = (JSONObject)jsonSpecimen.get(i);
4832 05 Jun 18 olle 1295             String itemName = (String)jsonSpec.get("name");
4832 05 Jun 18 olle 1296             Integer nofSections = 0;
4832 05 Jun 18 olle 1297             String nofSectionsString = (String)jsonSpec.get("nofSections");
4832 05 Jun 18 olle 1298             if (nofSectionsString != null && !nofSectionsString.equals(""))
4832 05 Jun 18 olle 1299             {
4832 05 Jun 18 olle 1300               nofSections = Integer.parseInt(nofSectionsString);
4832 05 Jun 18 olle 1301             }
4832 05 Jun 18 olle 1302             String operatorComment = Values.getStringOrNull((String)jsonSpec.get("comment"));
4832 05 Jun 18 olle 1303             // Create items of correct types
4832 05 Jun 18 olle 1304             if (tubeContentType != null && tubeContentType.equals("Specimen"))
4832 05 Jun 18 olle 1305             {
4832 05 Jun 18 olle 1306               Sample specimen = Sample.getNew(dc);
4832 05 Jun 18 olle 1307               specimen.setItemSubtype(Subtype.SPECIMEN.load(dc));
4832 05 Jun 18 olle 1308               specimen.setName(itemName);
4832 05 Jun 18 olle 1309               dc.saveItem(specimen);
4832 05 Jun 18 olle 1310
4832 05 Jun 18 olle 1311               BioMaterialEvent creationEvent = specimen.getCreationEvent();
4832 05 Jun 18 olle 1312               // Link the specimen with the case
4832 05 Jun 18 olle 1313               if (theCase != null)
4832 05 Jun 18 olle 1314               {
4832 05 Jun 18 olle 1315                 creationEvent.setSource(theCase);
4832 05 Jun 18 olle 1316               }
4832 05 Jun 18 olle 1317               creationEvent.setEventDate(createDate);
4832 05 Jun 18 olle 1318               
4832 05 Jun 18 olle 1319               setAnnotations(dc, specimen, jsonCase, nofSections, operatorComment);
4832 05 Jun 18 olle 1320               // Set PL-number and PAD/CL annotations
4832 05 Jun 18 olle 1321               Annotationtype.PL_NUMBER.setAnnotationValue(dc, specimen, plNumber);
4832 05 Jun 18 olle 1322               Annotationtype.PAD.setAnnotationValue(dc, specimen, pad);
4832 05 Jun 18 olle 1323               
4832 05 Jun 18 olle 1324               // Get biowell if it is specified for this tube
4832 05 Jun 18 olle 1325               BioWell well = fetchBioWell(dc, jsonSpec, bioPlateNamePlateHashMap);
4832 05 Jun 18 olle 1326               // Set storage space for specimen, if former is valid
4832 05 Jun 18 olle 1327               if (well != null)
4832 05 Jun 18 olle 1328               {
4832 05 Jun 18 olle 1329                 specimen.setBioWell(well);              
4832 05 Jun 18 olle 1330               }
4832 05 Jun 18 olle 1331               jsonMessages.add("Specimen tube '" + specimen.getName() + "' created successfully.");
4832 05 Jun 18 olle 1332
4832 05 Jun 18 olle 1333               // Optional creation of extracts from specimen
4832 05 Jun 18 olle 1334               if (i == 0 || !extractsFromFirstSpecimenOnly)
4832 05 Jun 18 olle 1335               {
4832 05 Jun 18 olle 1336                 // DNA extract from specimen
4832 05 Jun 18 olle 1337                 Extract dna = Extract.getNew(dc);
4832 05 Jun 18 olle 1338                 dna.setItemSubtype(Subtype.DNA.load(dc));
4832 05 Jun 18 olle 1339                 dna.setName(itemName + ".d");
4832 05 Jun 18 olle 1340                 BioMaterialEvent dnaEvent = dna.getCreationEvent();
4832 05 Jun 18 olle 1341                 dnaEvent.setSource(specimen);
4832 05 Jun 18 olle 1342                 dc.saveItem(dna);
4832 05 Jun 18 olle 1343                 // Get bioWell if it is specified for DNA extract
4832 05 Jun 18 olle 1344                 BioWell dnaWell = fetchBioWell(dc, jsonSpec, bioPlateNamePlateHashMap, "DNA");
4832 05 Jun 18 olle 1345                 // Set storage space for DNA, if former is valid
4832 05 Jun 18 olle 1346                 if (dnaWell != null)
4832 05 Jun 18 olle 1347                 {
4832 05 Jun 18 olle 1348                   dna.setBioWell(dnaWell);              
4832 05 Jun 18 olle 1349                 }
4832 05 Jun 18 olle 1350                 jsonMessages.add("DNA extract '" + dna.getName() + "' created successfully.");
4832 05 Jun 18 olle 1351
4832 05 Jun 18 olle 1352                 // RNA extract from specimen
4832 05 Jun 18 olle 1353                 Extract rna = Extract.getNew(dc);
4832 05 Jun 18 olle 1354                 rna.setItemSubtype(Subtype.RNA.load(dc));
4832 05 Jun 18 olle 1355                 rna.setName(itemName + ".r");
4832 05 Jun 18 olle 1356                 BioMaterialEvent rnaEvent = rna.getCreationEvent();
4832 05 Jun 18 olle 1357                 rnaEvent.setSource(specimen);
4832 05 Jun 18 olle 1358                 dc.saveItem(rna);
4832 05 Jun 18 olle 1359                 // Get bioWell if it is specified for RNA extract
4832 05 Jun 18 olle 1360                 BioWell rnaWell = fetchBioWell(dc, jsonSpec, bioPlateNamePlateHashMap, "RNA");
4832 05 Jun 18 olle 1361                 // Set storage space for RNA, if former is valid
4832 05 Jun 18 olle 1362                 if (rnaWell != null)
4832 05 Jun 18 olle 1363                 {
4832 05 Jun 18 olle 1364                   rna.setBioWell(rnaWell);              
4832 05 Jun 18 olle 1365                 }
4832 05 Jun 18 olle 1366                 jsonMessages.add("RNA extract '" + rna.getName() + "' created successfully.");
4832 05 Jun 18 olle 1367               }
4832 05 Jun 18 olle 1368             }
4832 05 Jun 18 olle 1369             else if (tubeContentType != null)
4832 05 Jun 18 olle 1370             {
4832 05 Jun 18 olle 1371               Extract extract = Extract.getNew(dc);
4832 05 Jun 18 olle 1372               String extractTypeStr = "Extract";
4832 05 Jun 18 olle 1373               if (itemName.endsWith(".d"))
4832 05 Jun 18 olle 1374               {
4832 05 Jun 18 olle 1375                 extractTypeStr = "DNA";
4832 05 Jun 18 olle 1376                 extract.setItemSubtype(Subtype.DNA.load(dc));
4832 05 Jun 18 olle 1377               }
4832 05 Jun 18 olle 1378               else if (itemName.endsWith(".r"))
4832 05 Jun 18 olle 1379               {
4832 05 Jun 18 olle 1380                 extractTypeStr = "RNA";
4832 05 Jun 18 olle 1381                 extract.setItemSubtype(Subtype.RNA.load(dc));
4832 05 Jun 18 olle 1382               }
4832 05 Jun 18 olle 1383               extract.setName(itemName);
4832 05 Jun 18 olle 1384               dc.saveItem(extract);
4832 05 Jun 18 olle 1385               
4832 05 Jun 18 olle 1386               BioMaterialEvent creationEvent = extract.getCreationEvent();
4832 05 Jun 18 olle 1387               // Link the extract with the case
4832 05 Jun 18 olle 1388               if (theCase != null)
4832 05 Jun 18 olle 1389               {
4832 05 Jun 18 olle 1390                 creationEvent.setSource(theCase);
4832 05 Jun 18 olle 1391               }
4832 05 Jun 18 olle 1392               creationEvent.setEventDate(createDate);
4832 05 Jun 18 olle 1393               
4832 05 Jun 18 olle 1394               setAnnotations(dc, extract, jsonCase, 0, operatorComment);
4832 05 Jun 18 olle 1395               
4832 05 Jun 18 olle 1396               // Get bioWell if it is specified for this tube
4832 05 Jun 18 olle 1397               BioWell well = fetchBioWell(dc, jsonSpec, bioPlateNamePlateHashMap);
4832 05 Jun 18 olle 1398               // Set storage space for specimen, if former is valid
4832 05 Jun 18 olle 1399               if (well != null)
4832 05 Jun 18 olle 1400               {
4832 05 Jun 18 olle 1401                 extract.setBioWell(well);              
4832 05 Jun 18 olle 1402               }
4832 05 Jun 18 olle 1403               jsonMessages.add(extractTypeStr + " tube '" + extract.getName() + "' created successfully.");
4832 05 Jun 18 olle 1404             }
4832 05 Jun 18 olle 1405           }
4832 05 Jun 18 olle 1406         }
4832 05 Jun 18 olle 1407         dc.commit();
4832 05 Jun 18 olle 1408         json.put("messages", jsonMessages);
4832 05 Jun 18 olle 1409       }      
4832 05 Jun 18 olle 1410       else if ("UpdateCase".equals(cmd))
4832 05 Jun 18 olle 1411       {
4832 05 Jun 18 olle 1412         dc = sc.newDbControl();
4832 05 Jun 18 olle 1413
4832 05 Jun 18 olle 1414         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
4832 05 Jun 18 olle 1415
4832 05 Jun 18 olle 1416         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
4870 25 Jun 18 olle 1417         //JSONObject jsonPat = (JSONObject)jsonReq.get("patientInfo");
4832 05 Jun 18 olle 1418         JSONObject jsonCase = (JSONObject)jsonReq.get("caseInfo");
4832 05 Jun 18 olle 1419         
4870 25 Jun 18 olle 1420         //BioSource patient = getOrCreatePatient(dc, jsonPat, jsonMessages);
4832 05 Jun 18 olle 1421       
4832 05 Jun 18 olle 1422         Number caseId = (Number)jsonCase.get("id");
4832 05 Jun 18 olle 1423         Sample theCase = Sample.getById(dc, caseId.intValue());
4832 05 Jun 18 olle 1424         String originalCaseName = (String)jsonCase.get("originalName");
4832 05 Jun 18 olle 1425         String tubeContentType = Values.getStringOrNull((String)jsonCase.get("tubeContentType"));
4832 05 Jun 18 olle 1426
4832 05 Jun 18 olle 1427         // Check if a patient is already associated with the case
4832 05 Jun 18 olle 1428         Patient casePatient = null;
4832 05 Jun 18 olle 1429         if (caseId != null && caseId.intValue() > 0)
4832 05 Jun 18 olle 1430         {
4832 05 Jun 18 olle 1431           Case aCase = Case.getById(dc, caseId.intValue());
4832 05 Jun 18 olle 1432           casePatient = Patient.findByCase(dc, aCase);
4832 05 Jun 18 olle 1433         }
4832 05 Jun 18 olle 1434         // If the case has no associated patient, associate it with new patient
4832 05 Jun 18 olle 1435         if (casePatient == null)
4832 05 Jun 18 olle 1436         {
4870 25 Jun 18 olle 1437           theCase.getCreationEvent().setSource(casePatient.getBioSource());
4832 05 Jun 18 olle 1438         }
4832 05 Jun 18 olle 1439
4832 05 Jun 18 olle 1440         // Get updated case information
4832 05 Jun 18 olle 1441 /*
4832 05 Jun 18 olle 1442         String plNumber = Values.getStringOrNull((String)jsonCase.get("plNumber"));
4832 05 Jun 18 olle 1443         caseInfo.bloodSamplingDate = Strings.trim(frm.bloodSamplingDate.value);
4832 05 Jun 18 olle 1444         caseInfo.bloodArrivalDate = Strings.trim(frm.bloodArrivalDate.value);
4832 05 Jun 18 olle 1445         caseInfo.ctDNA = frm.ctDNACB.checked;
4832 05 Jun 18 olle 1446         caseInfo.ctc = frm.ctcCB.checked;
4832 05 Jun 18 olle 1447         caseInfo.ffpeReferral = frm.ffpeReferralCB.checked;
4832 05 Jun 18 olle 1448         caseInfo.padPreEntry = Strings.trim(frm.padPreEntry.value);
4832 05 Jun 18 olle 1449         JSONArray jsonSpecimen = (JSONArray)jsonCase.get("specimen");
4832 05 Jun 18 olle 1450 */
4832 05 Jun 18 olle 1451         JSONArray jsonBlood = (JSONArray)jsonCase.get("blood");
4832 05 Jun 18 olle 1452
4832 05 Jun 18 olle 1453         jsonMessages.add("Case '" + originalCaseName + "' updated successfully.");
4832 05 Jun 18 olle 1454
4832 05 Jun 18 olle 1455         int numUpdatedBloodTubes = 0;
4832 05 Jun 18 olle 1456         // Update the specimen tubes
4832 05 Jun 18 olle 1457         if (jsonBlood != null && jsonBlood.size() > 0)
4832 05 Jun 18 olle 1458         {
4832 05 Jun 18 olle 1459           HashMap<String, BioPlate> bioPlateNamePlateHashMap = new HashMap<String, BioPlate>();
4832 05 Jun 18 olle 1460           Date samplingDate = Meludi.CONVERTER_STRING_TO_DATE.convert((String)jsonCase.get("bloodSamplingDate"));
4832 05 Jun 18 olle 1461           Date arrivalDate = Meludi.CONVERTER_STRING_TO_DATE.convert((String)jsonCase.get("bloodArrivalDate"));
4832 05 Jun 18 olle 1462           Boolean ctDNA = (Boolean)jsonCase.get("ctDNA");
4832 05 Jun 18 olle 1463           Boolean ctc = (Boolean)jsonCase.get("ctc");
4832 05 Jun 18 olle 1464           
4832 05 Jun 18 olle 1465           for (int i = 0; i < jsonBlood.size(); ++i)
4832 05 Jun 18 olle 1466           {
4832 05 Jun 18 olle 1467             JSONObject jsonBloodItem = (JSONObject)jsonBlood.get(i);
5044 19 Oct 18 olle 1468             String itemName = (String)jsonBloodItem.get("name");
5044 19 Oct 18 olle 1469             Sample blood = Sample.getNew(dc);
5044 19 Oct 18 olle 1470             blood.setItemSubtype(Subtype.BLOOD.load(dc));
5044 19 Oct 18 olle 1471             blood.setName(itemName);
5756 26 Nov 19 olle 1472             BioMaterialEvent creationEvent = blood.getCreationEvent();
5756 26 Nov 19 olle 1473             if (theCase != null)
5756 26 Nov 19 olle 1474             {
5756 26 Nov 19 olle 1475               creationEvent.setSource(theCase);
5756 26 Nov 19 olle 1476             }
5044 19 Oct 18 olle 1477             // !IMPORTANT - The sampling date must be set here and as an 'SamplingDateTime' annotation
5044 19 Oct 18 olle 1478             creationEvent.setEventDate(samplingDate);
5756 26 Nov 19 olle 1479             dc.saveItem(blood);
5044 19 Oct 18 olle 1480
5044 19 Oct 18 olle 1481             // Update blood item with consent for case
5044 19 Oct 18 olle 1482             if (theCase != null)
4832 05 Jun 18 olle 1483             {
5044 19 Oct 18 olle 1484               Consent.copyConsentAnnotations(dc, theCase, blood);
5044 19 Oct 18 olle 1485             }
4832 05 Jun 18 olle 1486               
5044 19 Oct 18 olle 1487             // Update the blood annotations
5044 19 Oct 18 olle 1488             Annotationtype.CASE_ID.setAnnotationValue(dc, blood, originalCaseName);
5044 19 Oct 18 olle 1489             //Annotationtype.PAD.setAnnotationValue(dc, blood, pad);
5044 19 Oct 18 olle 1490             if (samplingDate != null) Annotationtype.SAMPLING_DATE.setAnnotationValue(dc, blood, samplingDate);
5044 19 Oct 18 olle 1491             if (arrivalDate != null) Annotationtype.ARRIVAL_DATE.setAnnotationValue(dc, blood, arrivalDate);
4832 05 Jun 18 olle 1492             
5044 19 Oct 18 olle 1493             // Get biowell if it is specified for this tube
5044 19 Oct 18 olle 1494             String boxType = "Blood";
5044 19 Oct 18 olle 1495             BioWell well = fetchBioWell(dc, jsonBloodItem, bioPlateNamePlateHashMap, boxType);
5044 19 Oct 18 olle 1496             // Set storage space for blood, if former is valid
5044 19 Oct 18 olle 1497             if (well != null)
5044 19 Oct 18 olle 1498             {
5044 19 Oct 18 olle 1499               blood.setBioWell(well);              
5044 19 Oct 18 olle 1500             }
5044 19 Oct 18 olle 1501             jsonMessages.add("Blood tube '" + blood.getName() + "' created successfully.");
4832 05 Jun 18 olle 1502               
5044 19 Oct 18 olle 1503             numUpdatedBloodTubes++;
4832 05 Jun 18 olle 1504           }
4832 05 Jun 18 olle 1505           jsonMessages.add(numUpdatedBloodTubes + " blood tube(s) updated.");
4832 05 Jun 18 olle 1506         }
4832 05 Jun 18 olle 1507         dc.commit();
4832 05 Jun 18 olle 1508         json.put("messages", jsonMessages);
4832 05 Jun 18 olle 1509         CounterService.getInstance().setForceCount();
4832 05 Jun 18 olle 1510       }
5000 03 Oct 18 olle 1511       else if ("RegisterBloodSamples".equals(cmd))
5000 03 Oct 18 olle 1512       {
5000 03 Oct 18 olle 1513         dc = sc.newDbControl();
5000 03 Oct 18 olle 1514
5000 03 Oct 18 olle 1515         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
5000 03 Oct 18 olle 1516
5000 03 Oct 18 olle 1517         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
5000 03 Oct 18 olle 1518         JSONObject jsonBloodTot = (JSONObject)jsonReq.get("bloodInfo");
5000 03 Oct 18 olle 1519         JSONArray jsonBlood = (JSONArray)jsonBloodTot.get("blood");
5000 03 Oct 18 olle 1520
5000 03 Oct 18 olle 1521         // Register the blood tubes
5000 03 Oct 18 olle 1522         int numUpdatedBloodTubes = 0;
5000 03 Oct 18 olle 1523         if (jsonBlood != null && jsonBlood.size() > 0)
5000 03 Oct 18 olle 1524         {
5000 03 Oct 18 olle 1525           HashMap<String, String> caseNameHighestBloodNameHashMap = new HashMap<String, String>();
5000 03 Oct 18 olle 1526           HashMap<String, BioPlate> bioPlateNamePlateHashMap = new HashMap<String, BioPlate>();
5000 03 Oct 18 olle 1527           String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId());
5044 19 Oct 18 olle 1528           int bloodItemNumDigits = Meludi.fetchBloodItemNumDigits(sc.getActiveProjectId());
5000 03 Oct 18 olle 1529           
5044 19 Oct 18 olle 1530           
5000 03 Oct 18 olle 1531           // Get highest blood item name (all cases)
5044 19 Oct 18 olle 1532           String highestBloodItemName = fetchHighestItemName(dc, Subtype.BLOOD);
5000 03 Oct 18 olle 1533           if (highestBloodItemName == null)
5000 03 Oct 18 olle 1534           {
5000 03 Oct 18 olle 1535             // Create dummy blood item name with suffix .0
5000 03 Oct 18 olle 1536             highestBloodItemName = "";
5044 19 Oct 18 olle 1537             while (highestBloodItemName.length() < bloodItemNumDigits)
5000 03 Oct 18 olle 1538             {
5000 03 Oct 18 olle 1539               highestBloodItemName = "0" + highestBloodItemName;
5000 03 Oct 18 olle 1540             }
5000 03 Oct 18 olle 1541             // Add prefix and suffix
5000 03 Oct 18 olle 1542             highestBloodItemName = bloodItemPrefix + highestBloodItemName + ".0";
5000 03 Oct 18 olle 1543           }
5000 03 Oct 18 olle 1544
5000 03 Oct 18 olle 1545           for (int i = 0; i < jsonBlood.size(); ++i)
5000 03 Oct 18 olle 1546           {
5000 03 Oct 18 olle 1547             JSONObject jsonBloodItem = (JSONObject)jsonBlood.get(i);
5000 03 Oct 18 olle 1548             String tubeLabel = (String)jsonBloodItem.get("tubeLabel");
5027 15 Oct 18 olle 1549             String samplingDateString = (String)jsonBloodItem.get("samplingDate");
5027 15 Oct 18 olle 1550             String arrivalDateString = (String)jsonBloodItem.get("arrivalDate");
5000 03 Oct 18 olle 1551             String box = (String)jsonBloodItem.get("box");
5000 03 Oct 18 olle 1552             String row = (String)jsonBloodItem.get("row");
5000 03 Oct 18 olle 1553             String column = (String)jsonBloodItem.get("column");
5027 15 Oct 18 olle 1554             String comment = (String)jsonBloodItem.get("comment");
5027 15 Oct 18 olle 1555             String operator = (String)jsonBloodItem.get("operator");
5000 03 Oct 18 olle 1556             // Remove optional hyphens "-" from date string before conversion to date
5027 15 Oct 18 olle 1557             samplingDateString = samplingDateString.replaceAll("-", "");
5000 03 Oct 18 olle 1558             arrivalDateString = arrivalDateString.replaceAll("-", "");
5027 15 Oct 18 olle 1559             Date samplingDate = Meludi.CONVERTER_STRING_TO_DATE.convert(samplingDateString);
5000 03 Oct 18 olle 1560             Date arrivalDate = Meludi.CONVERTER_STRING_TO_DATE.convert(arrivalDateString);
5000 03 Oct 18 olle 1561
5000 03 Oct 18 olle 1562             // Get blood item name to use (base name + integer suffix)
5000 03 Oct 18 olle 1563             //
5000 03 Oct 18 olle 1564             String bloodItemBaseName = "";
5000 03 Oct 18 olle 1565             int bloodItemNumber = 0;
5000 03 Oct 18 olle 1566             String bloodItemName = null;
5000 03 Oct 18 olle 1567             // Get referral ID from tube label by removing suffix
5000 03 Oct 18 olle 1568             String referralId = tubeLabel;
5000 03 Oct 18 olle 1569             int dotIndex = referralId.indexOf(".");
5000 03 Oct 18 olle 1570             if (dotIndex >= 0)
5000 03 Oct 18 olle 1571             {
5000 03 Oct 18 olle 1572               // Remove part starting with first dot
5000 03 Oct 18 olle 1573               referralId = referralId.substring(0, dotIndex);
5000 03 Oct 18 olle 1574             }
5000 03 Oct 18 olle 1575             // Find case name from referral ID
5000 03 Oct 18 olle 1576             String caseName = null;
5000 03 Oct 18 olle 1577             Case theCase = Case.findByReferralId(dc, referralId);
5000 03 Oct 18 olle 1578             if (theCase != null)
5000 03 Oct 18 olle 1579             {
5000 03 Oct 18 olle 1580               caseName = theCase.getName();
5000 03 Oct 18 olle 1581             }
5000 03 Oct 18 olle 1582
5016 09 Oct 18 olle 1583             String highestBloodItemNameForCase = null;
5016 09 Oct 18 olle 1584             // Check if existing blood items exists for case in hash map
5016 09 Oct 18 olle 1585             highestBloodItemNameForCase = (String)caseNameHighestBloodNameHashMap.get(caseName);
5016 09 Oct 18 olle 1586             if (highestBloodItemNameForCase == null)
5000 03 Oct 18 olle 1587             {
5016 09 Oct 18 olle 1588               // Check if existing blood items exists for case (sorted ascending after name)
5016 09 Oct 18 olle 1589               List<Blood> bloodItems = null;
5016 09 Oct 18 olle 1590               bloodItems = Blood.findAllByCaseName(dc, caseName);
5016 09 Oct 18 olle 1591           
5016 09 Oct 18 olle 1592               if (bloodItems.size() > 0) 
5016 09 Oct 18 olle 1593               {
5016 09 Oct 18 olle 1594                 highestBloodItemNameForCase = ((Blood)bloodItems.get(bloodItems.size() - 1)).getName();
5016 09 Oct 18 olle 1595                 // Update hash map with highest blood name for case
5016 09 Oct 18 olle 1596                 caseNameHighestBloodNameHashMap.put(caseName, highestBloodItemNameForCase);
5016 09 Oct 18 olle 1597               }
5000 03 Oct 18 olle 1598             }
5016 09 Oct 18 olle 1599             
5016 09 Oct 18 olle 1600             if (highestBloodItemNameForCase != null)
5000 03 Oct 18 olle 1601             {
5016 09 Oct 18 olle 1602               // Get new blood item name by incrementing suffix number for existing blood item name
5016 09 Oct 18 olle 1603               //
5016 09 Oct 18 olle 1604               // Get base name (name without suffix) for highest blood item for case
5016 09 Oct 18 olle 1605               dotIndex = highestBloodItemNameForCase.indexOf(".");
5016 09 Oct 18 olle 1606               if (dotIndex > -1)
5000 03 Oct 18 olle 1607               {
5016 09 Oct 18 olle 1608                 bloodItemBaseName = highestBloodItemNameForCase.substring(0, dotIndex);
5016 09 Oct 18 olle 1609                 // Get suffix number string
5016 09 Oct 18 olle 1610                 String bloodItemNumberString = highestBloodItemNameForCase.substring(dotIndex + 1);
5016 09 Oct 18 olle 1611                 if (bloodItemNumberString != null)
5000 03 Oct 18 olle 1612                 {
5016 09 Oct 18 olle 1613                   bloodItemNumber = Integer.valueOf(bloodItemNumberString);
5000 03 Oct 18 olle 1614                 }
5016 09 Oct 18 olle 1615                 // Increment blood item suffix number for new blood item
5016 09 Oct 18 olle 1616                 bloodItemNumber = bloodItemNumber + 1;
5016 09 Oct 18 olle 1617                 // Get new blood item name
5016 09 Oct 18 olle 1618                 bloodItemName = bloodItemBaseName + "." + bloodItemNumber;
5000 03 Oct 18 olle 1619               }
5016 09 Oct 18 olle 1620             }
5016 09 Oct 18 olle 1621             else
5016 09 Oct 18 olle 1622             {
5016 09 Oct 18 olle 1623               // Get completely new blood item name (new base name with incremented number)
5016 09 Oct 18 olle 1624               // Get base name (name without suffix) for highest blood item
5016 09 Oct 18 olle 1625               String highestBloodItemBaseName = null;
5016 09 Oct 18 olle 1626               dotIndex = highestBloodItemName.indexOf(".");
5016 09 Oct 18 olle 1627               if (dotIndex > -1)
5000 03 Oct 18 olle 1628               {
5016 09 Oct 18 olle 1629                 highestBloodItemBaseName = highestBloodItemName.substring(0, dotIndex);
5000 03 Oct 18 olle 1630               }
5016 09 Oct 18 olle 1631               // Remove blood item item prefix
5016 09 Oct 18 olle 1632               int prefixLength = bloodItemPrefix.length();
5016 09 Oct 18 olle 1633               String highestBloodItemNumString = highestBloodItemBaseName.substring(prefixLength);
5016 09 Oct 18 olle 1634               // Remove leading zeroes in blood item number
5016 09 Oct 18 olle 1635               while (highestBloodItemNumString.indexOf("0") == 0)
5000 03 Oct 18 olle 1636               {
5016 09 Oct 18 olle 1637                 highestBloodItemNumString = highestBloodItemNumString.substring(1);
5000 03 Oct 18 olle 1638               }
5016 09 Oct 18 olle 1639               if (highestBloodItemNumString.equals(""))
5016 09 Oct 18 olle 1640               {
5016 09 Oct 18 olle 1641                 highestBloodItemNumString = "0";
5016 09 Oct 18 olle 1642               }
5016 09 Oct 18 olle 1643               // Get highest current blood item number as integer
5016 09 Oct 18 olle 1644               int highestBloodItemNumber = Integer.parseUnsignedInt(highestBloodItemNumString);
5016 09 Oct 18 olle 1645               // Get new blood item number
5016 09 Oct 18 olle 1646               int newBloodItemNumber = highestBloodItemNumber + 1;
5016 09 Oct 18 olle 1647               // Get new blood item number string with leading zeroes
5016 09 Oct 18 olle 1648               String newBloodItemNumString = "" + newBloodItemNumber;
5044 19 Oct 18 olle 1649               while (newBloodItemNumString.length() < bloodItemNumDigits)
5016 09 Oct 18 olle 1650               {
5016 09 Oct 18 olle 1651                 newBloodItemNumString = "0" + newBloodItemNumString;
5016 09 Oct 18 olle 1652               }
5016 09 Oct 18 olle 1653               // Get new blood item name
5016 09 Oct 18 olle 1654               bloodItemName = bloodItemPrefix + newBloodItemNumString + ".1";
5016 09 Oct 18 olle 1655               //bloodItemName = bloodItemBaseName + "." + bloodItemNumber;
5016 09 Oct 18 olle 1656               // Update highest blood item number
5016 09 Oct 18 olle 1657               highestBloodItemName = bloodItemName;
5016 09 Oct 18 olle 1658             }
5000 03 Oct 18 olle 1659
5016 09 Oct 18 olle 1660             // Update hash map with highest blood name for case
5016 09 Oct 18 olle 1661             caseNameHighestBloodNameHashMap.put(caseName, bloodItemName);
5000 03 Oct 18 olle 1662
5016 09 Oct 18 olle 1663             // Register blood sample
5016 09 Oct 18 olle 1664             //
5016 09 Oct 18 olle 1665             String itemName = bloodItemName;
5016 09 Oct 18 olle 1666             Sample blood = Sample.getNew(dc);
5016 09 Oct 18 olle 1667             blood.setItemSubtype(Subtype.BLOOD.load(dc));
5016 09 Oct 18 olle 1668             blood.setName(itemName);
5027 15 Oct 18 olle 1669             blood.setDescription(comment);
5756 26 Nov 19 olle 1670             BioMaterialEvent creationEvent = blood.getCreationEvent();
5756 26 Nov 19 olle 1671             if (theCase != null)
5756 26 Nov 19 olle 1672             {
5756 26 Nov 19 olle 1673               creationEvent.setSource(theCase.getSample());
5756 26 Nov 19 olle 1674             }
5016 09 Oct 18 olle 1675             dc.saveItem(blood);
5016 09 Oct 18 olle 1676             // !IMPORTANT - The sampling date must be set here and as an 'SamplingDateTime' annotation
5016 09 Oct 18 olle 1677             //BioMaterialEvent creationEvent = blood.getCreationEvent();
5016 09 Oct 18 olle 1678             //creationEvent.setEventDate(samplingDate);
5000 03 Oct 18 olle 1679
5016 09 Oct 18 olle 1680             // Update blood item with consent for case
5016 09 Oct 18 olle 1681             if (theCase != null)
5016 09 Oct 18 olle 1682             {
5016 09 Oct 18 olle 1683               Consent.copyConsentAnnotations(dc, theCase.getSample(), blood);
5016 09 Oct 18 olle 1684             }
5000 03 Oct 18 olle 1685             
5016 09 Oct 18 olle 1686             // Update the blood annotations
5016 09 Oct 18 olle 1687             Annotationtype.CASE_ID.setAnnotationValue(dc, blood, caseName);
5016 09 Oct 18 olle 1688             Annotationtype.TUBE_LABEL.setAnnotationValue(dc, blood, tubeLabel);
5016 09 Oct 18 olle 1689             if (samplingDate != null) Annotationtype.SAMPLING_DATE.setAnnotationValue(dc, blood, samplingDate);
5016 09 Oct 18 olle 1690             if (arrivalDate != null) Annotationtype.ARRIVAL_DATE.setAnnotationValue(dc, blood, arrivalDate);
5034 17 Oct 18 olle 1691             if (operator != null) Annotationtype.ARRIVAL_OPERATOR.setAnnotationValue(dc, blood, operator);
5000 03 Oct 18 olle 1692
5016 09 Oct 18 olle 1693             // Get biowell if it is specified for this tube
5016 09 Oct 18 olle 1694             String boxType = "Blood";
5016 09 Oct 18 olle 1695             BioWell well = fetchBioWell(dc, jsonBloodItem, bioPlateNamePlateHashMap, boxType);
5016 09 Oct 18 olle 1696             // Set storage space for blood, if former is valid
5016 09 Oct 18 olle 1697             if (well != null)
5016 09 Oct 18 olle 1698             {
5016 09 Oct 18 olle 1699               blood.setBioWell(well);              
5000 03 Oct 18 olle 1700             }
5016 09 Oct 18 olle 1701             numUpdatedBloodTubes++;
5016 09 Oct 18 olle 1702             jsonMessages.add("Blood item '" + blood.getName() + "' [tube label = " + tubeLabel + " case = " + caseName + "] created successfully.");
5000 03 Oct 18 olle 1703           }
5000 03 Oct 18 olle 1704           jsonMessages.add(numUpdatedBloodTubes + " blood tube(s) updated.");
5000 03 Oct 18 olle 1705         }
5000 03 Oct 18 olle 1706         dc.commit();
5000 03 Oct 18 olle 1707         json.put("messages", jsonMessages);
5000 03 Oct 18 olle 1708         CounterService.getInstance().setForceCount();
5000 03 Oct 18 olle 1709       }
5044 19 Oct 18 olle 1710       else if ("RegisterFFPEBlocks".equals(cmd))
5044 19 Oct 18 olle 1711       {
5044 19 Oct 18 olle 1712         dc = sc.newDbControl();
5044 19 Oct 18 olle 1713
5044 19 Oct 18 olle 1714         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
5044 19 Oct 18 olle 1715
5044 19 Oct 18 olle 1716         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
5044 19 Oct 18 olle 1717         JSONObject jsonFfpeBlockTot = (JSONObject)jsonReq.get("ffpeBlockInfo");
5044 19 Oct 18 olle 1718         JSONArray jsonFfpeBlock = (JSONArray)jsonFfpeBlockTot.get("ffpeBlock");
5044 19 Oct 18 olle 1719
5044 19 Oct 18 olle 1720         // Register the FFPE blocks
5044 19 Oct 18 olle 1721         int numUpdatedFfpeBlocks = 0;
5044 19 Oct 18 olle 1722         if (jsonFfpeBlock != null && jsonFfpeBlock.size() > 0)
5044 19 Oct 18 olle 1723         {
5044 19 Oct 18 olle 1724           HashMap<String, String> caseNameHighestFfpeBlockNameHashMap = new HashMap<String, String>();
5044 19 Oct 18 olle 1725           String ffpeBlockItemPrefix = Meludi.fetchFfpeBlockItemPrefix(sc.getActiveProjectId());
5044 19 Oct 18 olle 1726           int ffpeBlockItemNumDigits = Meludi.fetchFfpeBlockItemNumDigits(sc.getActiveProjectId());
5044 19 Oct 18 olle 1727           
5044 19 Oct 18 olle 1728           // Get highest FFPE block item name (all cases)
5044 19 Oct 18 olle 1729           String highestFfpeBlockItemName = fetchHighestItemName(dc, Subtype.FFPE_BLOCK);
5044 19 Oct 18 olle 1730           if (highestFfpeBlockItemName == null)
5044 19 Oct 18 olle 1731           {
5044 19 Oct 18 olle 1732             // Create dummy FFPE block item name with suffix .0
5044 19 Oct 18 olle 1733             highestFfpeBlockItemName = "";
5044 19 Oct 18 olle 1734             while (highestFfpeBlockItemName.length() < ffpeBlockItemNumDigits)
5044 19 Oct 18 olle 1735             {
5044 19 Oct 18 olle 1736               highestFfpeBlockItemName = "0" + highestFfpeBlockItemName;
5044 19 Oct 18 olle 1737             }
5044 19 Oct 18 olle 1738             // Add prefix and suffix
5044 19 Oct 18 olle 1739             highestFfpeBlockItemName = ffpeBlockItemPrefix + highestFfpeBlockItemName + ".0";
5044 19 Oct 18 olle 1740           }
5044 19 Oct 18 olle 1741
5044 19 Oct 18 olle 1742           for (int i = 0; i < jsonFfpeBlock.size(); ++i)
5044 19 Oct 18 olle 1743           {
5044 19 Oct 18 olle 1744             JSONObject jsonFfpeBlockItem = (JSONObject)jsonFfpeBlock.get(i);
5044 19 Oct 18 olle 1745             String caseName = (String)jsonFfpeBlockItem.get("caseName");
5044 19 Oct 18 olle 1746             String samplingDateString = (String)jsonFfpeBlockItem.get("samplingDate");
5044 19 Oct 18 olle 1747             String arrivalDateString = (String)jsonFfpeBlockItem.get("arrivalDate");
5044 19 Oct 18 olle 1748             String pad = (String)jsonFfpeBlockItem.get("pad");
5160 30 Nov 18 olle 1749             String materialNumber = (String)jsonFfpeBlockItem.get("materialNumber");
5160 30 Nov 18 olle 1750             String localisation = (String)jsonFfpeBlockItem.get("localisation");
5047 22 Oct 18 olle 1751             String yellowLabel = (String)jsonFfpeBlockItem.get("yellowLabel");
5044 19 Oct 18 olle 1752             String comment = (String)jsonFfpeBlockItem.get("comment");
5044 19 Oct 18 olle 1753             String operator = (String)jsonFfpeBlockItem.get("operator");
5044 19 Oct 18 olle 1754             // Remove optional hyphens "-" from date string before conversion to date
5044 19 Oct 18 olle 1755             //samplingDateString = samplingDateString.replaceAll("-", "");
5044 19 Oct 18 olle 1756             arrivalDateString = arrivalDateString.replaceAll("-", "");
5044 19 Oct 18 olle 1757             //Date samplingDate = Meludi.CONVERTER_STRING_TO_DATE.convert(samplingDateString);
5044 19 Oct 18 olle 1758             Date arrivalDate = Meludi.CONVERTER_STRING_TO_DATE.convert(arrivalDateString);
5044 19 Oct 18 olle 1759
5044 19 Oct 18 olle 1760             // Get FFPE block item name to use (base name + integer suffix)
5044 19 Oct 18 olle 1761             //
5044 19 Oct 18 olle 1762             String ffpeBlockItemBaseName = "";
5044 19 Oct 18 olle 1763             int ffpeBlockItemNumber = 0;
5044 19 Oct 18 olle 1764             String ffpeBlockItemName = null;
5044 19 Oct 18 olle 1765
5044 19 Oct 18 olle 1766             String highestFfpeBlockItemNameForCase = null;
5044 19 Oct 18 olle 1767             // Check if existing FFPE block items exists for case in hash map
5044 19 Oct 18 olle 1768             highestFfpeBlockItemNameForCase = (String)caseNameHighestFfpeBlockNameHashMap.get(caseName);
5044 19 Oct 18 olle 1769             if (highestFfpeBlockItemNameForCase == null)
5044 19 Oct 18 olle 1770             {
5044 19 Oct 18 olle 1771               // Check if existing FFPE block items exists for case (sorted ascending after name)
5044 19 Oct 18 olle 1772               List<FfpeBlock> ffpeBlockItems = null;
5044 19 Oct 18 olle 1773               ffpeBlockItems = FfpeBlock.findAllByCaseName(dc, caseName);
5044 19 Oct 18 olle 1774           
5044 19 Oct 18 olle 1775               if (ffpeBlockItems.size() > 0) 
5044 19 Oct 18 olle 1776               {
5044 19 Oct 18 olle 1777                 highestFfpeBlockItemNameForCase = ((FfpeBlock)ffpeBlockItems.get(ffpeBlockItems.size() - 1)).getName();
5044 19 Oct 18 olle 1778                 // Update hash map with highest FFPE block name for case
5044 19 Oct 18 olle 1779                 caseNameHighestFfpeBlockNameHashMap.put(caseName, highestFfpeBlockItemNameForCase);
5044 19 Oct 18 olle 1780               }
5044 19 Oct 18 olle 1781             }
5044 19 Oct 18 olle 1782             
5044 19 Oct 18 olle 1783             if (highestFfpeBlockItemNameForCase != null)
5044 19 Oct 18 olle 1784             {
5044 19 Oct 18 olle 1785               // Get new FFPE block item name by incrementing suffix number for existing FFPE block item name
5044 19 Oct 18 olle 1786               //
5044 19 Oct 18 olle 1787               // Get base name (name without suffix) for highest FFPE block item for case
5044 19 Oct 18 olle 1788               int dotIndex = highestFfpeBlockItemNameForCase.indexOf(".");
5044 19 Oct 18 olle 1789               if (dotIndex > -1)
5044 19 Oct 18 olle 1790               {
5044 19 Oct 18 olle 1791                 ffpeBlockItemBaseName = highestFfpeBlockItemNameForCase.substring(0, dotIndex);
5044 19 Oct 18 olle 1792                 // Get suffix number string
5044 19 Oct 18 olle 1793                 String ffpeBlockItemNumberString = highestFfpeBlockItemNameForCase.substring(dotIndex + 1);
5044 19 Oct 18 olle 1794                 if (ffpeBlockItemNumberString != null)
5044 19 Oct 18 olle 1795                 {
5044 19 Oct 18 olle 1796                   ffpeBlockItemNumber = Integer.valueOf(ffpeBlockItemNumberString);
5044 19 Oct 18 olle 1797                 }
5044 19 Oct 18 olle 1798                 // Increment FFPE block item suffix number for new FFPE block item
5044 19 Oct 18 olle 1799                 ffpeBlockItemNumber = ffpeBlockItemNumber + 1;
5044 19 Oct 18 olle 1800                 // Get new FFPE block item name
5044 19 Oct 18 olle 1801                 ffpeBlockItemName = ffpeBlockItemBaseName + "." + ffpeBlockItemNumber;
5044 19 Oct 18 olle 1802               }
5044 19 Oct 18 olle 1803             }
5044 19 Oct 18 olle 1804             else
5044 19 Oct 18 olle 1805             {
5044 19 Oct 18 olle 1806               // Get completely new FFPE block item name (new base name with incremented number)
5044 19 Oct 18 olle 1807               // Get base name (name without suffix) for highest FFPE block item
5044 19 Oct 18 olle 1808               String highestFfpeBlockItemBaseName = null;
5044 19 Oct 18 olle 1809               int dotIndex = highestFfpeBlockItemName.indexOf(".");
5044 19 Oct 18 olle 1810               if (dotIndex > -1)
5044 19 Oct 18 olle 1811               {
5044 19 Oct 18 olle 1812                 highestFfpeBlockItemBaseName = highestFfpeBlockItemName.substring(0, dotIndex);
5044 19 Oct 18 olle 1813               }
5044 19 Oct 18 olle 1814               // Remove FFPE block item item prefix
5044 19 Oct 18 olle 1815               int prefixLength = ffpeBlockItemPrefix.length();
5044 19 Oct 18 olle 1816               String highestFfpeBlockItemNumString = highestFfpeBlockItemBaseName.substring(prefixLength);
5044 19 Oct 18 olle 1817               // Remove leading zeroes in FFPE block item number
5044 19 Oct 18 olle 1818               while (highestFfpeBlockItemNumString.indexOf("0") == 0)
5044 19 Oct 18 olle 1819               {
5044 19 Oct 18 olle 1820                 highestFfpeBlockItemNumString = highestFfpeBlockItemNumString.substring(1);
5044 19 Oct 18 olle 1821               }
5044 19 Oct 18 olle 1822               if (highestFfpeBlockItemNumString.equals(""))
5044 19 Oct 18 olle 1823               {
5044 19 Oct 18 olle 1824                 highestFfpeBlockItemNumString = "0";
5044 19 Oct 18 olle 1825               }
5044 19 Oct 18 olle 1826               // Get highest current FFPE block item number as integer
5044 19 Oct 18 olle 1827               int highestFfpeBlockItemNumber = Integer.parseUnsignedInt(highestFfpeBlockItemNumString);
5044 19 Oct 18 olle 1828               // Get new FFPE block item number
5044 19 Oct 18 olle 1829               int newFfpeBlockItemNumber = highestFfpeBlockItemNumber + 1;
5044 19 Oct 18 olle 1830               // Get new FFPE block item number string with leading zeroes
5044 19 Oct 18 olle 1831               String newFfpeBlockItemNumString = "" + newFfpeBlockItemNumber;
5044 19 Oct 18 olle 1832               while (newFfpeBlockItemNumString.length() < ffpeBlockItemNumDigits)
5044 19 Oct 18 olle 1833               {
5044 19 Oct 18 olle 1834                 newFfpeBlockItemNumString = "0" + newFfpeBlockItemNumString;
5044 19 Oct 18 olle 1835               }
5044 19 Oct 18 olle 1836               // Get new FFPE block item name
5044 19 Oct 18 olle 1837               ffpeBlockItemName = ffpeBlockItemPrefix + newFfpeBlockItemNumString + ".1";
5044 19 Oct 18 olle 1838               //ffpeBlockItemName = ffpeBlockItemBaseName + "." + ffpeBlockItemNumber;
5044 19 Oct 18 olle 1839               // Update highest FFPE block item number
5044 19 Oct 18 olle 1840               highestFfpeBlockItemName = ffpeBlockItemName;
5044 19 Oct 18 olle 1841             }
5044 19 Oct 18 olle 1842
5044 19 Oct 18 olle 1843             // Update hash map with highest FFPE block name for case
5044 19 Oct 18 olle 1844             caseNameHighestFfpeBlockNameHashMap.put(caseName, ffpeBlockItemName);
5044 19 Oct 18 olle 1845
5044 19 Oct 18 olle 1846             // Register FFPE block sample
5044 19 Oct 18 olle 1847             //
5044 19 Oct 18 olle 1848             String itemName = ffpeBlockItemName;
5044 19 Oct 18 olle 1849             Sample ffpeBlock = Sample.getNew(dc);
5044 19 Oct 18 olle 1850             ffpeBlock.setItemSubtype(Subtype.FFPE_BLOCK.load(dc));
5044 19 Oct 18 olle 1851             ffpeBlock.setName(itemName);
5044 19 Oct 18 olle 1852             //ffpeBlock.setDescription(comment);
5756 26 Nov 19 olle 1853             BioMaterialEvent creationEvent = ffpeBlock.getCreationEvent();
5756 26 Nov 19 olle 1854             Case theCase = Case.findByName(dc, caseName);
5756 26 Nov 19 olle 1855             if (theCase != null)
5756 26 Nov 19 olle 1856             {
5756 26 Nov 19 olle 1857               creationEvent.setSource(theCase.getSample());
5756 26 Nov 19 olle 1858             }
5044 19 Oct 18 olle 1859             dc.saveItem(ffpeBlock);
5044 19 Oct 18 olle 1860
5044 19 Oct 18 olle 1861             // Update FFPE block item with consent for case
5044 19 Oct 18 olle 1862             if (theCase != null)
5044 19 Oct 18 olle 1863             {
5044 19 Oct 18 olle 1864               Consent.copyConsentAnnotations(dc, theCase.getSample(), ffpeBlock);
5044 19 Oct 18 olle 1865             }
5044 19 Oct 18 olle 1866             
5044 19 Oct 18 olle 1867             // Update the FFPE block annotations
5044 19 Oct 18 olle 1868             Annotationtype.CASE_ID.setAnnotationValue(dc, ffpeBlock, caseName);
5044 19 Oct 18 olle 1869             Annotationtype.PAD.setAnnotationValue(dc, ffpeBlock, pad);
5160 30 Nov 18 olle 1870             Annotationtype.MATERIAL_NUMBER.setAnnotationValue(dc, ffpeBlock, materialNumber);
5160 30 Nov 18 olle 1871             Annotationtype.LOCALISATION.setAnnotationValue(dc, ffpeBlock, localisation);
5044 19 Oct 18 olle 1872             Annotationtype.YELLOW_LABEL.setAnnotationValue(dc, ffpeBlock, yellowLabel);
5044 19 Oct 18 olle 1873             //if (samplingDate != null) Annotationtype.SAMPLING_DATE.setAnnotationValue(dc, ffpeBlock, samplingDate);
5044 19 Oct 18 olle 1874             if (arrivalDate != null) Annotationtype.ARRIVAL_DATE.setAnnotationValue(dc, ffpeBlock, arrivalDate);
5044 19 Oct 18 olle 1875             //if (operator != null) Annotationtype.ARRIVAL_OPERATOR.setAnnotationValue(dc, ffpeBlock, operator);
5044 19 Oct 18 olle 1876             Annotationtype.OPERATOR_DELIVERY_COMMENT.setAnnotationValue(dc, ffpeBlock, comment);
5044 19 Oct 18 olle 1877
5044 19 Oct 18 olle 1878             numUpdatedFfpeBlocks++;
5044 19 Oct 18 olle 1879             jsonMessages.add("FFPE block item '" + ffpeBlock.getName() + "' [PAD = " + pad + " case = " + caseName + "] created successfully.");
5044 19 Oct 18 olle 1880           }
5044 19 Oct 18 olle 1881           jsonMessages.add(numUpdatedFfpeBlocks + " FFPE block(s) updated.");
5044 19 Oct 18 olle 1882         }
5044 19 Oct 18 olle 1883         dc.commit();
5044 19 Oct 18 olle 1884         json.put("messages", jsonMessages);
5044 19 Oct 18 olle 1885         CounterService.getInstance().setForceCount();
5044 19 Oct 18 olle 1886       }
5060 29 Oct 18 olle 1887       else if ("RegisterFFPESections".equals(cmd))
5060 29 Oct 18 olle 1888       {
5060 29 Oct 18 olle 1889         dc = sc.newDbControl();
5060 29 Oct 18 olle 1890
5060 29 Oct 18 olle 1891         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
5060 29 Oct 18 olle 1892
5060 29 Oct 18 olle 1893         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
5060 29 Oct 18 olle 1894         JSONObject jsonFfpeSectionTot = (JSONObject)jsonReq.get("ffpeSectionInfo");
5060 29 Oct 18 olle 1895         JSONArray jsonFfpeSections = (JSONArray)jsonFfpeSectionTot.get("ffpeSections");
5060 29 Oct 18 olle 1896
5060 29 Oct 18 olle 1897         // Register the FFPE sections (specimen)
5060 29 Oct 18 olle 1898         int numUpdatedFfpeSections = 0;
5060 29 Oct 18 olle 1899         if (jsonFfpeSections != null && jsonFfpeSections.size() > 0)
5060 29 Oct 18 olle 1900         {
5114 20 Nov 18 olle 1901           HashMap<String, BioPlate> bioPlateNamePlateHashMap = new HashMap<String, BioPlate>();
5060 29 Oct 18 olle 1902           for (int i = 0; i < jsonFfpeSections.size(); ++i)
5060 29 Oct 18 olle 1903           {
5060 29 Oct 18 olle 1904             JSONObject jsonFfpeSection = (JSONObject)jsonFfpeSections.get(i);
5060 29 Oct 18 olle 1905             String ffpeSectionBlockName = (String)jsonFfpeSection.get("blockName");
5060 29 Oct 18 olle 1906             //String samplingDateString = (String)jsonFfpeSection.get("samplingDate");
5060 29 Oct 18 olle 1907             //String arrivalDateString = (String)jsonFfpeSection.get("arrivalDate");
5060 29 Oct 18 olle 1908             String pad = (String)jsonFfpeSection.get("pad");
5114 20 Nov 18 olle 1909             String materialNumber = (String)jsonFfpeSection.get("materialNumber");
5060 29 Oct 18 olle 1910             String yellowLabel = (String)jsonFfpeSection.get("yellowLabel");
5060 29 Oct 18 olle 1911             Integer nofSections = 0;
5060 29 Oct 18 olle 1912             String nofSectionsString = (String)jsonFfpeSection.get("nofSections");
5060 29 Oct 18 olle 1913             if (nofSectionsString != null && !nofSectionsString.equals(""))
5060 29 Oct 18 olle 1914             {
5060 29 Oct 18 olle 1915               nofSections = Integer.parseInt(nofSectionsString);
5060 29 Oct 18 olle 1916             }
5060 29 Oct 18 olle 1917             String comment = (String)jsonFfpeSection.get("comment");
5060 29 Oct 18 olle 1918             //String operator = (String)jsonFfpeSection.get("operator");
5060 29 Oct 18 olle 1919             // Remove optional hyphens "-" from date string before conversion to date
5060 29 Oct 18 olle 1920             //samplingDateString = samplingDateString.replaceAll("-", "");
5060 29 Oct 18 olle 1921             //arrivalDateString = arrivalDateString.replaceAll("-", "");
5060 29 Oct 18 olle 1922             //Date samplingDate = Meludi.CONVERTER_STRING_TO_DATE.convert(samplingDateString);
5060 29 Oct 18 olle 1923             //Date arrivalDate = Meludi.CONVERTER_STRING_TO_DATE.convert(arrivalDateString);
5060 29 Oct 18 olle 1924
5114 20 Nov 18 olle 1925             String heGlassFBox = (String)jsonFfpeSection.get("heGlassFBox");
5114 20 Nov 18 olle 1926             String heGlassFPosition = (String)jsonFfpeSection.get("heGlassFPosition");
5832 21 Feb 20 olle 1927             //int pctTumourCellsF = Integer.parseInt((String)jsonFfpeSection.get("pctTumourCellsF"));
5114 20 Nov 18 olle 1928
5114 20 Nov 18 olle 1929             String heGlassEBox = (String)jsonFfpeSection.get("heGlassEBox");
5114 20 Nov 18 olle 1930             String heGlassEPosition = (String)jsonFfpeSection.get("heGlassEPosition");
5832 21 Feb 20 olle 1931             //int pctTumourCellsE = Integer.parseInt((String)jsonFfpeSection.get("pctTumourCellsE"));
5114 20 Nov 18 olle 1932
5060 29 Oct 18 olle 1933             // Find case name from FFPE block
5060 29 Oct 18 olle 1934             String caseName = null;
5060 29 Oct 18 olle 1935             Case theCase = null;
5060 29 Oct 18 olle 1936             Date createDate = null;
5060 29 Oct 18 olle 1937             // Use stored annotation snapshots for performance reasons
5060 29 Oct 18 olle 1938             SnapshotManager manager = new SnapshotManager();        
5060 29 Oct 18 olle 1939             FfpeBlock ffpeBlock = FfpeBlock.getByName(dc, ffpeSectionBlockName);
5060 29 Oct 18 olle 1940             if (ffpeBlock != null)
5060 29 Oct 18 olle 1941             {
5060 29 Oct 18 olle 1942               // Get CASE_ID annotation
5060 29 Oct 18 olle 1943               caseName = (String) Annotationtype.CASE_ID.getAnnotationValue(dc, manager, ffpeBlock.getSample());
5060 29 Oct 18 olle 1944               if (caseName != null)
5060 29 Oct 18 olle 1945               {
5060 29 Oct 18 olle 1946                 theCase = Case.findByName(dc, caseName);
5060 29 Oct 18 olle 1947               }
5060 29 Oct 18 olle 1948               // Get arrival date annotation and use as create date
5060 29 Oct 18 olle 1949               createDate = (Date) Annotationtype.ARRIVAL_DATE.getAnnotationValue(dc, manager, ffpeBlock.getSample());
5060 29 Oct 18 olle 1950             }
5060 29 Oct 18 olle 1951             
5060 29 Oct 18 olle 1952             // Register FFPE section (specimen)
5060 29 Oct 18 olle 1953             //
5060 29 Oct 18 olle 1954             String itemName = ffpeSectionBlockName + ".s";
5060 29 Oct 18 olle 1955             Sample specimen = Sample.getNew(dc);
5060 29 Oct 18 olle 1956             specimen.setItemSubtype(Subtype.SPECIMEN.load(dc));
5060 29 Oct 18 olle 1957             specimen.setName(itemName);
5060 29 Oct 18 olle 1958             dc.saveItem(specimen);
5060 29 Oct 18 olle 1959
5060 29 Oct 18 olle 1960             BioMaterialEvent creationEvent = specimen.getCreationEvent();
5832 21 Feb 20 olle 1961             /*
5060 29 Oct 18 olle 1962             // Link the specimen with the case
5060 29 Oct 18 olle 1963             if (theCase != null)
5060 29 Oct 18 olle 1964             {
5060 29 Oct 18 olle 1965               creationEvent.setSource(theCase.getSample());
5060 29 Oct 18 olle 1966             }
5060 29 Oct 18 olle 1967             creationEvent.setEventDate(createDate);
5832 21 Feb 20 olle 1968             */
5060 29 Oct 18 olle 1969
5832 21 Feb 20 olle 1970             // Link the specimen with the FFPE block
5832 21 Feb 20 olle 1971             if (ffpeBlock != null)
5832 21 Feb 20 olle 1972             {
5832 21 Feb 20 olle 1973               creationEvent.setSource(ffpeBlock.getSample());
5832 21 Feb 20 olle 1974             }
5832 21 Feb 20 olle 1975             creationEvent.setEventDate(createDate);
5832 21 Feb 20 olle 1976
5060 29 Oct 18 olle 1977             // Update specimen with consent for case
5060 29 Oct 18 olle 1978             if (theCase != null)
5060 29 Oct 18 olle 1979             {
5060 29 Oct 18 olle 1980               Consent.copyConsentAnnotations(dc, theCase.getSample(), specimen);
5060 29 Oct 18 olle 1981             }
5060 29 Oct 18 olle 1982             
5060 29 Oct 18 olle 1983             // Update the specimen annotations
5060 29 Oct 18 olle 1984             Annotationtype.CASE_ID.setAnnotationValue(dc, specimen, caseName);
5060 29 Oct 18 olle 1985             Annotationtype.PAD.setAnnotationValue(dc, specimen, pad);
5114 20 Nov 18 olle 1986             Annotationtype.MATERIAL_NUMBER.setAnnotationValue(dc, specimen, materialNumber);
5060 29 Oct 18 olle 1987             Annotationtype.YELLOW_LABEL.setAnnotationValue(dc, specimen, yellowLabel);
5060 29 Oct 18 olle 1988             Annotationtype.NOF_SECTIONS.setAnnotationValue(dc, specimen, nofSections);
5060 29 Oct 18 olle 1989             //if (samplingDate != null) Annotationtype.SAMPLING_DATE.setAnnotationValue(dc, specimen, samplingDate);
5060 29 Oct 18 olle 1990             //if (arrivalDate != null) Annotationtype.ARRIVAL_DATE.setAnnotationValue(dc, specimen, arrivalDate);
5060 29 Oct 18 olle 1991             //if (operator != null) Annotationtype.ARRIVAL_OPERATOR.setAnnotationValue(dc, specimen, operator);
5060 29 Oct 18 olle 1992             Annotationtype.OPERATOR_DELIVERY_COMMENT.setAnnotationValue(dc, specimen, comment);
5060 29 Oct 18 olle 1993
5060 29 Oct 18 olle 1994             numUpdatedFfpeSections++;
5060 29 Oct 18 olle 1995             jsonMessages.add("Specimen item '" + specimen.getName() + "' [PAD = " + pad + " case = " + caseName + "] created successfully.");
5114 20 Nov 18 olle 1996
5114 20 Nov 18 olle 1997             // DNA extract from specimen
5114 20 Nov 18 olle 1998             Extract dna = Extract.getNew(dc);
5114 20 Nov 18 olle 1999             dna.setItemSubtype(Subtype.DNA.load(dc));
5114 20 Nov 18 olle 2000             dna.setName(itemName + ".d");
5114 20 Nov 18 olle 2001             BioMaterialEvent dnaEvent = dna.getCreationEvent();
5114 20 Nov 18 olle 2002             dnaEvent.setSource(specimen);
5114 20 Nov 18 olle 2003             dc.saveItem(dna);
5114 20 Nov 18 olle 2004             // Get bioWell if it is specified for DNA extract
5114 20 Nov 18 olle 2005             BioWell dnaWell = fetchBioWell(dc, jsonFfpeSection, bioPlateNamePlateHashMap, "DNA");
5114 20 Nov 18 olle 2006             // Set storage space for DNA, if former is valid
5114 20 Nov 18 olle 2007             if (dnaWell != null)
5114 20 Nov 18 olle 2008             {
5114 20 Nov 18 olle 2009               dna.setBioWell(dnaWell);              
5114 20 Nov 18 olle 2010             }
5114 20 Nov 18 olle 2011             jsonMessages.add("DNA extract '" + dna.getName() + "' created successfully.");
5114 20 Nov 18 olle 2012
5114 20 Nov 18 olle 2013             // RNA extract from specimen
5114 20 Nov 18 olle 2014             Extract rna = Extract.getNew(dc);
5114 20 Nov 18 olle 2015             rna.setItemSubtype(Subtype.RNA.load(dc));
5114 20 Nov 18 olle 2016             rna.setName(itemName + ".r");
5114 20 Nov 18 olle 2017             BioMaterialEvent rnaEvent = rna.getCreationEvent();
5114 20 Nov 18 olle 2018             rnaEvent.setSource(specimen);
5114 20 Nov 18 olle 2019             dc.saveItem(rna);
5114 20 Nov 18 olle 2020             // Get bioWell if it is specified for RNA extract
5114 20 Nov 18 olle 2021             BioWell rnaWell = fetchBioWell(dc, jsonFfpeSection, bioPlateNamePlateHashMap, "RNA");
5114 20 Nov 18 olle 2022             // Set storage space for RNA, if former is valid
5114 20 Nov 18 olle 2023             if (rnaWell != null)
5114 20 Nov 18 olle 2024             {
5114 20 Nov 18 olle 2025               rna.setBioWell(rnaWell);              
5114 20 Nov 18 olle 2026             }
5114 20 Nov 18 olle 2027             jsonMessages.add("RNA extract '" + rna.getName() + "' created successfully.");
5114 20 Nov 18 olle 2028
5114 20 Nov 18 olle 2029             //#######################################
5114 20 Nov 18 olle 2030             // Histology and H&E glass bioplate items
5114 20 Nov 18 olle 2031
5114 20 Nov 18 olle 2032             AnnotationType ihc = Annotationtype.IHC.get(dc);
5114 20 Nov 18 olle 2033
5114 20 Nov 18 olle 2034             //-------------------------------
5114 20 Nov 18 olle 2035             // Create histology item
5114 20 Nov 18 olle 2036             Sample histology = Sample.getNew(dc);
5114 20 Nov 18 olle 2037             histology.setItemSubtype(Subtype.HISTOLOGY.load(dc));
5114 20 Nov 18 olle 2038             histology.setName(itemName + ".his");
5114 20 Nov 18 olle 2039             dc.saveItem(histology);
5114 20 Nov 18 olle 2040
5114 20 Nov 18 olle 2041             // Update histology annotations
5114 20 Nov 18 olle 2042             Annotationtype.CASE_ID.setAnnotationValue(dc, histology, caseName);
5114 20 Nov 18 olle 2043             jsonMessages.add("Histology item '" + histology.getName() + "' created successfully.");
5114 20 Nov 18 olle 2044             
5114 20 Nov 18 olle 2045             //-------------------------------
5114 20 Nov 18 olle 2046             // Create a new HE glass item "F"
5126 21 Nov 18 olle 2047             String heGlassFName = ffpeSectionBlockName + ".F";
5114 20 Nov 18 olle 2048             BioPlate heGlassF = BioPlate.getNew(dc, BioplateType.HE_GLASS.getPlateGeometry(dc), BioplateType.HE_GLASS.load(dc));
5114 20 Nov 18 olle 2049             heGlassF.setName(heGlassFName); // Safe, since we just made a check if the HEglass exists or not
5114 20 Nov 18 olle 2050             //heGlassF.setEventDate(stainDate);
5114 20 Nov 18 olle 2051             dc.saveItem(heGlassF);
5114 20 Nov 18 olle 2052             
5114 20 Nov 18 olle 2053             // Create bioplate event
5114 20 Nov 18 olle 2054             BioPlateEventType createBioMaterial = BioPlateEventType.getById(dc, BioPlateEventType.CREATE_BIOMATERIAL);
5114 20 Nov 18 olle 2055             BioPlateEvent stainEvent = BioPlateEvent.getNew(dc, createBioMaterial);
5114 20 Nov 18 olle 2056             stainEvent.setName("HE stain");
5114 20 Nov 18 olle 2057             stainEvent.addParticipant(heGlassF, "paraffin-block", 1);
5114 20 Nov 18 olle 2058             //stainEvent.setEventDate(stainDate);
5114 20 Nov 18 olle 2059             //stainEvent.setProtocol(protocol);
5114 20 Nov 18 olle 2060             dc.saveItem(stainEvent);
5114 20 Nov 18 olle 2061             int stainNo = 1;
5114 20 Nov 18 olle 2062
5114 20 Nov 18 olle 2063             BioPlateEventParticipant stainEventParticipant = stainEvent.addParticipant(heGlassF, "glass", stainNo);
5114 20 Nov 18 olle 2064           
5114 20 Nov 18 olle 2065             heGlassF.setTray(heGlassFBox);
5114 20 Nov 18 olle 2066             heGlassF.setPosition(heGlassFPosition);
5114 20 Nov 18 olle 2067             //heGlassF.setDescription(comment);
5114 20 Nov 18 olle 2068             //Annotationtype.IHC.setAnnotationValue(dc, heGlassF, ihc);
5114 20 Nov 18 olle 2069
5114 20 Nov 18 olle 2070             // Create new child biomaterial
5114 20 Nov 18 olle 2071             String stainedName = itemName + ".he" + ".F";
5114 20 Nov 18 olle 2072             MeasuredBioMaterial stained = Sample.getNew(dc, stainEventParticipant);
5114 20 Nov 18 olle 2073             stained.setItemSubtype(Subtype.STAINED.load(dc));
5114 20 Nov 18 olle 2074             stained.setName(stainedName); // Safe, since this is a new stain
5114 20 Nov 18 olle 2075             stained.setDescription(histology.getDescription());
5114 20 Nov 18 olle 2076             dc.saveItem(stained);
5114 20 Nov 18 olle 2077
5832 21 Feb 20 olle 2078             //Annotationtype.TUMOUR_CELLS_PERCENT.setAnnotationValue(dc, stained, pctTumourCellsF);
5114 20 Nov 18 olle 2079             // Get location for stain on glass plate
5114 20 Nov 18 olle 2080             BioWell stainedFWell = heGlassF.getBioWell(0, 0);
5114 20 Nov 18 olle 2081             // Set storage space for F-stain, if former is valid
5114 20 Nov 18 olle 2082             if (stainedFWell != null)
5114 20 Nov 18 olle 2083             {
5114 20 Nov 18 olle 2084               stained.setBioWell(stainedFWell);              
5114 20 Nov 18 olle 2085             }
5114 20 Nov 18 olle 2086             creationEvent = stained.getCreationEvent();
5114 20 Nov 18 olle 2087             creationEvent.setSource(histology);
5114 20 Nov 18 olle 2088             //creationEvent.setEventDate(stainDate);
5114 20 Nov 18 olle 2089             jsonMessages.add("HE stain '" + stained.getName() + "' created successfully.");
5114 20 Nov 18 olle 2090
5114 20 Nov 18 olle 2091             //-------------------------------
5114 20 Nov 18 olle 2092             // Create a new HE glass item "E"
5126 21 Nov 18 olle 2093             String heGlassEName = ffpeSectionBlockName + ".E";
5114 20 Nov 18 olle 2094             BioPlate heGlassE = BioPlate.getNew(dc, BioplateType.HE_GLASS.getPlateGeometry(dc), BioplateType.HE_GLASS.load(dc));
5114 20 Nov 18 olle 2095             heGlassE.setName(heGlassEName); // Safe, since we just made a check if the HEglass exists or not
5114 20 Nov 18 olle 2096             //heGlassE.setEventDate(stainDate);
5114 20 Nov 18 olle 2097             dc.saveItem(heGlassE);
5114 20 Nov 18 olle 2098             
5114 20 Nov 18 olle 2099             // Create bioplate event
5114 20 Nov 18 olle 2100             createBioMaterial = BioPlateEventType.getById(dc, BioPlateEventType.CREATE_BIOMATERIAL);
5114 20 Nov 18 olle 2101             stainEvent = BioPlateEvent.getNew(dc, createBioMaterial);
5114 20 Nov 18 olle 2102             stainEvent.setName("HE stain");
5114 20 Nov 18 olle 2103             stainEvent.addParticipant(heGlassE, "paraffin-block", 1);
5114 20 Nov 18 olle 2104             //stainEvent.setEventDate(stainDate);
5114 20 Nov 18 olle 2105             //stainEvent.setProtocol(protocol);
5114 20 Nov 18 olle 2106             dc.saveItem(stainEvent);
5114 20 Nov 18 olle 2107             stainNo = 1;
5114 20 Nov 18 olle 2108
5114 20 Nov 18 olle 2109             stainEventParticipant = stainEvent.addParticipant(heGlassE, "glass", stainNo);
5114 20 Nov 18 olle 2110           
5114 20 Nov 18 olle 2111             heGlassE.setTray(heGlassEBox);
5114 20 Nov 18 olle 2112             heGlassE.setPosition(heGlassEPosition);
5114 20 Nov 18 olle 2113             //heGlassE.setDescription(comment);
5114 20 Nov 18 olle 2114             //Annotationtype.IHC.setAnnotationValue(dc, heGlassE, ihc);
5114 20 Nov 18 olle 2115
5114 20 Nov 18 olle 2116             // Create new child biomaterial
5114 20 Nov 18 olle 2117             stainedName = itemName + ".he" + ".E";
5114 20 Nov 18 olle 2118             stained = Sample.getNew(dc, stainEventParticipant);
5114 20 Nov 18 olle 2119             stained.setItemSubtype(Subtype.STAINED.load(dc));
5114 20 Nov 18 olle 2120             stained.setName(stainedName); // Safe, since this is a new stain
5114 20 Nov 18 olle 2121             stained.setDescription(histology.getDescription());
5114 20 Nov 18 olle 2122             dc.saveItem(stained);
5114 20 Nov 18 olle 2123
5832 21 Feb 20 olle 2124             //Annotationtype.TUMOUR_CELLS_PERCENT.setAnnotationValue(dc, stained, pctTumourCellsE);
5114 20 Nov 18 olle 2125             // Get location for stain on glass plate
5114 20 Nov 18 olle 2126             BioWell stainedEWell = heGlassE.getBioWell(0, 0);
5114 20 Nov 18 olle 2127             // Set storage space for E-stain, if former is valid
5114 20 Nov 18 olle 2128             if (stainedEWell != null)
5114 20 Nov 18 olle 2129             {
5114 20 Nov 18 olle 2130               stained.setBioWell(stainedEWell);              
5114 20 Nov 18 olle 2131             }
5114 20 Nov 18 olle 2132             creationEvent = stained.getCreationEvent();
5114 20 Nov 18 olle 2133             creationEvent.setSource(histology);
5114 20 Nov 18 olle 2134             //creationEvent.setEventDate(stainDate);
5114 20 Nov 18 olle 2135             jsonMessages.add("HE stain '" + stained.getName() + "' created successfully.");
5114 20 Nov 18 olle 2136
5061 30 Oct 18 olle 2137             // Update the FFPE block annotations
5061 30 Oct 18 olle 2138             Annotationtype.USED_FOR_FFPE_SECTION.setAnnotationValue(dc, ffpeBlock.getSample(), Boolean.TRUE);
5060 29 Oct 18 olle 2139           }
5060 29 Oct 18 olle 2140           jsonMessages.add(numUpdatedFfpeSections + " Specimen(s) updated.");
5060 29 Oct 18 olle 2141         }
5060 29 Oct 18 olle 2142         dc.commit();
5060 29 Oct 18 olle 2143         json.put("messages", jsonMessages);
5060 29 Oct 18 olle 2144         CounterService.getInstance().setForceCount();
5060 29 Oct 18 olle 2145       }
5848 02 Mar 20 olle 2146       else if ("RegisterFFPESectionTumourCellPct".equals(cmd))
5848 02 Mar 20 olle 2147       {
5848 02 Mar 20 olle 2148         dc = sc.newDbControl();
5848 02 Mar 20 olle 2149
5848 02 Mar 20 olle 2150         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
5848 02 Mar 20 olle 2151
5848 02 Mar 20 olle 2152         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
5848 02 Mar 20 olle 2153         JSONObject jsonFfpeSectionTot = (JSONObject)jsonReq.get("ffpeSectionInfo");
5848 02 Mar 20 olle 2154         JSONArray jsonFfpeSections = (JSONArray)jsonFfpeSectionTot.get("ffpeSections");
5848 02 Mar 20 olle 2155
5848 02 Mar 20 olle 2156         // Register the FFPE section (specimen) tumour cell percentage
5848 02 Mar 20 olle 2157         int numUpdatedFfpeSections = 0;
5848 02 Mar 20 olle 2158         if (jsonFfpeSections != null && jsonFfpeSections.size() > 0)
5848 02 Mar 20 olle 2159         {
5848 02 Mar 20 olle 2160           HashMap<String, BioPlate> bioPlateNamePlateHashMap = new HashMap<String, BioPlate>();
5848 02 Mar 20 olle 2161           for (int i = 0; i < jsonFfpeSections.size(); ++i)
5848 02 Mar 20 olle 2162           {
5848 02 Mar 20 olle 2163             JSONObject jsonFfpeSection = (JSONObject)jsonFfpeSections.get(i);
5848 02 Mar 20 olle 2164             String ffpeSectionName = (String)jsonFfpeSection.get("name");
5848 02 Mar 20 olle 2165             int pctTumourCellsF = Integer.parseInt((String)jsonFfpeSection.get("pctTumourCellsF"));
5848 02 Mar 20 olle 2166             int pctTumourCellsE = Integer.parseInt((String)jsonFfpeSection.get("pctTumourCellsE"));
5848 02 Mar 20 olle 2167
5848 02 Mar 20 olle 2168             // Create new child biomaterial
5848 02 Mar 20 olle 2169             String itemName = ffpeSectionName;
5848 02 Mar 20 olle 2170             String stainedName = itemName + ".he" + ".F";
5848 02 Mar 20 olle 2171             
5848 02 Mar 20 olle 2172             // Look for a stain with the given name 
5848 02 Mar 20 olle 2173             MeasuredBioMaterial stained = null;
5848 02 Mar 20 olle 2174             ItemQuery<Sample> stainQuery = Sample.getQuery();
5848 02 Mar 20 olle 2175             Subtype.STAINED.addFilter(dc, stainQuery);
5848 02 Mar 20 olle 2176             stainQuery.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", stainedName, Type.STRING)));
5848 02 Mar 20 olle 2177             List<Sample> stainSamples = stainQuery.list(dc);
5848 02 Mar 20 olle 2178             if (stainSamples.size() == 1)
5848 02 Mar 20 olle 2179             {
5848 02 Mar 20 olle 2180               stained = Sample.getById(dc, stainSamples.get(0).getId());
5848 02 Mar 20 olle 2181             }
5848 02 Mar 20 olle 2182             stained.setItemSubtype(Subtype.STAINED.load(dc));
5848 02 Mar 20 olle 2183
5848 02 Mar 20 olle 2184             Annotationtype.TUMOUR_CELLS_PERCENT.setAnnotationValue(dc, stained, pctTumourCellsF);
5848 02 Mar 20 olle 2185             jsonMessages.add("HE stain '" + stained.getName() + "' updated with tumour cell percentage " + pctTumourCellsF + " successfully.");
5848 02 Mar 20 olle 2186
5848 02 Mar 20 olle 2187             stainedName = itemName + ".he" + ".E";
5848 02 Mar 20 olle 2188             
5848 02 Mar 20 olle 2189             // Look for a stain with the given name 
5848 02 Mar 20 olle 2190             stained = null;
5848 02 Mar 20 olle 2191             stainQuery = Sample.getQuery();
5848 02 Mar 20 olle 2192             Subtype.STAINED.addFilter(dc, stainQuery);
5848 02 Mar 20 olle 2193             stainQuery.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", stainedName, Type.STRING)));
5848 02 Mar 20 olle 2194             stainSamples = stainQuery.list(dc);
5848 02 Mar 20 olle 2195             if (stainSamples.size() == 1)
5848 02 Mar 20 olle 2196             {
5848 02 Mar 20 olle 2197               stained = Sample.getById(dc, stainSamples.get(0).getId());
5848 02 Mar 20 olle 2198             }
5848 02 Mar 20 olle 2199             stained.setItemSubtype(Subtype.STAINED.load(dc));
5848 02 Mar 20 olle 2200
5848 02 Mar 20 olle 2201             Annotationtype.TUMOUR_CELLS_PERCENT.setAnnotationValue(dc, stained, pctTumourCellsE);
5848 02 Mar 20 olle 2202             jsonMessages.add("HE stain '" + stained.getName() + "' updated with tumour cell percentage " + pctTumourCellsE + " successfully.");
5848 02 Mar 20 olle 2203
5848 02 Mar 20 olle 2204             // Update the FFPE block annotations
5848 02 Mar 20 olle 2205             //Annotationtype.USED_FOR_FFPE_SECTION.setAnnotationValue(dc, ffpeBlock.getSample(), Boolean.TRUE);
5848 02 Mar 20 olle 2206           }
5848 02 Mar 20 olle 2207           jsonMessages.add(numUpdatedFfpeSections + " Specimen(s) updated.");
5848 02 Mar 20 olle 2208         }
5848 02 Mar 20 olle 2209         dc.commit();
5848 02 Mar 20 olle 2210         json.put("messages", jsonMessages);
5848 02 Mar 20 olle 2211         CounterService.getInstance().setForceCount();
5848 02 Mar 20 olle 2212       }
5062 30 Oct 18 olle 2213       else if ("RegisterReturnedFFPEBlocks".equals(cmd))
5062 30 Oct 18 olle 2214       {
5062 30 Oct 18 olle 2215         dc = sc.newDbControl();
5062 30 Oct 18 olle 2216
5062 30 Oct 18 olle 2217         MeludiRole.checkPermission(dc, "'" + cmd + "' wizard", MeludiRole.PATIENT_CURATOR, MeludiRole.ADMINISTRATOR);
5062 30 Oct 18 olle 2218
5062 30 Oct 18 olle 2219         JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
5062 30 Oct 18 olle 2220         JSONObject jsonFfpeBlockTot = (JSONObject)jsonReq.get("ffpeBlockInfo");
5062 30 Oct 18 olle 2221         JSONArray jsonFfpeBlocks = (JSONArray)jsonFfpeBlockTot.get("ffpeBlocks");
5062 30 Oct 18 olle 2222
5062 30 Oct 18 olle 2223         // Get date of FFPE block return
5062 30 Oct 18 olle 2224         String returnedDateString = (String)jsonFfpeBlockTot.get("returnedDate");
5062 30 Oct 18 olle 2225         returnedDateString = returnedDateString.replaceAll("-", "");
5062 30 Oct 18 olle 2226         Date returnedDate = Meludi.CONVERTER_STRING_TO_DATE.convert(returnedDateString);
5062 30 Oct 18 olle 2227
5062 30 Oct 18 olle 2228         // Register the returned FFPE blocks
5062 30 Oct 18 olle 2229         int numUpdatedFfpeBlocks = 0;
5062 30 Oct 18 olle 2230         if (jsonFfpeBlocks != null && jsonFfpeBlocks.size() > 0)
5062 30 Oct 18 olle 2231         {
5062 30 Oct 18 olle 2232           for (int i = 0; i < jsonFfpeBlocks.size(); ++i)
5062 30 Oct 18 olle 2233           {
5062 30 Oct 18 olle 2234             JSONObject jsonFfpeBlock = (JSONObject)jsonFfpeBlocks.get(i);
5062 30 Oct 18 olle 2235             String ffpeBlockName = (String)jsonFfpeBlock.get("name");
5062 30 Oct 18 olle 2236             FfpeBlock ffpeBlock = FfpeBlock.getByName(dc, ffpeBlockName);
5062 30 Oct 18 olle 2237             if (ffpeBlock != null)
5062 30 Oct 18 olle 2238             {
5062 30 Oct 18 olle 2239               // Update the FFPE block annotations
5062 30 Oct 18 olle 2240               Annotationtype.RETURNED_DATE.setAnnotationValue(dc, ffpeBlock.getSample(), returnedDate);
5062 30 Oct 18 olle 2241               numUpdatedFfpeBlocks++;
5062 30 Oct 18 olle 2242             }
5062 30 Oct 18 olle 2243           }
5062 30 Oct 18 olle 2244           jsonMessages.add(numUpdatedFfpeBlocks + " FFPE block(s) updated.");
5062 30 Oct 18 olle 2245         }
5062 30 Oct 18 olle 2246         dc.commit();
5062 30 Oct 18 olle 2247         json.put("messages", jsonMessages);
5062 30 Oct 18 olle 2248         CounterService.getInstance().setForceCount();
5062 30 Oct 18 olle 2249       }
4832 05 Jun 18 olle 2250     }
4832 05 Jun 18 olle 2251     catch (Throwable t)
4832 05 Jun 18 olle 2252     {
4832 05 Jun 18 olle 2253       t.printStackTrace();
4832 05 Jun 18 olle 2254       json.clear();
4832 05 Jun 18 olle 2255       json.put("status", "error");
4832 05 Jun 18 olle 2256       json.put("message", t.getMessage());
4832 05 Jun 18 olle 2257       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
4832 05 Jun 18 olle 2258     }
4832 05 Jun 18 olle 2259     finally
4832 05 Jun 18 olle 2260     {
4832 05 Jun 18 olle 2261       if (dc != null) dc.close();
4832 05 Jun 18 olle 2262       json.writeJSONString(resp.getWriter());
4832 05 Jun 18 olle 2263     }
4832 05 Jun 18 olle 2264   }
4832 05 Jun 18 olle 2265   
4832 05 Jun 18 olle 2266   private void setAnnotations(DbControl dc, Annotatable item, JSONObject jsonCase, int nofSections, String operatorComment)
4832 05 Jun 18 olle 2267   {
4832 05 Jun 18 olle 2268     String tubeContentType = Values.getStringOrNull((String)jsonCase.get("tubeContentType"));
4832 05 Jun 18 olle 2269     String specimenType = Values.getStringOrNull((String)jsonCase.get("specimenType"));
4832 05 Jun 18 olle 2270     String specimenInputType = Values.getStringOrNull((String)jsonCase.get("specimenInputType"));
4832 05 Jun 18 olle 2271     StringToDateConverter dateConverter = new StringToDateConverter(new SimpleDateFormat("yyyyMMdd"));        
4832 05 Jun 18 olle 2272     Date arrivalDate = dateConverter.convert((String)jsonCase.get("arrivalDate"));        
4832 05 Jun 18 olle 2273     Date samplingDate = dateConverter.convert((String)jsonCase.get("samplingDate"));
4832 05 Jun 18 olle 2274     Integer viableTumourCellsPercent = null;
4832 05 Jun 18 olle 2275     String viableTumourCellsPercentString = (String)jsonCase.get("viableTumourCellsPercent");
4832 05 Jun 18 olle 2276     if (viableTumourCellsPercentString != null && !viableTumourCellsPercentString.equals(""))
4832 05 Jun 18 olle 2277     {
4832 05 Jun 18 olle 2278       viableTumourCellsPercent = Integer.parseInt(viableTumourCellsPercentString);
4832 05 Jun 18 olle 2279     }
4832 05 Jun 18 olle 2280     if (tubeContentType != null && tubeContentType.equals("Specimen"))
4832 05 Jun 18 olle 2281     {
4832 05 Jun 18 olle 2282       Annotationtype.NOF_SECTIONS.setAnnotationValue(dc, item, nofSections);
4832 05 Jun 18 olle 2283       Annotationtype.SPECIMEN_TYPE.setAnnotationValue(dc, item, specimenType);
4832 05 Jun 18 olle 2284       Annotationtype.SPECIMEN_INPUT_TYPE.setAnnotationValue(dc, item, specimenInputType);
4832 05 Jun 18 olle 2285       // The following annotations should not necessarily be restricted to specimens
4832 05 Jun 18 olle 2286       Annotationtype.ARRIVAL_DATE.setAnnotationValue(dc, item, arrivalDate);            
4832 05 Jun 18 olle 2287       Annotationtype.SAMPLING_DATE.setAnnotationValue(dc, item, samplingDate);
4832 05 Jun 18 olle 2288       Annotationtype.VIABLE_TUMOUR_CELLS_PERCENT.setAnnotationValue(dc, item, viableTumourCellsPercent);
4832 05 Jun 18 olle 2289       Annotationtype.OPERATOR_DELIVERY_COMMENT.setAnnotationValue(dc, item, operatorComment);  
4832 05 Jun 18 olle 2290     }
4832 05 Jun 18 olle 2291     else if (tubeContentType != null)
4832 05 Jun 18 olle 2292     {
4832 05 Jun 18 olle 2293       Annotationtype.SPECIMEN_TYPE_EXTRACT.setAnnotationValue(dc, item, specimenType);
4832 05 Jun 18 olle 2294       Annotationtype.ARRIVAL_DATE_EXTRACT.setAnnotationValue(dc, item, arrivalDate);            
4832 05 Jun 18 olle 2295       Annotationtype.SAMPLING_DATE_EXTRACT.setAnnotationValue(dc, item, samplingDate);
4832 05 Jun 18 olle 2296       Annotationtype.VIABLE_TUMOUR_CELLS_PERCENT_EXTRACT.setAnnotationValue(dc, item, viableTumourCellsPercent);
4832 05 Jun 18 olle 2297       Annotationtype.OPERATOR_DELIVERY_COMMENT_EXTRACT.setAnnotationValue(dc, item, operatorComment);  
4832 05 Jun 18 olle 2298     }
4832 05 Jun 18 olle 2299   }
4832 05 Jun 18 olle 2300
4958 03 Sep 18 olle 2301   /**
5044 19 Oct 18 olle 2302    * Fetches new item name of items of specified subtype
5044 19 Oct 18 olle 2303    * for the active project, equal to the one following the
5044 19 Oct 18 olle 2304    * currently highest item name.
4958 03 Sep 18 olle 2305    * 
4958 03 Sep 18 olle 2306    * @param dc DbControl The DbControl object to use.
5044 19 Oct 18 olle 2307    * @param subtype Subtype Sample subtype for the item of interest.
5044 19 Oct 18 olle 2308    * @param itemPrefix String Item name prefix for the item of interest.
5044 19 Oct 18 olle 2309    * @param itemNumDigits String Item name number of digits for the item of interest.
5044 19 Oct 18 olle 2310    * @return String The new FFPE block item name.
4958 03 Sep 18 olle 2311    */
5044 19 Oct 18 olle 2312   private String fetchNewItemName(DbControl dc, Subtype subtype, String itemPrefix, int itemNumDigits)
4958 03 Sep 18 olle 2313   {
4958 03 Sep 18 olle 2314     SessionControl sc = dc.getSessionControl();
5044 19 Oct 18 olle 2315     // Get highest current item number
5044 19 Oct 18 olle 2316     int highestItemNumber = 0;
5044 19 Oct 18 olle 2317     String highestItemName = fetchHighestItemName(dc, subtype);
5044 19 Oct 18 olle 2318     if (highestItemName != null)
4958 03 Sep 18 olle 2319     {
5044 19 Oct 18 olle 2320       // Get base name (name without suffix) for highest item for case
5044 19 Oct 18 olle 2321       String highestItemBaseName = null;
5044 19 Oct 18 olle 2322       int dotIndex = highestItemName.indexOf(".");
5000 03 Oct 18 olle 2323       if (dotIndex > -1)
5000 03 Oct 18 olle 2324       {
5044 19 Oct 18 olle 2325         highestItemBaseName = highestItemName.substring(0, dotIndex);
5000 03 Oct 18 olle 2326       }
5044 19 Oct 18 olle 2327       // Remove item prefix
5044 19 Oct 18 olle 2328       int prefixLength = itemPrefix.length();
5044 19 Oct 18 olle 2329       String highestItemNumString = highestItemBaseName.substring(prefixLength);
5044 19 Oct 18 olle 2330       // Remove leading zeroes in item number
5044 19 Oct 18 olle 2331       while (highestItemNumString.indexOf("0") == 0)
4958 03 Sep 18 olle 2332       {
5044 19 Oct 18 olle 2333         highestItemNumString = highestItemNumString.substring(1);
4958 03 Sep 18 olle 2334       }
5044 19 Oct 18 olle 2335       // Get highest current item number as integer
5044 19 Oct 18 olle 2336       highestItemNumber = Integer.parseUnsignedInt(highestItemNumString);
4958 03 Sep 18 olle 2337     }
5044 19 Oct 18 olle 2338     // Get new item number
5044 19 Oct 18 olle 2339     int newItemNumber = highestItemNumber + 1;
5044 19 Oct 18 olle 2340     // Get new item number string with leading zeroes
5044 19 Oct 18 olle 2341     String newItemNumString = "" + newItemNumber;
5044 19 Oct 18 olle 2342     while (newItemNumString.length() < itemNumDigits)
4958 03 Sep 18 olle 2343     {
5044 19 Oct 18 olle 2344       newItemNumString = "0" + newItemNumString;
4958 03 Sep 18 olle 2345     }
5044 19 Oct 18 olle 2346     // Get new item name
5044 19 Oct 18 olle 2347     String newItemName = itemPrefix + newItemNumString + ".1";
5044 19 Oct 18 olle 2348     return newItemName;
4958 03 Sep 18 olle 2349   }
4958 03 Sep 18 olle 2350
4958 03 Sep 18 olle 2351   /**
5044 19 Oct 18 olle 2352    * Fetches highest item number of items of specified subtype
5044 19 Oct 18 olle 2353    * for the active project, equal to number of the currently
5044 19 Oct 18 olle 2354    * highest item name.
4958 03 Sep 18 olle 2355    * 
4958 03 Sep 18 olle 2356    * @param dc DbControl The DbControl object to use.
5044 19 Oct 18 olle 2357    * @param subtype Subtype Sample subtype for the item of interest.
5044 19 Oct 18 olle 2358    * @param itemPrefix String Item name prefix for the item of interest.
5044 19 Oct 18 olle 2359    * @param itemNumDigits String Item name number of digits for the item of interest.
5044 19 Oct 18 olle 2360    * @return int The highest item number.
4958 03 Sep 18 olle 2361    */
5044 19 Oct 18 olle 2362   private int fetchHighestItemNumber(DbControl dc, Subtype subtype, String itemPrefix, int itemNumDigits)
4958 03 Sep 18 olle 2363   {
4958 03 Sep 18 olle 2364     SessionControl sc = dc.getSessionControl();
5044 19 Oct 18 olle 2365     // Get highest current item number
5044 19 Oct 18 olle 2366     int highestItemNumber = 0;
5044 19 Oct 18 olle 2367     String highestItemName = fetchHighestItemName(dc, subtype);
5044 19 Oct 18 olle 2368     if (highestItemName != null)
4958 03 Sep 18 olle 2369     {
5044 19 Oct 18 olle 2370       // Remove item prefix
5044 19 Oct 18 olle 2371       int prefixLength = itemPrefix.length();
5044 19 Oct 18 olle 2372       String highestItemNumString = highestItemName.substring(prefixLength);
5044 19 Oct 18 olle 2373       // Remove leading zeroes in item number
5044 19 Oct 18 olle 2374       while (highestItemNumString.indexOf("0") == 0)
4958 03 Sep 18 olle 2375       {
5044 19 Oct 18 olle 2376         highestItemNumString = highestItemNumString.substring(1);
4958 03 Sep 18 olle 2377       }
5044 19 Oct 18 olle 2378       // Get highest current item number as integer
5044 19 Oct 18 olle 2379       highestItemNumber = Integer.parseUnsignedInt(highestItemNumString);
4958 03 Sep 18 olle 2380     }
5044 19 Oct 18 olle 2381     return highestItemNumber;
4958 03 Sep 18 olle 2382   }
4958 03 Sep 18 olle 2383
4958 03 Sep 18 olle 2384   /**
5044 19 Oct 18 olle 2385    * Fetches the highest item name of items of specified subtype
5044 19 Oct 18 olle 2386    * for the active project, or `null`, if no items exist.
4958 03 Sep 18 olle 2387    * 
4958 03 Sep 18 olle 2388    * @param dc DbControl The DbControl object to use.
5044 19 Oct 18 olle 2389    * @param subtype Subtype Sample subtype for the item of interest.
5044 19 Oct 18 olle 2390    * @return String The highest item name, or `null` if no items exist.
4958 03 Sep 18 olle 2391    */
5044 19 Oct 18 olle 2392   private String fetchHighestItemName(DbControl dc, Subtype subtype)
4958 03 Sep 18 olle 2393   {
5044 19 Oct 18 olle 2394     String highestItemName = null;
4958 03 Sep 18 olle 2395     ItemQuery<Sample> query = Sample.getQuery();
5044 19 Oct 18 olle 2396     subtype.addFilter(dc, query);
4958 03 Sep 18 olle 2397     query.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT);
4958 03 Sep 18 olle 2398     query.setCacheResult(true);
4958 03 Sep 18 olle 2399     query.order(Orders.desc(Hql.property("name")));
5044 19 Oct 18 olle 2400     List<Sample> itemNames = query.list(dc);
5044 19 Oct 18 olle 2401     if (itemNames != null && itemNames.size() > 0)
4958 03 Sep 18 olle 2402     {
5044 19 Oct 18 olle 2403       Sample highestItem = (Sample) itemNames.get(0);
5044 19 Oct 18 olle 2404       highestItemName = highestItem.getName();
4958 03 Sep 18 olle 2405     }
5044 19 Oct 18 olle 2406     return highestItemName;
4958 03 Sep 18 olle 2407   }
4958 03 Sep 18 olle 2408
4832 05 Jun 18 olle 2409   private BioWell fetchBioWell(DbControl dc, JSONObject jsonSpec, HashMap<String, BioPlate> bioPlateNamePlateHashMap)
4832 05 Jun 18 olle 2410   {
4832 05 Jun 18 olle 2411     String boxType = null;
4832 05 Jun 18 olle 2412     BioWell well = fetchBioWell(dc, jsonSpec, bioPlateNamePlateHashMap, boxType);
4832 05 Jun 18 olle 2413     return well;
4832 05 Jun 18 olle 2414   }
4832 05 Jun 18 olle 2415
4832 05 Jun 18 olle 2416   private BioWell fetchBioWell(DbControl dc, JSONObject jsonSpec, HashMap<String, BioPlate> bioPlateNamePlateHashMap, String boxType)
4832 05 Jun 18 olle 2417   {
4832 05 Jun 18 olle 2418     BioWell well = null;
4832 05 Jun 18 olle 2419     String boxKey = "box";
4832 05 Jun 18 olle 2420     String rowKey = "row";
4832 05 Jun 18 olle 2421     String columnKey = "column";
4832 05 Jun 18 olle 2422     if (boxType != null && boxType.equals("DNA"))
4832 05 Jun 18 olle 2423     {
4832 05 Jun 18 olle 2424       boxKey = "dnaBox";
4832 05 Jun 18 olle 2425       rowKey = "dnaRow";
4832 05 Jun 18 olle 2426       columnKey = "dnaColumn";
4832 05 Jun 18 olle 2427     }
4832 05 Jun 18 olle 2428     else if (boxType != null && boxType.equals("RNA"))
4832 05 Jun 18 olle 2429     {
4832 05 Jun 18 olle 2430       boxKey = "rnaBox";
4832 05 Jun 18 olle 2431       rowKey = "rnaRow";
4832 05 Jun 18 olle 2432       columnKey = "rnaColumn";
4832 05 Jun 18 olle 2433     }
4832 05 Jun 18 olle 2434     // Set biowell if it is specified for this tube
4832 05 Jun 18 olle 2435     String box = (String)jsonSpec.get(boxKey);
4832 05 Jun 18 olle 2436     String rowString = (String)jsonSpec.get(rowKey);
4832 05 Jun 18 olle 2437     String columnString = (String)jsonSpec.get(columnKey);
4832 05 Jun 18 olle 2438     
4832 05 Jun 18 olle 2439     BioPlate plate = null;
4832 05 Jun 18 olle 2440     StoragePlate storageBox = StoragePlate.findByName(dc, box);
4832 05 Jun 18 olle 2441     if (storageBox != null)
4832 05 Jun 18 olle 2442     {
4832 05 Jun 18 olle 2443       plate = storageBox.getBioPlate();
4832 05 Jun 18 olle 2444     }
4832 05 Jun 18 olle 2445     else if (box != null && !box.equals(""))
4832 05 Jun 18 olle 2446     {
4832 05 Jun 18 olle 2447       // Use already created new storage box, if existing
4832 05 Jun 18 olle 2448       plate = (BioPlate) bioPlateNamePlateHashMap.get(box);
4832 05 Jun 18 olle 2449       if (plate == null)
4832 05 Jun 18 olle 2450       {
4832 05 Jun 18 olle 2451         // Create new storage box
5152 28 Nov 18 olle 2452         if (boxType != null && boxType.equals("Blood"))
5152 28 Nov 18 olle 2453         {
5155 29 Nov 18 olle 2454           String geometryString = "100-well (10 x 10)";
5152 28 Nov 18 olle 2455           plate = createStorageBox(dc, box, geometryString);
5152 28 Nov 18 olle 2456         }
5152 28 Nov 18 olle 2457         else
5152 28 Nov 18 olle 2458         {
5152 28 Nov 18 olle 2459           // Create 81-well (9 x 9) box
5152 28 Nov 18 olle 2460           plate = createStorageBox(dc, box);
5152 28 Nov 18 olle 2461         }
4832 05 Jun 18 olle 2462         dc.saveItem(plate);
4832 05 Jun 18 olle 2463         // Update hash map with new plate
4832 05 Jun 18 olle 2464         bioPlateNamePlateHashMap.put(box, plate);
4832 05 Jun 18 olle 2465       }
4832 05 Jun 18 olle 2466     }
4832 05 Jun 18 olle 2467
4832 05 Jun 18 olle 2468     // Set storage space for specimen, if former is valid
4832 05 Jun 18 olle 2469     if (box != null && !box.equals("") && rowString != null && !rowString.equals("") && columnString != null && !columnString.equals(""))
4832 05 Jun 18 olle 2470     {
4832 05 Jun 18 olle 2471       WellCoordinateFormatter wcfRow = new WellCoordinateFormatter(true);
4832 05 Jun 18 olle 2472       Integer rowIndex = wcfRow.parseString(rowString)-1;
4832 05 Jun 18 olle 2473       Integer columnIndex = Integer.parseInt(columnString)-1;              
4832 05 Jun 18 olle 2474       well = plate.getBioWell(rowIndex, columnIndex);
4832 05 Jun 18 olle 2475     }
4832 05 Jun 18 olle 2476     return well;
4832 05 Jun 18 olle 2477   }
4832 05 Jun 18 olle 2478
4832 05 Jun 18 olle 2479   /**
4832 05 Jun 18 olle 2480    * Creates a storage box BioPlate item with a name having
4832 05 Jun 18 olle 2481    * given plate prefix, suffix, and number.
4832 05 Jun 18 olle 2482    * Note that the returned BioPlate item will not automatically
4832 05 Jun 18 olle 2483    * be stored in the database.
4832 05 Jun 18 olle 2484    * 
4832 05 Jun 18 olle 2485    * @param dc DbControl The DbControl to use
4832 05 Jun 18 olle 2486    * @param platePrefix String The plate prefix of the bioplate to create
4832 05 Jun 18 olle 2487    * @param plateNumDigits Integer The number of digits in the name of the bioplate to create
4832 05 Jun 18 olle 2488    * @param plateSuffix String The plate suffix of the bioplate to create
4832 05 Jun 18 olle 2489    * @param plateNumber int The plate number of the bioplate to create
4832 05 Jun 18 olle 2490    * @return BioPlate The created BioPlate item
4832 05 Jun 18 olle 2491    */
4832 05 Jun 18 olle 2492   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 2493   private BioPlate createStorageBox(DbControl dc, String platePrefix, Integer plateNumDigits, String plateSuffix, int plateNumber)
4832 05 Jun 18 olle 2494   {
4832 05 Jun 18 olle 2495     Integer numDigits = plateNumDigits;
4832 05 Jun 18 olle 2496     if (numDigits == null || numDigits < 1)
4832 05 Jun 18 olle 2497     {
4832 05 Jun 18 olle 2498       numDigits = 4;
4832 05 Jun 18 olle 2499     }
4832 05 Jun 18 olle 2500     // Get new plate name
4832 05 Jun 18 olle 2501     String plateNumberStr = "" + plateNumber;
4832 05 Jun 18 olle 2502     while (plateNumberStr.length() < numDigits)
4832 05 Jun 18 olle 2503     {
4832 05 Jun 18 olle 2504       plateNumberStr = "0" + plateNumberStr;
4832 05 Jun 18 olle 2505     }
4832 05 Jun 18 olle 2506     String plateName = platePrefix + plateNumberStr + plateSuffix;
4832 05 Jun 18 olle 2507     // Create new storage box
4832 05 Jun 18 olle 2508     BioPlate box = createStorageBox(dc, plateName);
4832 05 Jun 18 olle 2509     return box;
4832 05 Jun 18 olle 2510   }
4832 05 Jun 18 olle 2511
4832 05 Jun 18 olle 2512   /**
4832 05 Jun 18 olle 2513    * Creates a storage box BioPlate item with a given name.
4832 05 Jun 18 olle 2514    * Note that the returned BioPlate item will not automatically
4832 05 Jun 18 olle 2515    * be stored in the database.
4832 05 Jun 18 olle 2516    * 
4832 05 Jun 18 olle 2517    * @param dc DbControl The DbControl to use
4832 05 Jun 18 olle 2518    * @param plateName String Name of the bioplate to create
4832 05 Jun 18 olle 2519    * @return BioPlate The created BioPlate item
4832 05 Jun 18 olle 2520    */
4832 05 Jun 18 olle 2521   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 2522   private BioPlate createStorageBox(DbControl dc, String plateName)
4832 05 Jun 18 olle 2523   {  
4832 05 Jun 18 olle 2524     // Get plate geometry for storage box (81-well (9 x 9))
5152 28 Nov 18 olle 2525     String geometryString = "81-well (9 x 9)";
5152 28 Nov 18 olle 2526     BioPlate box = createStorageBox(dc, plateName, geometryString);
5152 28 Nov 18 olle 2527     return box;
5152 28 Nov 18 olle 2528   }
5152 28 Nov 18 olle 2529
5152 28 Nov 18 olle 2530   /**
5152 28 Nov 18 olle 2531    * Creates a storage box BioPlate item with a given name and geometry.
5152 28 Nov 18 olle 2532    * Note that the returned BioPlate item will not automatically
5152 28 Nov 18 olle 2533    * be stored in the database.
5152 28 Nov 18 olle 2534    * 
5152 28 Nov 18 olle 2535    * @param dc DbControl The DbControl to use
5152 28 Nov 18 olle 2536    * @param plateName String Name of the bioplate to create
5152 28 Nov 18 olle 2537    * @param geometryString String Description of the bioplate geometry to create for use in query
5152 28 Nov 18 olle 2538    * @return BioPlate The created BioPlate item
5152 28 Nov 18 olle 2539    */
5152 28 Nov 18 olle 2540   @SuppressWarnings("unchecked")
5152 28 Nov 18 olle 2541   private BioPlate createStorageBox(DbControl dc, String plateName, String geometryString)
5152 28 Nov 18 olle 2542   {  
5152 28 Nov 18 olle 2543     // Get plate geometry for storage box (81-well (9 x 9))
4832 05 Jun 18 olle 2544     ItemQuery<PlateGeometry> plateGeometryQuery = PlateGeometry.getQuery();
5152 28 Nov 18 olle 2545     plateGeometryQuery.restrict(Restrictions.eq(Hql.property("name"), Expressions.string(geometryString)));
4832 05 Jun 18 olle 2546     ItemResultList<PlateGeometry> plateGeometryList = plateGeometryQuery.list(dc);
4832 05 Jun 18 olle 2547     PlateGeometry geometry = null;
4832 05 Jun 18 olle 2548     if (plateGeometryList != null && plateGeometryList.size() > 0)
4832 05 Jun 18 olle 2549     {
4832 05 Jun 18 olle 2550       geometry = (PlateGeometry) plateGeometryList.get(0);
4832 05 Jun 18 olle 2551     }
4832 05 Jun 18 olle 2552     // Get bioplate type for storage plate (Storage plate)
4832 05 Jun 18 olle 2553     ItemQuery<BioPlateType> bioPlateTypeQuery = BioPlateType.getQuery();
4832 05 Jun 18 olle 2554     bioPlateTypeQuery.restrict(Restrictions.eq(Hql.property("name"), Expressions.string("Storage plate")));
4832 05 Jun 18 olle 2555     ItemResultList<BioPlateType> bioPlateTypeList = bioPlateTypeQuery.list(dc);
4832 05 Jun 18 olle 2556     BioPlateType plateType = null;
4832 05 Jun 18 olle 2557     if (bioPlateTypeList != null && bioPlateTypeList.size() > 0)
4832 05 Jun 18 olle 2558     {
4832 05 Jun 18 olle 2559       plateType = (BioPlateType) bioPlateTypeList.get(0);
4832 05 Jun 18 olle 2560     }
4832 05 Jun 18 olle 2561     // Create new storage box
4832 05 Jun 18 olle 2562     BioPlate box = BioPlate.getNew(dc, geometry, plateType);
4832 05 Jun 18 olle 2563     box.setName(plateName);
4832 05 Jun 18 olle 2564     return box;
4832 05 Jun 18 olle 2565   }
4832 05 Jun 18 olle 2566
4832 05 Jun 18 olle 2567   @SuppressWarnings("unchecked")
4832 05 Jun 18 olle 2568   private BioSource getOrCreatePatient(DbControl dc, JSONObject jsonPat, JSONArray jsonMessages)
4832 05 Jun 18 olle 2569     throws Exception
4832 05 Jun 18 olle 2570   {
4832 05 Jun 18 olle 2571     Number patientId = (Number)jsonPat.get("id");
4832 05 Jun 18 olle 2572     BioSource patient = null;
4832 05 Jun 18 olle 2573     String familyName = Values.getStringOrNull((String)jsonPat.get("familyName"));
4832 05 Jun 18 olle 2574     String allFirstNames = Values.getStringOrNull((String)jsonPat.get("allFirstNames"));
4832 05 Jun 18 olle 2575     if (patientId != null)
4832 05 Jun 18 olle 2576     {
4832 05 Jun 18 olle 2577       patient = BioSource.getById(dc, patientId.intValue());
4832 05 Jun 18 olle 2578       // Update names
4832 05 Jun 18 olle 2579       Annotationtype.FAMILY_NAME.setAnnotationValue(dc, patient, familyName);
4832 05 Jun 18 olle 2580       Annotationtype.ALL_FIRST_NAMES.setAnnotationValue(dc, patient, allFirstNames);
4832 05 Jun 18 olle 2581     }
4832 05 Jun 18 olle 2582     else
4832 05 Jun 18 olle 2583     {
4832 05 Jun 18 olle 2584       String pnr = (String)jsonPat.get("personalNumber");
4832 05 Jun 18 olle 2585       String patName = (String)jsonPat.get("name");
4832 05 Jun 18 olle 2586       Patient.ensureNotExistingPatient(dc, pnr, patName);
4832 05 Jun 18 olle 2587
4832 05 Jun 18 olle 2588       // Create new patient
4832 05 Jun 18 olle 2589       patient = BioSource.getNew(dc);
4832 05 Jun 18 olle 2590       patient.setItemSubtype(Subtype.PATIENT.load(dc));
4832 05 Jun 18 olle 2591       patient.setName((String)jsonPat.get("name"));
4832 05 Jun 18 olle 2592       StringToDateConverter dateConverter = new StringToDateConverter(new SimpleDateFormat("yyyy-MM-dd"));
4832 05 Jun 18 olle 2593       Date dateOfBirth = dateConverter.convert((String)jsonPat.get("dateOfBirth"));
4832 05 Jun 18 olle 2594       String gender = Values.getStringOrNull((String)jsonPat.get("gender"));
4832 05 Jun 18 olle 2595       
4832 05 Jun 18 olle 2596       Annotationtype.PERSONAL_NUMBER.setAnnotationValue(dc, patient, pnr);
4832 05 Jun 18 olle 2597       Annotationtype.FAMILY_NAME.setAnnotationValue(dc, patient, familyName);
4832 05 Jun 18 olle 2598       Annotationtype.ALL_FIRST_NAMES.setAnnotationValue(dc, patient, allFirstNames);
4832 05 Jun 18 olle 2599       Annotationtype.GENDER.setAnnotationValue(dc, patient, gender);
4832 05 Jun 18 olle 2600       Annotationtype.DATE_OF_BIRTH.setAnnotationValue(dc, patient, dateOfBirth);
4832 05 Jun 18 olle 2601       
4832 05 Jun 18 olle 2602       if (gender == null || dateOfBirth == null)
4832 05 Jun 18 olle 2603       {
4832 05 Jun 18 olle 2604         patient.setDescription("This patient was recorded with a non-standard PersonalNumber. " +
4832 05 Jun 18 olle 2605             "DateOfBirth and Gender annotations could not be automatically generated.");
4832 05 Jun 18 olle 2606       }
4832 05 Jun 18 olle 2607       dc.saveItem(patient);
4832 05 Jun 18 olle 2608       
4832 05 Jun 18 olle 2609       jsonMessages.add("Patient '" + patient.getName() + "' created successfully.");
4832 05 Jun 18 olle 2610     }
4832 05 Jun 18 olle 2611     return patient;
4832 05 Jun 18 olle 2612
4832 05 Jun 18 olle 2613   }
4832 05 Jun 18 olle 2614   
4832 05 Jun 18 olle 2615   /**
4832 05 Jun 18 olle 2616    * Convenience method that replaces an empty string with `null`.
4832 05 Jun 18 olle 2617    * 
4832 05 Jun 18 olle 2618    * @param str The input string.
4832 05 Jun 18 olle 2619    * @return String The input string; replaced with `null` if empty string.
4832 05 Jun 18 olle 2620    */
4832 05 Jun 18 olle 2621   private String replaceBlankWithNull(String str)
4832 05 Jun 18 olle 2622   {
4832 05 Jun 18 olle 2623     if (str != null && str.equals(""))
4832 05 Jun 18 olle 2624     {
4832 05 Jun 18 olle 2625       str = null;
4832 05 Jun 18 olle 2626     }
4832 05 Jun 18 olle 2627     return str;
4832 05 Jun 18 olle 2628   }
4832 05 Jun 18 olle 2629
4832 05 Jun 18 olle 2630   /**
4832 05 Jun 18 olle 2631    * Updates an input mutation analysis list with new String entry if
4832 05 Jun 18 olle 2632    * a boolean flag set to true is found for the specified String key
4832 05 Jun 18 olle 2633    * in the input JSONObject. A string entry is only added once to the
4832 05 Jun 18 olle 2634    * mutation analysis list.
4832 05 Jun 18 olle 2635    * 
4832 05 Jun 18 olle 2636    * @param jsonCase JSONObject The JSONObject to check for mutation analysis flag.
4832 05 Jun 18 olle 2637    * @param jsonKey String JSON key for Boolean mutation analysis flag.
4832 05 Jun 18 olle 2638    * @param mutationAnalysisStr String The annotation string to add to mutation analysis list, if flag is true.
4832 05 Jun 18 olle 2639    * @param mutationAnalysisList List<String> Input mutation analysis list to be updated with new entry if flag is true.
4832 05 Jun 18 olle 2640    * @return List<String> Input mutation analysis list optionally updated with new entry.
4832 05 Jun 18 olle 2641    */
4832 05 Jun 18 olle 2642   private List<String> fetchMutationAnalysisList(JSONObject jsonCase, String jsonKey, String mutationAnalysisStr, List<String> mutationAnalysisList)
4832 05 Jun 18 olle 2643   {
4832 05 Jun 18 olle 2644     if (jsonCase != null && jsonKey != null && mutationAnalysisList != null)
4832 05 Jun 18 olle 2645     {
4832 05 Jun 18 olle 2646       Boolean isIncluded = (Boolean)jsonCase.get(jsonKey);
4832 05 Jun 18 olle 2647       if (isIncluded != null && isIncluded)
4832 05 Jun 18 olle 2648       {
4832 05 Jun 18 olle 2649         if (!mutationAnalysisList.contains(mutationAnalysisStr))
4832 05 Jun 18 olle 2650         {
4832 05 Jun 18 olle 2651           mutationAnalysisList.add(mutationAnalysisStr);
4832 05 Jun 18 olle 2652         }
4832 05 Jun 18 olle 2653       }
4832 05 Jun 18 olle 2654     }
4832 05 Jun 18 olle 2655     return mutationAnalysisList;
4832 05 Jun 18 olle 2656   }
4832 05 Jun 18 olle 2657 }