// $HeadURL$
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.ui.libraries;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import org.apache.log4j.Logger;
import org.joda.time.LocalDate;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.LibrariesDAO;
import edu.harvard.med.screensaver.db.Criterion.Operator;
import edu.harvard.med.screensaver.db.datafetcher.EntityDataFetcher;
import edu.harvard.med.screensaver.db.hqlbuilder.HqlBuilder;
import edu.harvard.med.screensaver.model.MolarConcentration;
import edu.harvard.med.screensaver.model.Volume;
import edu.harvard.med.screensaver.model.libraries.ConcentrationStatistics;
import edu.harvard.med.screensaver.model.libraries.Copy;
import edu.harvard.med.screensaver.model.libraries.CopyUsageType;
import edu.harvard.med.screensaver.model.libraries.Library;
import edu.harvard.med.screensaver.model.libraries.LibraryType;
import edu.harvard.med.screensaver.model.libraries.PlateStatus;
import edu.harvard.med.screensaver.model.libraries.VolumeStatistics;
import edu.harvard.med.screensaver.model.meta.PropertyPath;
import edu.harvard.med.screensaver.model.meta.RelationshipPath;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.ui.activities.ActivitySearchResults;
import edu.harvard.med.screensaver.ui.arch.datatable.column.DateColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.FixedDecimalColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.IntegerColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.TableColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.VolumeColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.DateEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.EnumEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.FixedDecimalEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.IntegerEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.TextEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.model.InMemoryEntityDataModel;
import edu.harvard.med.screensaver.ui.arch.searchresults.EntityBasedEntitySearchResults;
import edu.harvard.med.screensaver.ui.arch.searchresults.SearchResults;
import edu.harvard.med.screensaver.util.StringUtils;
/**
* A {@link SearchResults} for {@link Copy Copies}.
*
* @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a>
*/
public class LibraryCopySearchResults extends EntityBasedEntitySearchResults<Copy,Integer>
{
private static final Logger log = Logger.getLogger(LibraryCopySearchResults.class);
protected static final int DECIMAL_SCALE = 1; // number of decimal digits (to the right of decimal point) for plate screening count average
private static final String COLUMN_GROUP_CONCENTRATION = "Concentration";
private GenericEntityDAO _dao;
private LibrariesDAO _librariesDao;
private LibraryCopyViewer _libraryCopyViewer;
private LibraryViewer _libraryViewer;
private ActivitySearchResults _activitesBrowser;
private LibraryCopyPlateSearchResults _libraryCopyPlateSearchResults;
/**
* @motivation for CGLIB2
*/
protected LibraryCopySearchResults()
{
}
public LibraryCopySearchResults(GenericEntityDAO dao,
LibrariesDAO librariesDao,
LibraryCopyViewer libraryCopyViewer,
LibraryViewer libraryViewer,
ActivitySearchResults activitiesBrowser,
LibraryCopyPlateSearchResults libraryCopyPlateSearchResults)
{
super(libraryCopyViewer);
_dao = dao;
_librariesDao = librariesDao;
_libraryCopyViewer = libraryCopyViewer;
_libraryViewer = libraryViewer;
_activitesBrowser = activitiesBrowser;
_libraryCopyPlateSearchResults = libraryCopyPlateSearchResults;
}
/**
* For command line usage only
*/
public LibraryCopySearchResults(GenericEntityDAO dao,
LibrariesDAO librariesDao)
{
super(null);
_dao = dao;
_librariesDao = librariesDao;
}
@Override
public void searchAll()
{
setTitle("Library Copies");
initialize(new EntityDataFetcher<Copy,Integer>(Copy.class, _dao));
}
public void searchCopiesByLibrary(final Library library)
{
setTitle("Library Copies for library " + library.getLibraryName());
EntityDataFetcher<Copy,Integer> copyDataFetcher =
new EntityDataFetcher<Copy,Integer>(Copy.class, _dao) {
@Override
public void addDomainRestrictions(HqlBuilder hql)
{
hql.where(getRootAlias(), Copy.library.getLeaf(), Operator.EQUAL, library);
}
};
initialize(copyDataFetcher);
}
private void initialize(EntityDataFetcher<Copy,Integer> copyDataFetcher)
{
initialize(new InMemoryEntityDataModel<Copy,Integer,Copy>(copyDataFetcher) {
@Override
public void fetch(List<? extends TableColumn<Copy,?>> columns)
{
super.fetch(columns);
_librariesDao.calculateCopyScreeningStatistics(_unfilteredData);
_librariesDao.calculateCopyVolumeStatistics(_unfilteredData);
}
});
}
@Override
protected List<TableColumn<Copy,?>> buildColumns()
{
List<TableColumn<Copy,?>> columns = Lists.newArrayList();
columns.add(new TextEntityColumn<Copy>(Copy.library,
"Library",
"The library that this copy represents",
TableColumn.UNGROUPED) {
@Override
public String getCellValue(Copy copy)
{
return copy.getLibrary().getLibraryName();
}
@Override
public boolean isCommandLink()
{
return true;
}
@Override
public Object cellAction(Copy copy)
{
return _libraryViewer.viewEntity(copy.getLibrary());
}
});
Iterables.getLast(columns).setVisible(!isNested());
columns.add(new EnumEntityColumn<Copy,ScreenType>(RelationshipPath.from(Copy.class).toProperty("library"),
"Screen Type", "'RNAi' or 'Small Molecule'",
TableColumn.UNGROUPED, ScreenType.values()) {
@Override
public ScreenType getCellValue(Copy copy)
{
return copy.getLibrary().getScreenType();
}
});
Iterables.getLast(columns).setVisible(false);
String names = Joiner.on("','").join(StringUtils.getVocabularyTerms(LibraryType.values()));
columns.add(new EnumEntityColumn<Copy,LibraryType>(RelationshipPath.from(Copy.class).toProperty("library"),
"Library Type", names,
TableColumn.UNGROUPED, LibraryType.values()) {
@Override
public LibraryType getCellValue(Copy copy)
{
return copy.getLibrary().getLibraryType();
}
});
Iterables.getLast(columns).setVisible(false);
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("name"),
"Copy Name",
"The name of the the copy",
TableColumn.UNGROUPED) {
@Override
public String getCellValue(Copy copy)
{
return copy.getName();
}
@Override
public boolean isCommandLink()
{
return true;
}
@Override
public Object cellAction(Copy copy)
{
if (isNested()) {
LibraryCopySearchResults libraryCopySearchResults = (LibraryCopySearchResults) _libraryCopyViewer.getContextualSearchResults();
libraryCopySearchResults.searchCopiesByLibrary(copy.getLibrary());
libraryCopySearchResults.findEntity(copy);
return BROWSE_LIBRARY_COPIES;
}
return viewSelectedEntity();
}
});
((TextEntityColumn<Copy>) Iterables.getLast(columns)).addRelationshipPath(Copy.library);
columns.add(new EnumEntityColumn<Copy,CopyUsageType>(PropertyPath.from(Copy.class).toProperty("usageType"),
"Usage Type",
"The usage type of the copy",
TableColumn.UNGROUPED,
CopyUsageType.values()) {
@Override
public CopyUsageType getCellValue(Copy copy)
{
return copy.getUsageType();
}
});
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("primaryPlateLocation"),
"Primary Plate Location",
"The most common plate location for plates of this copy",
TableColumn.UNGROUPED) {
@Override
public String getCellValue(Copy copy)
{
if (copy.getPrimaryPlateLocation() == null) {
return null;
}
return copy.getPrimaryPlateLocation().toDisplayString();
}
});
columns.add(new IntegerEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("plateLocationsCount"),
"Plate Locations",
"The number different plate locations found for plates of this copy",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getPlateLocationsCount();
}
});
columns.add(new EnumEntityColumn<Copy,PlateStatus>(PropertyPath.from(Copy.class).toProperty("primaryPlateStatus"),
"Primary Plate Status",
"The most common plate status for plates of this copy",
TableColumn.UNGROUPED,
PlateStatus.values()) {
@Override
public PlateStatus getCellValue(Copy copy)
{
return copy.getPrimaryPlateStatus();
}
});
buildConcentrationColumns(columns);
columns.add(new IntegerEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("platesAvailable"),
"Plates Available",
"The number of plates with a status of \"Available\"",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getPlatesAvailable();
}
});
columns.add(new FixedDecimalColumn<Copy>("Plate Screening Count Average",
"The average number of times this copy's plates have been screened, ignoring replicates",
TableColumn.UNGROUPED) {
@Override
public BigDecimal getCellValue(Copy copy)
{
if (copy.getScreeningStatistics().getPlateCount() == 0) return null;
if (copy.getScreeningStatistics().getPlateScreeningCount() == 0) return BigDecimal.ZERO;
BigDecimal val = new BigDecimal(copy.getScreeningStatistics().getPlateScreeningCount()).divide(new BigDecimal(copy.getScreeningStatistics().getPlateCount()),
DECIMAL_SCALE,
RoundingMode.CEILING);
return val;
}
});
columns.add(new VolumeColumn<Copy>("Average Plate Remaining Volume",
"The average well volume remaining across all library screening plates of this copy",
TableColumn.UNGROUPED) {
@Override
public Volume getCellValue(Copy copy)
{
return getNullSafeVolumeStatistics(copy).getAverageRemaining();
}
});
columns.add(new VolumeColumn<Copy>("Min Plate Remaining Volume",
"The minimum well volume remaining across all library screening plates of this copy",
TableColumn.UNGROUPED) {
@Override
public Volume getCellValue(Copy copy)
{
return getNullSafeVolumeStatistics(copy).getMinRemaining();
}
});
columns.add(new VolumeColumn<Copy>("Max Plate Remaining Volume",
"The maximum well volume remaining across all library screening plates of this copy",
TableColumn.UNGROUPED) {
@Override
public Volume getCellValue(Copy copy)
{
return getNullSafeVolumeStatistics(copy).getMaxRemaining();
}
});
columns.add(new DateColumn<Copy>("Last Date Screened",
"The date the copy was last screened",
TableColumn.UNGROUPED) {
@Override
public LocalDate getDate(Copy copy)
{
return copy.getScreeningStatistics().getLastDateScreened();
}
});
columns.add(new DateColumn<Copy>("First Date Screened",
"The date the copy was first screened",
TableColumn.UNGROUPED) {
@Override
public LocalDate getDate(Copy copy)
{
return copy.getScreeningStatistics().getFirstDateScreened();
}
});
columns.add(new DateEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("datePlated"),
"Date Plated",
"The earliest date on which a plate of this copy was created",
TableColumn.UNGROUPED) {
@Override
public LocalDate getDate(Copy copy)
{
return copy.getDatePlated();
}
});
columns.add(new IntegerEntityColumn<Copy>(Copy.library.toProperty("startPlate"),
"Start Plate",
"The first plate number of the library",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getLibrary().getStartPlate();
}
});
Iterables.getLast(columns).setVisible(!isNested());
columns.add(new IntegerEntityColumn<Copy>(Copy.library.toProperty("startPlate"),
"End Plate",
"The last plate number of the library",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getLibrary().getEndPlate();
}
});
Iterables.getLast(columns).setVisible(!isNested());
columns.add(new IntegerEntityColumn<Copy>(Copy.library,
"Library Plate Count",
"The number of plates in the library",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getLibrary().getEndPlate() - copy.getLibrary().getStartPlate() + 1;
}
});
Iterables.getLast(columns).setVisible(false);
columns.add(new IntegerColumn<Copy>("Copy Plate Count",
"The number of plates in this copy",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getScreeningStatistics().getPlateCount();
}
@Override
public boolean isCommandLink()
{
return true;
}
@Override
public Object cellAction(Copy copy)
{
_libraryCopyPlateSearchResults.searchPlatesForCopy(copy);
return BROWSE_LIBRARY_COPY_PLATES;
}
});
columns.add(new IntegerColumn<Copy>("Assay Plate Count",
"The number of assay plates screened for this copy",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getScreeningStatistics().getAssayPlateCount();
}
});
columns.add(new IntegerColumn<Copy>("Screening Count",
"The total number of times this copy has been screened, ignoring replicates",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getScreeningStatistics().getScreeningCount();
}
@Override
public boolean isCommandLink()
{
return true;
}
@Override
public Object cellAction(Copy copy)
{
_activitesBrowser.searchLibraryScreeningActivitiesForCopy(copy);
return BROWSE_ACTIVITIES;
}
});
columns.add(new IntegerColumn<Copy>("Plate Screening Count",
"The total number of times individual plates from this copy have been screened, ignoring replicates",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getScreeningStatistics().getPlateScreeningCount();
}
});
Iterables.getLast(columns).setVisible(false);
columns.add(new IntegerColumn<Copy>("Data Loading Count",
"The number of screen results loaded for screens of this copy",
TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(Copy copy)
{
return copy.getScreeningStatistics().getDataLoadingCount();
}
});
columns.add(new DateColumn<Copy>("First Date Data Loaded",
"The date of the first screen result data loading activity",
TableColumn.UNGROUPED) {
@Override
public LocalDate getDate(Copy copy)
{
return copy.getScreeningStatistics().getFirstDateDataLoaded();
}
});
Iterables.getLast(columns).setVisible(false);
columns.add(new DateColumn<Copy>("Last Date Data Loaded",
"The date of the last screen result data loading activity",
TableColumn.UNGROUPED) {
@Override
public LocalDate getDate(Copy copy)
{
return copy.getScreeningStatistics().getLastDateDataLoaded();
}
});
Iterables.getLast(columns).setVisible(false);
return columns;
}
private void buildConcentrationColumns(List<TableColumn<Copy,?>> columns)
{
// Concentration Columns
// molar values
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("minMolarConcentration"),
"Minimum Well Molar Concentration",
"The minimum molar concentration (diluted) of the wells of the copy's plates",
COLUMN_GROUP_CONCENTRATION) {
@Override
public String getCellValue(Copy copy)
{
MolarConcentration value = copy.getNullSafeConcentrationStatistics().getDilutedMinMolarConcentration(copy.getWellConcentrationDilutionFactor());
return value == null ? "n/a": value.toString();
}
});
Iterables.getLast(columns).setVisible(true);
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("maxMolarConcentration"),
"Maximum Well Molar Concentration",
"The maximum molar concentration (diluted) of the wells of the copy's plates",
COLUMN_GROUP_CONCENTRATION) {
@Override
public String getCellValue(Copy copy)
{
MolarConcentration value = copy.getNullSafeConcentrationStatistics().getDilutedMaxMolarConcentration(copy.getWellConcentrationDilutionFactor());
return value == null ? "n/a": value.toString();
}
});
Iterables.getLast(columns).setVisible(true);
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("primaryWellMolarConcentration"),
"Primary Well Molar Concentration",
"The value of the most frequent plate well molar concentration (diluted)",
COLUMN_GROUP_CONCENTRATION) {
@Override
public String getCellValue(Copy copy)
{
MolarConcentration value = copy.getNullSafeConcentrationStatistics().getDilutedPrimaryWellMolarConcentration(copy.getWellConcentrationDilutionFactor());
return value == null ? "n/a": value.toString();
}
});
Iterables.getLast(columns).setVisible(false);
// mg/mL
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("minMgMlConcentration"),
"Minimum Well Concentration (mg/mL)",
"The minimum mg/mL concentration (diluted) of the wells of the copy's plates",
COLUMN_GROUP_CONCENTRATION) {
@Override
public String getCellValue(Copy copy)
{
BigDecimal value = copy.getNullSafeConcentrationStatistics().getDilutedMinMgMlConcentration(copy.getWellConcentrationDilutionFactor());
return value == null ? "n/a" : value.toString();
}
});
Iterables.getLast(columns).setVisible(true);
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("maxMgMlConcentration"),
"Maximum Well Concentration (mg/mL)",
"The minimum mg/mL concentration (diluted) of the wells of the copy's plates",
COLUMN_GROUP_CONCENTRATION) {
@Override
public String getCellValue(Copy copy)
{
BigDecimal value = copy.getNullSafeConcentrationStatistics().getDilutedMaxMgMlConcentration(copy.getWellConcentrationDilutionFactor());
return value == null ? "n/a" : value.toString();
}
});
Iterables.getLast(columns).setVisible(true);
columns.add(new TextEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("primaryWellMgMlConcentration"),
"Primary Well Concentration (mg/mL)",
"The value of the most frequent plate well mg/mL concentration (diluted)",
COLUMN_GROUP_CONCENTRATION) {
@Override
public String getCellValue(Copy copy)
{
BigDecimal value = copy.getNullSafeConcentrationStatistics().getDilutedPrimaryWellMgMlConcentration(copy.getWellConcentrationDilutionFactor());
return value == null ? "n/a" : value.toString();
}
});
Iterables.getLast(columns).setVisible(false);
columns.add(new FixedDecimalEntityColumn<Copy>(PropertyPath.from(Copy.class).toProperty("wellConcentrationDilutionFactor"),
"Primary Well Concentration Dilution Factor",
"The most often ocurring factor by which the original library well concentration is diluted for this copy's plates",
COLUMN_GROUP_CONCENTRATION) {
@Override
public BigDecimal getCellValue(Copy copy)
{
return copy.getWellConcentrationDilutionFactor();
}
});
Iterables.getLast(columns).setVisible(true);
}
private static VolumeStatistics getNullSafeVolumeStatistics(Copy copy)
{
VolumeStatistics volumeStatistics = copy.getVolumeStatistics();
if (volumeStatistics == null) {
return VolumeStatistics.Null;
}
return volumeStatistics;
}
@Override
protected Copy rowToEntity(Copy row)
{
return row;
}
}