extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/StoragePlate.java

Code
Comments
Other
Rev Date Author Line
1589 20 Mar 12 nicklas 1 package net.sf.basedb.reggie.dao;
1589 20 Mar 12 nicklas 2
1589 20 Mar 12 nicklas 3 import java.util.ArrayList;
4089 08 Sep 16 nicklas 4 import java.util.Collection;
1589 20 Mar 12 nicklas 5 import java.util.List;
1589 20 Mar 12 nicklas 6
1589 20 Mar 12 nicklas 7 import org.json.simple.JSONArray;
1589 20 Mar 12 nicklas 8 import org.json.simple.JSONObject;
1589 20 Mar 12 nicklas 9
1589 20 Mar 12 nicklas 10 import net.sf.basedb.core.BioPlate;
1589 20 Mar 12 nicklas 11 import net.sf.basedb.core.BioPlateType;
1589 20 Mar 12 nicklas 12 import net.sf.basedb.core.BioWell;
1589 20 Mar 12 nicklas 13 import net.sf.basedb.core.DbControl;
7140 28 Apr 23 nicklas 14 import net.sf.basedb.core.Hardware;
2677 17 Sep 14 nicklas 15 import net.sf.basedb.core.InvalidDataException;
2014 02 Aug 13 nicklas 16 import net.sf.basedb.core.Item;
1639 09 May 12 nicklas 17 import net.sf.basedb.core.ItemNotFoundException;
1589 20 Mar 12 nicklas 18 import net.sf.basedb.core.ItemQuery;
1589 20 Mar 12 nicklas 19 import net.sf.basedb.core.ItemSubtype;
1589 20 Mar 12 nicklas 20 import net.sf.basedb.core.PlateGeometry;
7140 28 Apr 23 nicklas 21 import net.sf.basedb.core.Project;
7140 28 Apr 23 nicklas 22 import net.sf.basedb.core.SessionControl;
2677 17 Sep 14 nicklas 23 import net.sf.basedb.core.Type;
1639 09 May 12 nicklas 24 import net.sf.basedb.core.query.Expressions;
1589 20 Mar 12 nicklas 25 import net.sf.basedb.core.query.Hql;
1589 20 Mar 12 nicklas 26 import net.sf.basedb.core.query.Orders;
1639 09 May 12 nicklas 27 import net.sf.basedb.core.query.Restrictions;
1589 20 Mar 12 nicklas 28 import net.sf.basedb.reggie.Reggie;
7140 28 Apr 23 nicklas 29 import net.sf.basedb.util.EqualsHelper;
7140 28 Apr 23 nicklas 30 import net.sf.basedb.util.MD5;
7140 28 Apr 23 nicklas 31 import net.sf.basedb.util.Values;
1589 20 Mar 12 nicklas 32
1589 20 Mar 12 nicklas 33 /**
1589 20 Mar 12 nicklas 34   Class for loading information that is related to storage bioplates.
1589 20 Mar 12 nicklas 35   
1589 20 Mar 12 nicklas 36   @author nicklas
1589 20 Mar 12 nicklas 37   @since 2.5
1589 20 Mar 12 nicklas 38 */
1589 20 Mar 12 nicklas 39 public class StoragePlate
1589 20 Mar 12 nicklas 40   extends ReggieItem<BioPlate>
1589 20 Mar 12 nicklas 41 {
1589 20 Mar 12 nicklas 42
1589 20 Mar 12 nicklas 43
1589 20 Mar 12 nicklas 44   /**
1589 20 Mar 12 nicklas 45     Find all storage plates which can hold biomaterial items of the given 
1589 20 Mar 12 nicklas 46     subtype.
1589 20 Mar 12 nicklas 47     
1589 20 Mar 12 nicklas 48     
1589 20 Mar 12 nicklas 49     @param dc
1589 20 Mar 12 nicklas 50     @param bioPlateType The required bioplate type, or null to not filter on bioplate type
1589 20 Mar 12 nicklas 51     @param subtype A biomaterial subtype, or null to not filter on subtype
1589 20 Mar 12 nicklas 52   */
1589 20 Mar 12 nicklas 53   public static List<StoragePlate> findByBioMaterialSubtype(DbControl dc, 
1589 20 Mar 12 nicklas 54     BioplateType bioPlateType, Subtype subtype)
1589 20 Mar 12 nicklas 55   {
1589 20 Mar 12 nicklas 56     ItemQuery<BioPlate> query = BioPlate.getQuery();
1589 20 Mar 12 nicklas 57     query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
1589 20 Mar 12 nicklas 58     if (subtype != null || bioPlateType != null)
1589 20 Mar 12 nicklas 59     {
1589 20 Mar 12 nicklas 60       query.join(Hql.innerJoin("bioPlateType", "bpt"));
1589 20 Mar 12 nicklas 61       if (bioPlateType != null) bioPlateType.addFilter(dc, query, false);
1589 20 Mar 12 nicklas 62       if (subtype != null) subtype.addFilter(dc, query, "bpt");
1589 20 Mar 12 nicklas 63     }
1589 20 Mar 12 nicklas 64     
1589 20 Mar 12 nicklas 65     query.order(Orders.asc(Hql.property("name")));
1589 20 Mar 12 nicklas 66     
1589 20 Mar 12 nicklas 67     List<BioPlate> tmp = query.list(dc);
1589 20 Mar 12 nicklas 68     List<StoragePlate> plates = new ArrayList<StoragePlate>(tmp.size());
1589 20 Mar 12 nicklas 69     for (BioPlate plate : tmp)
1589 20 Mar 12 nicklas 70     {
1589 20 Mar 12 nicklas 71       plates.add(new StoragePlate(plate));
1589 20 Mar 12 nicklas 72     }
1589 20 Mar 12 nicklas 73     return plates;
1589 20 Mar 12 nicklas 74   }
1589 20 Mar 12 nicklas 75   
1639 09 May 12 nicklas 76   /**
2677 17 Sep 14 nicklas 77     Find the storage plate with the given name.
2677 17 Sep 14 nicklas 78     @since 2.16
2677 17 Sep 14 nicklas 79    */
2677 17 Sep 14 nicklas 80   public static StoragePlate findByName(DbControl dc, String name)
2677 17 Sep 14 nicklas 81   {
2677 17 Sep 14 nicklas 82     
2677 17 Sep 14 nicklas 83     ItemQuery<BioPlate> query = BioPlate.getQuery();
2677 17 Sep 14 nicklas 84     query.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", name, Type.STRING)));
2677 17 Sep 14 nicklas 85   
2677 17 Sep 14 nicklas 86     List<BioPlate> tmp = query.list(dc);
2677 17 Sep 14 nicklas 87     StoragePlate sp = null;
2677 17 Sep 14 nicklas 88     
2677 17 Sep 14 nicklas 89     if (tmp.size() > 1)
2677 17 Sep 14 nicklas 90     {
2677 17 Sep 14 nicklas 91       throw new InvalidDataException(
2677 17 Sep 14 nicklas 92         "Found " + tmp.size() + " storage plates with the same name (" + name + 
2677 17 Sep 14 nicklas 93         "). This wizard can't be used until that is corrected.");
2677 17 Sep 14 nicklas 94     }
2677 17 Sep 14 nicklas 95     else if (tmp.size() == 1)
2677 17 Sep 14 nicklas 96     {
2677 17 Sep 14 nicklas 97       sp = new StoragePlate(tmp.get(0));
2677 17 Sep 14 nicklas 98     }
2677 17 Sep 14 nicklas 99     
2677 17 Sep 14 nicklas 100     return sp;
2677 17 Sep 14 nicklas 101   }
2677 17 Sep 14 nicklas 102
2677 17 Sep 14 nicklas 103   
2677 17 Sep 14 nicklas 104   /**
1639 09 May 12 nicklas 105     Find the correct biowell location for a child item, given the location of a parent item.
1639 09 May 12 nicklas 106     The parentPrefix is the prefix on the parent bioplate which is replaced with the
1639 09 May 12 nicklas 107     child prefix. The resulting name is used to located the child bioplate. The child
1639 09 May 12 nicklas 108     item is expected to have the same position as the parent.
1639 09 May 12 nicklas 109   */
1639 09 May 12 nicklas 110   public static BioWell getChildBioWell(DbControl dc, BioWell parentWell, String parentPrefix, String childPrefix)
1639 09 May 12 nicklas 111   {
1639 09 May 12 nicklas 112     BioPlate parentPlate = parentWell.getPlate();
1639 09 May 12 nicklas 113     String childPlateName = parentPlate.getName().replace(parentPrefix, childPrefix);
1639 09 May 12 nicklas 114     
1639 09 May 12 nicklas 115     ItemQuery<BioPlate> query = BioPlate.getQuery();
1639 09 May 12 nicklas 116     query.restrict(Restrictions.eq(Hql.property("name"), Expressions.string(childPlateName)));
1639 09 May 12 nicklas 117     List<BioPlate> list = query.list(dc);
1639 09 May 12 nicklas 118     if (list.size() == 0)
1639 09 May 12 nicklas 119     {
1639 09 May 12 nicklas 120       throw new ItemNotFoundException("BioPlate[name="+childPlateName + "]");
1639 09 May 12 nicklas 121     }
1639 09 May 12 nicklas 122     return list.get(0).getBioWell(parentWell.getPlateCoordinate());
1639 09 May 12 nicklas 123   }
1639 09 May 12 nicklas 124   
1589 20 Mar 12 nicklas 125   public static StoragePlate getById(DbControl dc, int bioPlateId)
1589 20 Mar 12 nicklas 126   {
1589 20 Mar 12 nicklas 127     BioPlate plate = BioPlate.getById(dc, bioPlateId);
1589 20 Mar 12 nicklas 128     return plate == null ? null : new StoragePlate(plate);
1589 20 Mar 12 nicklas 129   }
1589 20 Mar 12 nicklas 130   
1589 20 Mar 12 nicklas 131   public static StoragePlate getNew(DbControl dc, BioplateType bioplateType)
1589 20 Mar 12 nicklas 132   {
1589 20 Mar 12 nicklas 133     BioPlate plate = BioPlate.getNew(dc, bioplateType.getPlateGeometry(dc), bioplateType.load(dc));
1589 20 Mar 12 nicklas 134     return new StoragePlate(plate);
1589 20 Mar 12 nicklas 135   }
1589 20 Mar 12 nicklas 136   
7140 28 Apr 23 nicklas 137   /**
7140 28 Apr 23 nicklas 138     Find existing storage boxes with the given prefix. If a "lastPlacedSpecimen" is given
7140 28 Apr 23 nicklas 139     only boxes with a name that is alphabetically sorted later are returned.
7140 28 Apr 23 nicklas 140     @sinced 4.47 (was in SpecimenTubeServlet before that)
7140 28 Apr 23 nicklas 141   */
7140 28 Apr 23 nicklas 142   public static List<StoragePlate> findExistingStorageBoxes(DbControl dc, SpecimenTube lastPlacedSpecimen, String boxPrefix)
7140 28 Apr 23 nicklas 143   {
7140 28 Apr 23 nicklas 144     ItemQuery<BioPlate> spBoxQuery = BioPlate.getQuery();
7140 28 Apr 23 nicklas 145     spBoxQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.string(boxPrefix+"%")));
7140 28 Apr 23 nicklas 146     if (lastPlacedSpecimen != null)
7140 28 Apr 23 nicklas 147     {
7140 28 Apr 23 nicklas 148       BioPlate lastBox = lastPlacedSpecimen.getItem().getBioWell().getPlate();
7140 28 Apr 23 nicklas 149       // Only load boxes with the same or later name than the last sample
7140 28 Apr 23 nicklas 150       spBoxQuery.restrict(Restrictions.gteq(Hql.property("name"), Expressions.string(lastBox.getName())));
7140 28 Apr 23 nicklas 151     }
7140 28 Apr 23 nicklas 152     spBoxQuery.order(Orders.asc(Hql.property("name")));
7140 28 Apr 23 nicklas 153     return StoragePlate.toStoragePlates(spBoxQuery.list(dc));
7140 28 Apr 23 nicklas 154   }
7140 28 Apr 23 nicklas 155
7140 28 Apr 23 nicklas 156   /**
7140 28 Apr 23 nicklas 157     Find empty wells in the given list of storage plates. It will return
7140 28 Apr 23 nicklas 158     at most 'nofTubes' wells. If the given list of storage plates doens't have
7140 28 Apr 23 nicklas 159     enough free wells new storage plates may be created if a boxType is given. If
7140 28 Apr 23 nicklas 160     boxType is null no new boxes are created and the returned list may be
7140 28 Apr 23 nicklas 161     less than the number of requested wells.
7140 28 Apr 23 nicklas 162     @since 4.47 (was in SpecimenTubeServlet before that)
7140 28 Apr 23 nicklas 163   */
7140 28 Apr 23 nicklas 164   public static List<BioWell> findEmptyWells(DbControl dc, List<StoragePlate> spBoxes, int nofTubes, BoxType boxType)
7140 28 Apr 23 nicklas 165   {
7140 28 Apr 23 nicklas 166     List<BioWell> wells = new ArrayList<>(nofTubes);
7140 28 Apr 23 nicklas 167     while (wells.size() < nofTubes)
7140 28 Apr 23 nicklas 168     {
7140 28 Apr 23 nicklas 169       BioPlate lastPlate = null;
7140 28 Apr 23 nicklas 170       for (StoragePlate box : spBoxes)
7140 28 Apr 23 nicklas 171       {
7140 28 Apr 23 nicklas 172         lastPlate = box.getBioPlate();
7140 28 Apr 23 nicklas 173         BioWell free = box.getFirstFreeWell();
7140 28 Apr 23 nicklas 174         while (free != null)
7140 28 Apr 23 nicklas 175         {
7140 28 Apr 23 nicklas 176           wells.add(free);
7140 28 Apr 23 nicklas 177           if (wells.size() == nofTubes) break;
7140 28 Apr 23 nicklas 178           free = box.getNextFreeWell(free);
7140 28 Apr 23 nicklas 179         }
7140 28 Apr 23 nicklas 180         if (wells.size() == nofTubes) break;
7140 28 Apr 23 nicklas 181       }
7140 28 Apr 23 nicklas 182       
7140 28 Apr 23 nicklas 183       if (wells.size() != nofTubes && boxType != null)
7140 28 Apr 23 nicklas 184       {
7140 28 Apr 23 nicklas 185         // We need to create more storage boxes
7188 22 May 23 nicklas 186         spBoxes = StoragePlate.toStoragePlates(createNewStorageBoxes(dc, lastPlate, 1, boxType, null, true));
7140 28 Apr 23 nicklas 187       }
7140 28 Apr 23 nicklas 188       else
7140 28 Apr 23 nicklas 189       {
7140 28 Apr 23 nicklas 190         // Break without creating the requested number of wells
7140 28 Apr 23 nicklas 191         break;
7140 28 Apr 23 nicklas 192       }
7140 28 Apr 23 nicklas 193     }
7140 28 Apr 23 nicklas 194     return wells;
7140 28 Apr 23 nicklas 195   }
7140 28 Apr 23 nicklas 196
7140 28 Apr 23 nicklas 197   /**
7140 28 Apr 23 nicklas 198     Creates new storage boxes for Specimen, Lysate, DNA, RNA and FlowThrough.
7140 28 Apr 23 nicklas 199     The last existing Specimen box is used for calculating the location of
7140 28 Apr 23 nicklas 200     the new boxes by increasing the properties in the following order:
7140 28 Apr 23 nicklas 201     
7140 28 Apr 23 nicklas 202     Position: 1..4
7140 28 Apr 23 nicklas 203     Tray: 11, 21, 31, 41, 51, 61 (only in section 2 and 4)
7140 28 Apr 23 nicklas 204     Section: 1..4
7140 28 Apr 23 nicklas 205     
7140 28 Apr 23 nicklas 206     That last digit of the "tray" depends on the item type:
7140 28 Apr 23 nicklas 207     
7140 28 Apr 23 nicklas 208     Specimen: *1
7140 28 Apr 23 nicklas 209     Lysate: *2
7140 28 Apr 23 nicklas 210     DNA: *3
7140 28 Apr 23 nicklas 211     RNA: *4
7140 28 Apr 23 nicklas 212     FlowThrough: *5
7140 28 Apr 23 nicklas 213     
7140 28 Apr 23 nicklas 214     Tray 1* and 2* in section 3 and tray *6 are used for temporary/other 
7140 28 Apr 23 nicklas 215     storage and should be skipped.
7140 28 Apr 23 nicklas 216     @since 4.47 (was in SpecimenTubeServlet before that)
7140 28 Apr 23 nicklas 217   */
7188 22 May 23 nicklas 218   public static List<BioPlate> createNewStorageBoxes(DbControl dc, BioPlate lastSpBox, int numBoxes, BoxType boxType, Hardware selectedFreezer, boolean useSeparateTransaction)
7140 28 Apr 23 nicklas 219   {
7140 28 Apr 23 nicklas 220     SessionControl sc = dc.getSessionControl();
7140 28 Apr 23 nicklas 221     DbControl dc2 = null;
7140 28 Apr 23 nicklas 222     List<BioPlate> created = new ArrayList<>(numBoxes);
7140 28 Apr 23 nicklas 223     try
7140 28 Apr 23 nicklas 224     {
7140 28 Apr 23 nicklas 225       // Load the project default freezer
7140 28 Apr 23 nicklas 226       Hardware defaultFreezer = null;
7140 28 Apr 23 nicklas 227       if (sc.getActiveProjectId() != 0)
7140 28 Apr 23 nicklas 228       {
7140 28 Apr 23 nicklas 229         Project p = Project.getById(dc, sc.getActiveProjectId());
7140 28 Apr 23 nicklas 230         List<Hardware> list = p.findDefaultItems(dc, Subtype.FREEZER.load(dc), true);
7140 28 Apr 23 nicklas 231         defaultFreezer = list.size() > 0 ? list.get(0) : null;
7140 28 Apr 23 nicklas 232       }
7140 28 Apr 23 nicklas 233   
7140 28 Apr 23 nicklas 234       // Initial settings for the first storage box
7140 28 Apr 23 nicklas 235       Hardware freezer = defaultFreezer;
7140 28 Apr 23 nicklas 236       int plateNo = 1;
7140 28 Apr 23 nicklas 237       int section = 1;
7140 28 Apr 23 nicklas 238       int tray = 11;
7140 28 Apr 23 nicklas 239       int position = 1;
7140 28 Apr 23 nicklas 240       
7140 28 Apr 23 nicklas 241       // Boxes are created in a separate transaction
7140 28 Apr 23 nicklas 242       dc2 = useSeparateTransaction ? sc.newDbControl(dc.getName()) : dc;
7140 28 Apr 23 nicklas 243   
7140 28 Apr 23 nicklas 244       for (int boxNo = 0; boxNo < numBoxes; boxNo++)
7140 28 Apr 23 nicklas 245       {
7140 28 Apr 23 nicklas 246         if (lastSpBox != null)
7140 28 Apr 23 nicklas 247         {
7140 28 Apr 23 nicklas 248           // Increase plate number
7140 28 Apr 23 nicklas 249           plateNo = Values.getInt(lastSpBox.getName().replaceAll("[^0-9]", "")) + 1;
7140 28 Apr 23 nicklas 250           // Get the freezer and location of the last plate
7140 28 Apr 23 nicklas 251           freezer = lastSpBox.getFreezer();
7140 28 Apr 23 nicklas 252           if (boxType == BoxType.NORMAL)
7140 28 Apr 23 nicklas 253           {
7140 28 Apr 23 nicklas 254             section = Values.getInt(lastSpBox.getSection());
7140 28 Apr 23 nicklas 255             tray = Values.getInt(lastSpBox.getTray());
7140 28 Apr 23 nicklas 256             position = Values.getInt(lastSpBox.getPosition());        
7140 28 Apr 23 nicklas 257             
7140 28 Apr 23 nicklas 258             // Increase position+tray+section until we find a valid location
7140 28 Apr 23 nicklas 259             boolean isValidLocation = false;
7140 28 Apr 23 nicklas 260             while (!isValidLocation)
7140 28 Apr 23 nicklas 261             {
7140 28 Apr 23 nicklas 262               position++;
7140 28 Apr 23 nicklas 263               if (position > 4)
7140 28 Apr 23 nicklas 264               {
7140 28 Apr 23 nicklas 265                 position = 1;
7140 28 Apr 23 nicklas 266                 tray += 10;
7140 28 Apr 23 nicklas 267               }
7140 28 Apr 23 nicklas 268               if (tray > ((section == 1 || section == 3) ? 60 : 70)) // Section 1&3 have 5 rows, 2&4 have 6 rows
7140 28 Apr 23 nicklas 269               {
7140 28 Apr 23 nicklas 270                 tray = 11;
7140 28 Apr 23 nicklas 271                 section++;
7140 28 Apr 23 nicklas 272               }
7140 28 Apr 23 nicklas 273               if (section > 4)
7140 28 Apr 23 nicklas 274               {
7140 28 Apr 23 nicklas 275                 section = 1;
7140 28 Apr 23 nicklas 276                 // Use the default freezer but not if it is the same as the current
7140 28 Apr 23 nicklas 277                 // since it should be full by now...
7140 28 Apr 23 nicklas 278                 freezer = EqualsHelper.equals(freezer, defaultFreezer) ? null : defaultFreezer;
7140 28 Apr 23 nicklas 279               }
7140 28 Apr 23 nicklas 280               // Check if location is valid
7140 28 Apr 23 nicklas 281               // Tray column 6 and row 1&2 in section 3 are reserved for temporary/other boxes
7140 28 Apr 23 nicklas 282               int trayCol = tray % 10;
7140 28 Apr 23 nicklas 283               int trayRow = tray / 10;
7140 28 Apr 23 nicklas 284               if (trayCol == 6 || (section == 3 && (trayRow < 3)))
7140 28 Apr 23 nicklas 285               {
7140 28 Apr 23 nicklas 286                 isValidLocation = false;
7140 28 Apr 23 nicklas 287               }
7140 28 Apr 23 nicklas 288               else
7140 28 Apr 23 nicklas 289               {
7140 28 Apr 23 nicklas 290                 isValidLocation = true;
7140 28 Apr 23 nicklas 291               }
7140 28 Apr 23 nicklas 292             }
7140 28 Apr 23 nicklas 293           }
7140 28 Apr 23 nicklas 294         }
7140 28 Apr 23 nicklas 295         
7140 28 Apr 23 nicklas 296         // Convert plate number to a 0-padded string with length 3.
7140 28 Apr 23 nicklas 297         String nameSuffix = MD5.leftPad(Integer.toString(plateNo), '0', 3);
7140 28 Apr 23 nicklas 298         BioPlate sp = null;
7140 28 Apr 23 nicklas 299         if (boxType == BoxType.PAUSE)
7140 28 Apr 23 nicklas 300         {
7140 28 Apr 23 nicklas 301           sp = createStorageBox(dc2, "PSp"+nameSuffix, 0, 0, 0, freezer);
7140 28 Apr 23 nicklas 302         }
7140 28 Apr 23 nicklas 303         else if (boxType == BoxType.NORMAL)
7140 28 Apr 23 nicklas 304         {
7140 28 Apr 23 nicklas 305           sp = createStorageBox(dc2, "Sp"+nameSuffix, section, tray, position, freezer);
7140 28 Apr 23 nicklas 306           BioPlate lys = createStorageBox(dc2, "Lys"+nameSuffix, section, tray+1, position, freezer);
7140 28 Apr 23 nicklas 307           BioPlate dna = createStorageBox(dc2, "DNA"+nameSuffix, section, tray+2, position, freezer);
7140 28 Apr 23 nicklas 308           BioPlate rna = createStorageBox(dc2, "RNA"+nameSuffix, section, tray+3, position, freezer);
7140 28 Apr 23 nicklas 309           BioPlate ft = createStorageBox(dc2, "FT"+nameSuffix, section, tray+4, position, freezer);
7140 28 Apr 23 nicklas 310         }
7140 28 Apr 23 nicklas 311         else if (boxType == BoxType.EXTERNAL)
7140 28 Apr 23 nicklas 312         {
7188 22 May 23 nicklas 313           // Force using the selected freezer
7188 22 May 23 nicklas 314           if (selectedFreezer != null) freezer = selectedFreezer;
7188 22 May 23 nicklas 315           
7140 28 Apr 23 nicklas 316           sp = createStorageBox(dc2, "E-Sp"+nameSuffix, 0, 0, 0, freezer);
7140 28 Apr 23 nicklas 317           BioPlate lys = createStorageBox(dc2, "E-Lys"+nameSuffix, 0, 0, 0, freezer);
7140 28 Apr 23 nicklas 318           BioPlate dna = createStorageBox(dc2, "E-DNA"+nameSuffix, 0, 0, 0, freezer);
7140 28 Apr 23 nicklas 319           BioPlate rna = createStorageBox(dc2, "E-RNA"+nameSuffix, 0, 0, 0, freezer);
7140 28 Apr 23 nicklas 320           BioPlate ft = createStorageBox(dc2, "E-FT"+nameSuffix, 0, 0, 0, freezer);
7140 28 Apr 23 nicklas 321         }
7140 28 Apr 23 nicklas 322         created.add(sp);
7140 28 Apr 23 nicklas 323         lastSpBox = sp;
7140 28 Apr 23 nicklas 324       }
7140 28 Apr 23 nicklas 325       
7140 28 Apr 23 nicklas 326       if (useSeparateTransaction) 
7140 28 Apr 23 nicklas 327       {
7140 28 Apr 23 nicklas 328         dc2.commit();
7140 28 Apr 23 nicklas 329         
7140 28 Apr 23 nicklas 330         // Reload the Sp plate in the original transaction
7140 28 Apr 23 nicklas 331         for (int i = 0; i < created.size(); i++)
7140 28 Apr 23 nicklas 332         {
7140 28 Apr 23 nicklas 333           created.set(i, BioPlate.getById(dc, created.get(i).getId()));
7140 28 Apr 23 nicklas 334         }
7140 28 Apr 23 nicklas 335       }
7140 28 Apr 23 nicklas 336     }
7140 28 Apr 23 nicklas 337     finally
7140 28 Apr 23 nicklas 338     {
7140 28 Apr 23 nicklas 339       if (useSeparateTransaction && dc2 != null) dc2.close();
7140 28 Apr 23 nicklas 340     }
7140 28 Apr 23 nicklas 341     
7140 28 Apr 23 nicklas 342     return created;
7140 28 Apr 23 nicklas 343   }
7140 28 Apr 23 nicklas 344   
7140 28 Apr 23 nicklas 345   /**
7140 28 Apr 23 nicklas 346     Create a new storage box with the specified freezer location. Section, tray and position
7140 28 Apr 23 nicklas 347     should be >0 or they will not be set.
7140 28 Apr 23 nicklas 348     @since 4.47 (was in SpecimenTubeServlet before that)
7140 28 Apr 23 nicklas 349   */
7140 28 Apr 23 nicklas 350   public static BioPlate createStorageBox(DbControl dc, String name, int section, int tray, int position, Hardware freezer)
7140 28 Apr 23 nicklas 351   {
7140 28 Apr 23 nicklas 352     ReggieItem.ensureNonExistingItem(dc, Item.BIOPLATE, "Storage box", name);
7140 28 Apr 23 nicklas 353     BioPlate box = BioPlate.getNew(dc, BioplateType.STORAGE_BOX.getPlateGeometry(dc), BioplateType.STORAGE_BOX.load(dc));
7140 28 Apr 23 nicklas 354     box.setName(name);
7140 28 Apr 23 nicklas 355     box.setFreezer(freezer);
7140 28 Apr 23 nicklas 356     if (section > 0) box.setSection(Integer.toString(section));
7140 28 Apr 23 nicklas 357     if (tray > 0) box.setTray(Integer.toString(tray));
7140 28 Apr 23 nicklas 358     if (position > 0) box.setPosition(Integer.toString(position));    
7140 28 Apr 23 nicklas 359     dc.saveItem(box);
7140 28 Apr 23 nicklas 360     return box;
7140 28 Apr 23 nicklas 361   }
7140 28 Apr 23 nicklas 362
4089 08 Sep 16 nicklas 363   public static List<StoragePlate> toStoragePlates(Collection<BioPlate> plates)
4089 08 Sep 16 nicklas 364   {
4089 08 Sep 16 nicklas 365     List<StoragePlate> storagePlates = new ArrayList<StoragePlate>(plates.size());
4089 08 Sep 16 nicklas 366     for (BioPlate bp : plates)
4089 08 Sep 16 nicklas 367     {
4089 08 Sep 16 nicklas 368       storagePlates.add(new StoragePlate(bp));
4089 08 Sep 16 nicklas 369     }
4089 08 Sep 16 nicklas 370     return storagePlates;
4089 08 Sep 16 nicklas 371   }
4089 08 Sep 16 nicklas 372
4089 08 Sep 16 nicklas 373   
1589 20 Mar 12 nicklas 374   private JSONArray jsonWells;
1589 20 Mar 12 nicklas 375   
1589 20 Mar 12 nicklas 376   private StoragePlate(BioPlate plate)
1589 20 Mar 12 nicklas 377   {
1589 20 Mar 12 nicklas 378     super(plate);
1589 20 Mar 12 nicklas 379   }
1589 20 Mar 12 nicklas 380   
1589 20 Mar 12 nicklas 381   
1589 20 Mar 12 nicklas 382   /**
1589 20 Mar 12 nicklas 383     Get the real bioplate that represents this reaction plate in BASE.
1589 20 Mar 12 nicklas 384   */
1589 20 Mar 12 nicklas 385   public BioPlate getBioPlate()
1589 20 Mar 12 nicklas 386   {
1589 20 Mar 12 nicklas 387     return getItem();
1589 20 Mar 12 nicklas 388   }
1589 20 Mar 12 nicklas 389   
1589 20 Mar 12 nicklas 390   public void loadBioWells(DbControl dc)
1589 20 Mar 12 nicklas 391   {
1589 20 Mar 12 nicklas 392     if (jsonWells != null) return;
1589 20 Mar 12 nicklas 393     
1589 20 Mar 12 nicklas 394     BioPlate plate = getItem();
1589 20 Mar 12 nicklas 395     int rows = plate.getRows();
1589 20 Mar 12 nicklas 396     int cols = plate.getColumns();
1589 20 Mar 12 nicklas 397     
1589 20 Mar 12 nicklas 398     jsonWells = new JSONArray();
1589 20 Mar 12 nicklas 399     for (int r = 0; r < rows; ++r)
1589 20 Mar 12 nicklas 400     {
1589 20 Mar 12 nicklas 401       for (int c = 0; c < cols; ++c)
1589 20 Mar 12 nicklas 402       {
1589 20 Mar 12 nicklas 403         BioWell well = plate.getBioWell(r, c);
1589 20 Mar 12 nicklas 404         JSONObject jsonWell = new JSONObject();
1589 20 Mar 12 nicklas 405         jsonWell.put("id", well.getId());
1589 20 Mar 12 nicklas 406         jsonWell.put("row", well.getRow());
1589 20 Mar 12 nicklas 407         jsonWell.put("column", well.getColumn());
1589 20 Mar 12 nicklas 408         jsonWell.put("canAdd", well.canAddBioMaterial());
1589 20 Mar 12 nicklas 409         jsonWell.put("canRemove", well.canClearBioMaterial());
1589 20 Mar 12 nicklas 410         jsonWells.add(jsonWell);
1589 20 Mar 12 nicklas 411       }
1589 20 Mar 12 nicklas 412     }  
1589 20 Mar 12 nicklas 413   }
1589 20 Mar 12 nicklas 414   
1589 20 Mar 12 nicklas 415   @Override
1589 20 Mar 12 nicklas 416   protected void initJSON(JSONObject json)
1589 20 Mar 12 nicklas 417   {
1589 20 Mar 12 nicklas 418     super.initJSON(json);
1589 20 Mar 12 nicklas 419     BioPlate plate = getItem();
1589 20 Mar 12 nicklas 420     BioPlateType plateType = plate.getBioPlateType();
1589 20 Mar 12 nicklas 421     PlateGeometry geometry = plate.getPlateGeometry();
1589 20 Mar 12 nicklas 422     ItemSubtype bioMaterialSubtype = plateType.getItemSubtype();
2014 02 Aug 13 nicklas 423     Item bioMaterialType = plateType.getBioMaterialType();
1589 20 Mar 12 nicklas 424     
1589 20 Mar 12 nicklas 425     json.put("freeWells", plate.getFreeWells());
1589 20 Mar 12 nicklas 426     json.put("usedWells", plate.getUsedWells());
1589 20 Mar 12 nicklas 427     json.put("barcode", plate.getBarcode());
1589 20 Mar 12 nicklas 428     
1589 20 Mar 12 nicklas 429     JSONObject jsonBioPlateType = new JSONObject();
1589 20 Mar 12 nicklas 430     jsonBioPlateType.put("id", plateType.getId());
2014 02 Aug 13 nicklas 431     jsonBioPlateType.put("name", plateType.getName());
2014 02 Aug 13 nicklas 432     if (bioMaterialType != null)
2014 02 Aug 13 nicklas 433     {
2014 02 Aug 13 nicklas 434       jsonBioPlateType.put("bioMaterialType", bioMaterialType.name());
2014 02 Aug 13 nicklas 435     }
1589 20 Mar 12 nicklas 436     json.put("bioPlateType", jsonBioPlateType);
1589 20 Mar 12 nicklas 437     
1589 20 Mar 12 nicklas 438     JSONObject jsonGeometry = new JSONObject();
1589 20 Mar 12 nicklas 439     jsonGeometry.put("id", geometry.getId());
1589 20 Mar 12 nicklas 440     jsonGeometry.put("rows", geometry.getRows());
1589 20 Mar 12 nicklas 441     jsonGeometry.put("columns", geometry.getColumns());
1589 20 Mar 12 nicklas 442     json.put("geometry", jsonGeometry);
1589 20 Mar 12 nicklas 443     
1589 20 Mar 12 nicklas 444     if (bioMaterialSubtype != null)
1589 20 Mar 12 nicklas 445     {
1589 20 Mar 12 nicklas 446       json.put("bioMaterialSubtype", Subtype.get(bioMaterialSubtype).asJSONObject(null));
1589 20 Mar 12 nicklas 447     }
1589 20 Mar 12 nicklas 448     if (jsonWells != null)
1589 20 Mar 12 nicklas 449     {
1589 20 Mar 12 nicklas 450       json.put("bioWells", jsonWells);
1589 20 Mar 12 nicklas 451     }
1589 20 Mar 12 nicklas 452   }
1589 20 Mar 12 nicklas 453
4089 08 Sep 16 nicklas 454   public BioWell getFirstFreeWell()
4089 08 Sep 16 nicklas 455   {
4089 08 Sep 16 nicklas 456     BioPlate box = getBioPlate();
4089 08 Sep 16 nicklas 457     // First free well in the box. 
4089 08 Sep 16 nicklas 458     BioWell firstFreeWell= null;
4089 08 Sep 16 nicklas 459     
4089 08 Sep 16 nicklas 460     int rowIndex = box.getRows()-1;
4089 08 Sep 16 nicklas 461     boolean foundLastEmpty = false;          
4089 08 Sep 16 nicklas 462     while (rowIndex >= 0 && !foundLastEmpty)
4089 08 Sep 16 nicklas 463     {
4089 08 Sep 16 nicklas 464       int columnIndex = box.getColumns()-1;
4089 08 Sep 16 nicklas 465       while (columnIndex >= 0 && !foundLastEmpty)
4089 08 Sep 16 nicklas 466       { 
4089 08 Sep 16 nicklas 467         if (!box.getBioWell(rowIndex, columnIndex).isEmpty())
4089 08 Sep 16 nicklas 468         {
4089 08 Sep 16 nicklas 469           /* We past the last free well or reach the beginning of the plate, 
4089 08 Sep 16 nicklas 470              take one step forward and check if all tubes can be placed on the same row
4089 08 Sep 16 nicklas 471           */
4089 08 Sep 16 nicklas 472           int freeColumn = columnIndex+1;
4089 08 Sep 16 nicklas 473           int freeRow = rowIndex;
4089 08 Sep 16 nicklas 474           if (freeColumn >= box.getColumns())
4089 08 Sep 16 nicklas 475           {
4089 08 Sep 16 nicklas 476             freeRow++;
4089 08 Sep 16 nicklas 477             freeColumn = 0;
4089 08 Sep 16 nicklas 478           }
4089 08 Sep 16 nicklas 479                     
4089 08 Sep 16 nicklas 480           if (freeRow<box.getRows() && freeColumn<box.getColumns())
4089 08 Sep 16 nicklas 481           {
4089 08 Sep 16 nicklas 482             firstFreeWell = box.getBioWell(freeRow, freeColumn);
4089 08 Sep 16 nicklas 483           }          
4089 08 Sep 16 nicklas 484           foundLastEmpty = true;
4089 08 Sep 16 nicklas 485         }
4089 08 Sep 16 nicklas 486         else if (rowIndex == 0 && columnIndex==0)
4089 08 Sep 16 nicklas 487         {
4089 08 Sep 16 nicklas 488           // We reached the first well on the plate without seeing any specimen
4089 08 Sep 16 nicklas 489           firstFreeWell = box.getBioWell(rowIndex, columnIndex);
4089 08 Sep 16 nicklas 490         }
4089 08 Sep 16 nicklas 491         columnIndex--;
4089 08 Sep 16 nicklas 492       }
4089 08 Sep 16 nicklas 493       rowIndex--;
4089 08 Sep 16 nicklas 494     }    
4089 08 Sep 16 nicklas 495     return firstFreeWell;
4089 08 Sep 16 nicklas 496   }
1589 20 Mar 12 nicklas 497   
4089 08 Sep 16 nicklas 498   public BioWell getNextFreeWell(BioWell well)
4089 08 Sep 16 nicklas 499   {
4089 08 Sep 16 nicklas 500     BioWell nextFree = null;
4089 08 Sep 16 nicklas 501     BioPlate plate = well.getPlate();
4089 08 Sep 16 nicklas 502     int numColumns = plate.getColumns();
4089 08 Sep 16 nicklas 503     
4089 08 Sep 16 nicklas 504     int nextPos = well.getRow() * numColumns + well.getColumn()+1;
4089 08 Sep 16 nicklas 505     int nextCol = nextPos % numColumns;
4089 08 Sep 16 nicklas 506     int nextRow = nextPos / numColumns;
4089 08 Sep 16 nicklas 507     nextFree = plate.getBioWell(nextRow, nextCol);
4089 08 Sep 16 nicklas 508     
4089 08 Sep 16 nicklas 509     return nextFree;
4089 08 Sep 16 nicklas 510   }
4089 08 Sep 16 nicklas 511   
7140 28 Apr 23 nicklas 512   public static enum BoxType
7140 28 Apr 23 nicklas 513   {
7140 28 Apr 23 nicklas 514     NORMAL,
7140 28 Apr 23 nicklas 515     PAUSE,
7140 28 Apr 23 nicklas 516     EXTERNAL;
7140 28 Apr 23 nicklas 517   }
7140 28 Apr 23 nicklas 518
1589 20 Mar 12 nicklas 519 }