All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.jessemull.microflexbigdecimal.plate.WellPrecursor Maven / Gradle / Ivy

The newest version!
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* ---------------------- Package ----------------------- */

package com.github.jessemull.microflexbigdecimal.plate;

/* -------------------- Dependencies -------------------- */

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.builder.HashCodeBuilder;

import com.google.common.base.Preconditions;

/**
 * This class represents a well in a microplate. It contains the the logic to 
 * convert row letters to integers and vice-versa, enforces the correct format 
 * for well IDs and holds a list of data set values. The well object does not 
 * check for wells outside a specified range. This logic is housed within the 
 * plate object.
 * 
 * All the classes in the microplate library are designed to be flexible in
 * order to accommodate data in a variety of formats. The well object constructor
 * accepts well IDs in each of the following formats:
 * 
 * 
 *    
 *    
 *    
 *    
 *       
 *       
 *       
 *    
 *    
 *       
 *       
 *       
 *    
 *    
 *       
 *       
 *       
 *    
 *    
 *       
 *       
 *       
 *    
 *    
 *       
 *       
 *       
 *    
 *    
 *       
 *       
 *       
 *    
 *    
 *       
 *       
 *       
 *    
 * 
Row
Column
Input
IntegerIntegerRow = 1 Column = 2
StringIntegerRow = "1" Column = 2
StringIntegerRow = "A" Column = 2
IntegerStringRow = 1 Column = "2"
StringStringRow = "A" Column = "2"
StringStringRow = "1" Column = "2"
StringString"A2" Input must be [A-Za-z]+[0-9]+
* * The Well class also implements both hash code and equals functions in order to * prevent duplicate wells within a single plate object. * * The well constructor is passed a flag holding the numerical data type. Once * set, the numerical data type cannot be changed. The MicroFlex library supports * wells containing all primitive numerical types for input and output as well * as two immutable types: BigDecimal and BigInteger. * * @author Jesse L. Mull * @update Updated Oct 18, 2016 * @address http://www.jessemull.com * @email [email protected] */ public abstract class WellPrecursor implements Comparable> { /* --------------------------- Public Fields ---------------------------- */ public static final int DOUBLE = 0; public static final int INTEGER = 1; public static final int BIGDECIMAL = 2; public static final int BIGINTEGER = 3; /* --------------------------- Private Fields --------------------------- */ private int row; // Well row private int column; // Well column private int type; // Numerical data type private int ALPHA_BASE = 26; // Number of char types available for the row ID private String digits = "\\d+$"; // Numerals only regex private String letters = "^[A-Z]+"; // Letters only regex private String alphaOnly = "^[A-Za-z]+[0-9]+$"; // Alphanumeric characters only private Pattern digitsPattern = Pattern.compile(digits); // Numeral only pattern private Pattern lettersPattern = Pattern.compile(letters); // Letters only pattern private Pattern alphaOnlyPattern = Pattern.compile(alphaOnly); // Alphanumeric characters only pattern /* ---------------------------- Constructors ---------------------------- */ /** * Creates a new Well object from row and column integers. * @param int the well row * @param int the well column */ public WellPrecursor(int type, int row, int column) { this.validateType(type); this.validateIndices(row, column); this.type = type; this.row = row; this.column = column; } /** * Creates a new Well object using the numerical type flag, row string and * column number. * @param int the numerical data type * @param String the well row * @param int the well column */ public WellPrecursor(int type, String row, int column) { try { this.row = Integer.decode(row); } catch(NumberFormatException e) { this.row = parseRow(row); } this.column = column; this.type = type; validateIndices(this.row, this. column); } /** * Creates a new Well object using the numerical type flag, row number and * column string. * @param int the numerical data type * @param int the well row * @param String the well column * @throws IllegalArgumentException invalid column value */ public WellPrecursor(int type, int row, String column) { this.row = row; this.type = type; try { this.column = Integer.decode(column); } catch(Exception e) { throw new IllegalArgumentException("Illegal column value: " + column); } validateIndices(this.row, this. column); } /** * Creates a new Well object using the numerical type flag, row and column * strings. * @param int the numerical data type * @param String the well row * @param String the well column * @throws IllegalArgumentException invalid column value */ public WellPrecursor(int type, String row, String column) { try { this.row = Integer.decode(row); } catch(NumberFormatException e) { this.row = parseRow(row); } try { this.column = Integer.decode(column); } catch(Exception e) { throw new IllegalArgumentException("Illegal column value: " + column); } this.type = type; validateIndices(this.row, this. column); } /** * Creates a new Well object from a string holding the column and row values. * The string must be in the format [a-ZA-Z]+[0-9]+ * @param int the numerical data type * @param String the well index */ public WellPrecursor(int type, String wellID) { this.type = type; String upper = wellID.toUpperCase().trim(); Matcher digitsMatcher = digitsPattern.matcher(upper); Matcher lettersMatcher = lettersPattern.matcher(upper); Matcher alphasOnlyMatcher = alphaOnlyPattern.matcher(upper); /* Alphas matcher enforces the correct format for the well ID */ if(alphasOnlyMatcher.find()) { lettersMatcher.find(); digitsMatcher.find(); this.row = parseRow(lettersMatcher.group(0).trim()); try { this.column = Integer.decode(digitsMatcher.group(0)); } catch(NumberFormatException e) { throw new IllegalArgumentException("Invalid column ID: " + digitsMatcher.group(0).trim()); } } else { throw new IllegalArgumentException("Invalid well index: " + wellID); } validateIndices(this.row, this. column); } /** * Clones a well without invoking clone. * @param WellPrecursor the well to clone */ public WellPrecursor(WellPrecursor well) { this.type = well.type(); this.row = well.row(); this.column = well.column(); } /* --------------------------- Private Methods -------------------------- */ /** * Converts a row ID to an integer value. * @param String the row as a string * @return the row as an integer value */ private int parseRow(String rowString) { int rowInt = 0; int baseIndex = 1; String upper = rowString.toUpperCase().trim(); Matcher lettersMatcher = lettersPattern.matcher(upper); if(lettersMatcher.find()) { String letters = lettersMatcher.group(0); rowInt = letters.charAt(letters.length() - 1) - 65; for(int i = letters.length() - 2; i >= 0; i--) { rowInt += (letters.charAt(i) - 65 + 1) * Math.pow(ALPHA_BASE, baseIndex++); } return rowInt; } else { throw new IllegalArgumentException("Invalid row ID: " + row); } } /** * Returns the well index as a letter(s) number pair. * @return the index */ public String index() { return this.rowString() + this.column; } /** * Returns the numerical data type as an integer value. * @return numerical data type integer */ public int type() { return this.type; } /** * Returns the numerical data type as a String. * @return numerical data type String */ public String typeString() { switch(this.type) { case 0: return "Double"; case 1: return "Integer"; case 2: return "BigDecimal"; case 3: return "BigInteger"; default: return "Undefined numerical data type."; } } /** * Returns the column number. * @return the column number */ public int column() { return this.column; } /** * Returns the row number. * @return the row number */ public int row() { return this.row; } /** * Returns the alpha base value. * @return the alpha base value */ public int alphaBase() { return this.ALPHA_BASE; } /** * Returns the row ID. * @return row ID */ public String rowString() { int rowInt = this.row; String rowString = ""; while (rowInt >= 0) { rowString = (char) (rowInt % ALPHA_BASE + 65) + rowString; rowInt = (rowInt / ALPHA_BASE) - 1; } return rowString; } /** * Returns row ID plus column number. * @return row ID plus column number */ public String toString() { String array = "["; int index; for(index = 0; index < this.data().size() - 1; index++) { array += this.data().get(index) + ", "; } array += this.data().get(index) + "]"; return rowString() + this.column + " " + array; } /** * Checks that the row and column integer values have a positive sign. * @param int the row value * @param int the column value */ private void validateIndices(int row, int column) { Preconditions.checkArgument(row >= 0, "Invalid row index: %s. Row value must be a positive value.", row); Preconditions.checkArgument(column > 0, "Invalid column index: %s. Column value must be greater than zero.", column); } /** * Checks type flag for invalid values. * @param int the numerical data type */ private void validateType(int type) { if(type < 0 || type > 3) { throw new IllegalArgumentException("Invalid numerical data type: " + type + "."); } } /** * Hash code uses the row, column and ALPHA_BASE fields. * @return the hash code */ public int hashCode() { return new HashCodeBuilder(17, 37). append(this.row). append(this.column). append(this.ALPHA_BASE). toHashCode(); } /** * Wells are ordered based on row and column number. * @param WellPrecursor the object for comparison * @return this == well --> 0 * this > well --> 1 * this < well --> -1 */ public int compareTo(WellPrecursor well) throws ClassCastException { if(this.equals(well)) { return 0; } if(this.row() > well.row()) { return 1; } else if(this.row() != well.row()) { return -1; } if(this.column() > well.column()) { return 1; } else if(this.column() != well.column()) { return -1; } return 0; } public abstract List data(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy