package edu.ualberta.med.biobank.common.wrappers;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.criterion.DetachedCriteria;
import edu.ualberta.med.biobank.common.exception.BiobankCheckException;
import edu.ualberta.med.biobank.common.peer.ContainerTypePeer;
import edu.ualberta.med.biobank.common.util.RowColPos;
import edu.ualberta.med.biobank.common.wrappers.WrapperTransaction.TaskList;
import edu.ualberta.med.biobank.common.wrappers.base.ContainerLabelingSchemeBaseWrapper;
import edu.ualberta.med.biobank.model.Capacity;
import edu.ualberta.med.biobank.model.ContainerLabelingScheme;
import edu.ualberta.med.biobank.model.ContainerType;
import gov.nih.nci.system.applicationservice.ApplicationException;
import gov.nih.nci.system.applicationservice.WritableApplicationService;
import gov.nih.nci.system.query.hibernate.HQLCriteria;
public class ContainerLabelingSchemeWrapper extends
ContainerLabelingSchemeBaseWrapper {
public static final int SCHEME_SBS = 1;
public static final int SCHEME_CBSR_2_CHAR_ALPHA = 2;
public static final int SCHEME_2_CHAR_NUMERIC = 3;
public static final int SCHEME_DEWAR = 4;
public static final int SCHEME_CBSR_SBS = 5;
public static final int SCHEME_2_CHAR_ALPHA = 6;
public static final String CBSR_2_CHAR_LABELLING_PATTERN =
"ABCDEFGHJKLMNPQRSTUVWXYZ"; //$NON-NLS-1$
public static final String TWO_CHAR_LABELLING_PATTERN =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //$NON-NLS-1$
public static final String SBS_ROW_LABELLING_PATTERN = "ABCDEFGHIJKLMNOP"; //$NON-NLS-1$
public static String BOX81_LABELLING_PATTERN = "ABCDEFGHJ"; //$NON-NLS-1$
private static Map<Integer, ContainerLabelingSchemeWrapper> allSchemes =
null;
public ContainerLabelingSchemeWrapper(
WritableApplicationService appService,
ContainerLabelingScheme wrappedObject) {
super(appService, wrappedObject);
}
public ContainerLabelingSchemeWrapper(WritableApplicationService appService) {
super(appService);
}
public static synchronized Map<Integer, ContainerLabelingSchemeWrapper> getAllLabelingSchemesMap(
WritableApplicationService appService) throws ApplicationException {
if (allSchemes == null) {
allSchemes = new HashMap<Integer, ContainerLabelingSchemeWrapper>();
List<ContainerLabelingScheme> list =
appService.query(DetachedCriteria
.forClass(ContainerLabelingScheme.class));
if (list != null) {
for (ContainerLabelingScheme scheme : list) {
Integer id = scheme.getId();
switch (id.intValue()) {
case SCHEME_SBS:
if (!scheme.getName().equals("SBS Standard")) { //$NON-NLS-1$
throw new ApplicationException(
"labeling scheme is not " + scheme.getName()); //$NON-NLS-1$
}
break;
case SCHEME_CBSR_2_CHAR_ALPHA:
if (!scheme.getName().equals("CBSR 2 char alphabetic")) { //$NON-NLS-1$
throw new ApplicationException(
"labeling scheme is not " + scheme.getName()); //$NON-NLS-1$
}
break;
case SCHEME_2_CHAR_NUMERIC:
if (!scheme.getName().equals("2 char numeric")) { //$NON-NLS-1$
throw new ApplicationException(
"labeling scheme is not " + scheme.getName()); //$NON-NLS-1$
}
break;
case SCHEME_DEWAR:
if (!scheme.getName().equals("Dewar")) { //$NON-NLS-1$
throw new ApplicationException(
"labeling scheme is not " + scheme.getName()); //$NON-NLS-1$
}
break;
case SCHEME_CBSR_SBS:
if (!scheme.getName().equals("CBSR SBS")) { //$NON-NLS-1$
throw new ApplicationException(
"labeling scheme is not " + scheme.getName()); //$NON-NLS-1$
}
break;
case SCHEME_2_CHAR_ALPHA:
if (!scheme.getName().equals("2 char alphabetic")) { //$NON-NLS-1$
throw new ApplicationException(
"labeling scheme is not " + scheme.getName()); //$NON-NLS-1$
}
break;
default:
throw new ApplicationException(
"labeling scheme with id " + id //$NON-NLS-1$
+ " is not mapped correctly"); //$NON-NLS-1$
}
allSchemes.put(id, new ContainerLabelingSchemeWrapper(
appService, scheme));
}
}
}
return allSchemes;
}
public static ContainerLabelingSchemeWrapper getLabelingSchemeById(
WritableApplicationService appService, Integer id)
throws ApplicationException {
getAllLabelingSchemesMap(appService);
ContainerLabelingSchemeWrapper scheme = allSchemes.get(id);
if (scheme == null) {
throw new ApplicationException("labeling scheme with id " + id //$NON-NLS-1$
+ " does not exist"); //$NON-NLS-1$
}
return scheme;
}
@Override
public int compareTo(ModelWrapper<ContainerLabelingScheme> o) {
return 0;
}
@Deprecated
@Override
public void persist() throws Exception {
super.persist();
resetAllSchemes();
}
@Deprecated
@Override
public void delete() throws Exception {
super.delete();
resetAllSchemes();
}
private static synchronized void resetAllSchemes() {
allSchemes = null;
}
/**
* Check labeling scheme limits for a given gridsize
**/
public static boolean checkBounds(WritableApplicationService appService,
Integer labelingScheme, Integer totalRows, Integer totalCols) {
if (totalRows == null || totalRows <= 0 || totalCols == null
|| totalCols <= 0) {
return false;
}
try {
getAllLabelingSchemesMap(appService);
} catch (ApplicationException e) {
throw new RuntimeException(
"could not load container labeling schemes"); //$NON-NLS-1$
}
ContainerLabelingSchemeWrapper schemeWrapper = allSchemes
.get(labelingScheme);
if (schemeWrapper != null) {
return schemeWrapper.checkBounds(totalRows, totalCols);
}
return false;
}
/**
* Check labeling scheme limits for a given gridsize
**/
public boolean checkBounds(int totalRows, int totalCols) {
Integer maxRows = getMaxRows();
Integer maxCols = getMaxCols();
Integer maxCapacity = getMaxCapacity();
boolean isInBounds = true;
if (maxRows != null) {
isInBounds &= totalRows <= maxRows;
}
if (maxCols != null) {
isInBounds &= totalCols <= maxCols;
}
if (maxCapacity != null) {
isInBounds &= totalRows * totalCols <= maxCapacity;
}
return isInBounds;
}
public static boolean canLabel(ContainerLabelingScheme scheme,
Capacity capacity) {
boolean canLabel = true;
if (canLabel && scheme.getMaxRows() != null) {
canLabel &= capacity.getRowCapacity() <= scheme.getMaxRows();
}
if (canLabel && scheme.getMaxCols() != null) {
canLabel &= capacity.getColCapacity() <= scheme.getMaxCols();
}
if (canLabel && scheme.getMaxCapacity() != null) {
int max = capacity.getRowCapacity() * capacity.getColCapacity();
canLabel &= max <= scheme.getMaxCapacity();
}
return canLabel;
}
private static final String POS_LABEL_LEN_QRY =
"select min(minChars), max(maxChars) from " //$NON-NLS-1$
+ ContainerLabelingScheme.class.getName();
public static List<Integer> getPossibleLabelLength(
WritableApplicationService appService) throws ApplicationException {
HQLCriteria rangeQuery = new HQLCriteria(POS_LABEL_LEN_QRY);
Object[] minMax = (Object[]) appService.query(rangeQuery).get(0);
List<Integer> validLengths = new ArrayList<Integer>();
for (int i = (Integer) minMax[0]; i < (Integer) minMax[1] + 1; i++) {
validLengths.add(i);
}
return validLengths;
}
/**
* Get the rowColPos corresponding to the given SBS standard 2 or 3 char
* string position. Could be A2 or F12.
*/
public static RowColPos sbsToRowCol(WritableApplicationService appService,
String pos) throws Exception {
ContainerLabelingSchemeWrapper scheme = getLabelingSchemeById(
appService, SCHEME_SBS);
if (scheme == null) {
throw new BiobankCheckException(
Messages
.getString("ContainerLabelingSchemeWrapper.sbs.not.found.msg")); //$NON-NLS-1$
}
if ((pos.length() != scheme.getMinChars())
&& (pos.length() != scheme.getMaxChars())) {
throw new Exception("binPos has an invalid length: " + pos); //$NON-NLS-1$
}
int row = SBS_ROW_LABELLING_PATTERN.indexOf(pos.charAt(0));
int col = Integer.parseInt(pos.substring(1)) - 1;
if (row == -1 || col == -1) return null;
return new RowColPos(row, col);
}
/**
* Get the rowColPos corresponding to the given CBSR SBS 2 char string
* position. Could be A2 or F9. (CBSR SBS skip I and O)
*/
public static RowColPos cbsrSbsToRowCol(
WritableApplicationService appService, String pos) throws Exception {
ContainerLabelingSchemeWrapper scheme = getLabelingSchemeById(
appService, SCHEME_CBSR_SBS);
if (scheme == null) {
throw new BiobankCheckException(
Messages
.getString("ContainerLabelingSchemeWrapper.cbsr.sbs.not.found.msg")); //$NON-NLS-1$
}
if ((pos.length() != scheme.getMinChars())
&& (pos.length() != scheme.getMaxChars())) {
throw new Exception("binPos has an invalid length: " + pos); //$NON-NLS-1$
}
int row = BOX81_LABELLING_PATTERN.indexOf(pos.charAt(0));
if (row == -1) return null;
int col = Integer.parseInt(pos.substring(1)) - 1;
if (row == -1 || col == -1) return null;
return new RowColPos(row, col);
}
/**
* Get the string corresponding to the given RowColPos and using the SBS
* standard. 2:1 will return C2.
*/
public static String rowColToSbs(RowColPos rcp) {
if (rcp.getRow() < 0
|| rcp.getRow() > SBS_ROW_LABELLING_PATTERN.length() - 1)
return null;
return "" + SBS_ROW_LABELLING_PATTERN.charAt(rcp.getRow())
+ (rcp.getCol() + 1);
}
/**
* Get the string corresponding to the given RowColPos and using the SBS
* standard. 2:1 will return C2.
*/
private static String rowColtoCbsrSbs(RowColPos rcp) {
if (rcp.getRow() < 0
|| rcp.getRow() > BOX81_LABELLING_PATTERN.length() - 1)
return null;
return "" + BOX81_LABELLING_PATTERN.charAt(rcp.getRow())
+ (rcp.getCol() + 1);
}
/**
* get the RowColPos in the given container corresponding to the given label
* AB and will return 1:0.
*/
public static RowColPos cbsrTwoCharToRowCol(
WritableApplicationService appService, String label, int rowCap,
int colCap, String containerTypeName) throws Exception {
ContainerLabelingSchemeWrapper scheme = getLabelingSchemeById(
appService, SCHEME_CBSR_2_CHAR_ALPHA);
if (scheme == null) {
throw new BiobankCheckException(
Messages
.getString("ContainerLabelingSchemeWrapper.cbsr.2char.alpha.not.found.msg")); //$NON-NLS-1$
}
int len = label.length();
if ((len != scheme.getMinChars()) && (len != scheme.getMaxChars()))
throw new Exception(
MessageFormat.format(
Messages
.getString("ContainerLabelingSchemeWrapper.characters.length.msg"), scheme.getMinChars())); //$NON-NLS-1$
int index1 = CBSR_2_CHAR_LABELLING_PATTERN.indexOf(label
.charAt(len - 2));
int index2 = CBSR_2_CHAR_LABELLING_PATTERN.indexOf(label
.charAt(len - 1));
if ((index1 < 0) || (index2 < 0)) {
throw new Exception(
Messages
.getString("ContainerLabelingSchemeWrapper.invalid.charac.msg")); //$NON-NLS-1$
}
int pos = index1 * CBSR_2_CHAR_LABELLING_PATTERN.length() + index2;
if (pos >= rowCap * colCap) {
String maxValue = ContainerLabelingSchemeWrapper
.rowColToCbsrTwoChar(new RowColPos(rowCap - 1, colCap - 1),
rowCap, colCap);
String msgStart =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.label.not.exists.msg"), //$NON-NLS-1$
label);
if (containerTypeName != null)
msgStart =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.label.not.exists.in.type.msg"), label, //$NON-NLS-1$
containerTypeName);
String msgMax =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.scheme.max.value.msg"), maxValue, //$NON-NLS-1$
rowCap, colCap);
throw new BiobankCheckException(msgStart + " " + msgMax); //$NON-NLS-1$
}
Integer row = pos % rowCap;
Integer col = pos / rowCap;
RowColPos rowColPos = new RowColPos(row, col);
return rowColPos;
}
/**
* get the RowColPos in the given container corresponding to the given label
* AB and will return 1:0.
*/
public static RowColPos twoCharToRowCol(
WritableApplicationService appService, String label, int rowCap,
int colCap, String containerTypeName) throws Exception {
ContainerLabelingSchemeWrapper scheme = getLabelingSchemeById(
appService, SCHEME_2_CHAR_ALPHA);
if (scheme == null) {
throw new BiobankCheckException(
Messages
.getString("ContainerLabelingSchemeWrapper.2char.alpha.not.found.msg")); //$NON-NLS-1$
}
int len = label.length();
if ((len != scheme.getMinChars()) && (len != scheme.getMaxChars()))
throw new Exception(
MessageFormat.format(
Messages
.getString("ContainerLabelingSchemeWrapper.characters.length.msg"), //$NON-NLS-1$
scheme.getMinChars()));
int index1 = TWO_CHAR_LABELLING_PATTERN.indexOf(label.charAt(len - 2));
int index2 = TWO_CHAR_LABELLING_PATTERN.indexOf(label.charAt(len - 1));
if ((index1 < 0) || (index2 < 0)) {
throw new Exception(
Messages
.getString("ContainerLabelingSchemeWrapper.invalid.charac.msg")); //$NON-NLS-1$
}
int pos = index1 * TWO_CHAR_LABELLING_PATTERN.length() + index2;
if (pos >= rowCap * colCap) {
String maxValue = ContainerLabelingSchemeWrapper
.rowColToCbsrTwoChar(new RowColPos(rowCap - 1, colCap - 1),
rowCap, colCap);
String msgStart =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.label.not.exists.msg"), //$NON-NLS-1$
label);
if (containerTypeName != null)
msgStart =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.label.not.exists.in.type.msg"), label, //$NON-NLS-1$
containerTypeName);
String msgMax =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.scheme.max.value.msg"), maxValue, //$NON-NLS-1$
rowCap, colCap);
throw new BiobankCheckException(msgStart + " " + msgMax); //$NON-NLS-1$
}
Integer row = pos % rowCap;
Integer col = pos / rowCap;
RowColPos rowColPos = new RowColPos(row, col);
return rowColPos;
}
/**
* Get the RowColPos in the given container corresponding to the given label
* using the 2 char numeric labelling.
*/
public static RowColPos twoCharNumericToRowCol(
WritableApplicationService appService, String label, int totalRows)
throws Exception {
ContainerLabelingSchemeWrapper scheme = getLabelingSchemeById(
appService, SCHEME_2_CHAR_NUMERIC);
if (scheme == null) {
throw new BiobankCheckException(
Messages
.getString("ContainerLabelingSchemeWrapper.2char.numeric.not.found.msg")); //$NON-NLS-1$
}
String errorMsg =
MessageFormat
.format(
Messages
.getString("ContainerLabelingSchemeWrapper.characters.length.incorrect.msg"), label); //$NON-NLS-1$
int len = label.length();
if ((len != scheme.getMinChars()) && (len != scheme.getMaxChars()))
throw new Exception(errorMsg);
try {
int pos = Integer.parseInt(label) - 1;
// has remove 1 because the two char numeric starts at 1
Integer row = pos % totalRows;
Integer col = pos / totalRows;
RowColPos rowColPos = new RowColPos(row, col);
return rowColPos;
} catch (NumberFormatException nbe) {
throw new Exception(errorMsg);
}
}
/**
* Convert a position in row*column to two letter (in the CBSR way)
*
* @throws Exception
*
* @throws BiobankCheckException
*/
public static String rowColToCbsrTwoChar(RowColPos rcp, int totalRows,
int totalCols) {
int pos1, pos2, index;
int lettersLength = CBSR_2_CHAR_LABELLING_PATTERN.length();
if (totalRows == 1) {
index = rcp.getCol();
} else if (totalCols == 1) {
index = rcp.getRow();
} else {
index = totalRows * rcp.getCol() + rcp.getRow();
}
pos1 = index / lettersLength;
pos2 = index % lettersLength;
if (pos1 >= 0 && pos2 >= 0) {
return String.valueOf(CBSR_2_CHAR_LABELLING_PATTERN.charAt(pos1))
+ String.valueOf(CBSR_2_CHAR_LABELLING_PATTERN.charAt(pos2));
}
return null;
}
/**
* Convert a position in row*column to two letter (in the CBSR way)
*
* @throws Exception
*
* @throws BiobankCheckException
*/
public static String rowColToTwoChar(RowColPos rcp, int totalRows,
int totalCols) {
int pos1, pos2, index;
int lettersLength = TWO_CHAR_LABELLING_PATTERN.length();
if (totalRows == 1) {
index = rcp.getCol();
} else if (totalCols == 1) {
index = rcp.getRow();
} else {
index = totalRows * rcp.getCol() + rcp.getRow();
}
pos1 = index / lettersLength;
pos2 = index % lettersLength;
if (pos1 >= 0 && pos2 >= 0) {
return String.valueOf(TWO_CHAR_LABELLING_PATTERN.charAt(pos1))
+ String.valueOf(TWO_CHAR_LABELLING_PATTERN.charAt(pos2));
}
return null;
}
/**
* Convert a position in row*column to two char numeric.
*/
public static String rowColToTwoCharNumeric(RowColPos rcp, int totalRows) {
return String.format("%02d", rcp.getRow() + totalRows * rcp.getCol() //$NON-NLS-1$
+ 1);
}
/**
* Convert a position in row*column to Dewar labelling (AA, BB, CC...).
*/
public static String rowColToDewar(RowColPos rcp, Integer colCapacity) {
int pos = rcp.getCol() + (colCapacity * rcp.getRow());
String letter = String.valueOf(SBS_ROW_LABELLING_PATTERN.charAt(pos));
return letter + letter;
}
/**
* Get the RowColPos in the given container corresponding to the given label
* using the dewar labelling.
*
* @throws Exception
*/
public static RowColPos dewarToRowCol(
WritableApplicationService appService, String label, int totalCol)
throws Exception {
ContainerLabelingSchemeWrapper scheme = getLabelingSchemeById(
appService, SCHEME_DEWAR);
if (scheme == null) {
throw new BiobankCheckException(
Messages
.getString("ContainerLabelingSchemeWrapper.cbsr.2char.alpha.not.found.msg")); //$NON-NLS-1$
}
int len = label.length();
if ((len != scheme.getMinChars()) && (len != scheme.getMaxChars()))
throw new Exception(
MessageFormat.format(
Messages
.getString("ContainerLabelingSchemeWrapper.characters.length.msg"), scheme.getMinChars())); //$NON-NLS-1$
if (label.charAt(0) != label.charAt(1)) {
throw new Exception(
Messages
.getString("ContainerLabelingSchemeWrapper.letter.double.msg")); //$NON-NLS-1$
}
// letters are double (BB). need only one
int letterPosition = SBS_ROW_LABELLING_PATTERN.indexOf(label.charAt(0));
if (letterPosition == -1) return null;
Integer row = letterPosition / totalCol;
Integer col = letterPosition % totalCol;
RowColPos rowColPos = new RowColPos(row, col);
return rowColPos;
}
/**
* Get the 2 char string corresponding to a RowColPos position given the
* container capacity
*/
public static String getPositionString(RowColPos rcp,
Integer childLabelingSchemeId, Integer rowCapacity, Integer colCapacity) {
switch (childLabelingSchemeId) {
case 1:
// SBS standard
return rowColToSbs(rcp);
case 2:
// CBSR 2 char alphabetic
return rowColToCbsrTwoChar(rcp, rowCapacity, colCapacity);
case 3:
// 2 char numeric
return rowColToTwoCharNumeric(rcp, rowCapacity);
case 4:
// dewar
return rowColToDewar(rcp, colCapacity);
case 5:
// CBSR SBS
return rowColtoCbsrSbs(rcp);
case 6:
// 2 char alphabetic
return rowColToTwoChar(rcp, rowCapacity, colCapacity);
}
return null;
}
/**
* Get the RowColPos position corresponding to the string position given the
* container capacity
*/
public static RowColPos getRowColFromPositionString(
WritableApplicationService appService, String position,
Integer childLabelingSchemeId, Integer rowCapacity, Integer colCapacity)
throws Exception {
switch (childLabelingSchemeId) {
case 1:
// SBS standard
return sbsToRowCol(appService, position);
case 2:
// CBSR 2 char alphabetic
return cbsrTwoCharToRowCol(appService, position, rowCapacity,
colCapacity, null);
case 3:
// 2 char numeric
return twoCharNumericToRowCol(appService, position, rowCapacity);
case 4:
// Dewar
return dewarToRowCol(appService, position, colCapacity);
case 5:
// Box81
return cbsrSbsToRowCol(appService, position);
case 6:
// 2 char alphabetic
return twoCharToRowCol(appService, position, rowCapacity,
colCapacity, null);
}
return null;
}
@Deprecated
@Override
protected void addDeleteTasks(TaskList tasks) {
tasks.add(check().notUsedBy(ContainerType.class,
ContainerTypePeer.CHILD_LABELING_SCHEME));
super.addDeleteTasks(tasks);
}
}