package edu.ualberta.med.biobank.forms.utils; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.events.MouseEvent; import org.eclipse.ui.PlatformUI; import org.springframework.remoting.RemoteConnectFailureException; import edu.ualberta.med.biobank.BiobankPlugin; import edu.ualberta.med.biobank.SessionManager; import edu.ualberta.med.biobank.common.action.scanprocess.CellInfoStatus; import edu.ualberta.med.biobank.common.util.RowColPos; import edu.ualberta.med.biobank.common.wrappers.ContainerTypeWrapper; import edu.ualberta.med.biobank.common.wrappers.ContainerWrapper; import edu.ualberta.med.biobank.common.wrappers.SpecimenWrapper; import edu.ualberta.med.biobank.dialogs.ScanOneTubeDialog; import edu.ualberta.med.biobank.gui.common.BgcPlugin; import edu.ualberta.med.biobank.model.ContainerType; import edu.ualberta.med.biobank.widgets.grids.ScanPalletWidget; import edu.ualberta.med.biobank.widgets.grids.cell.PalletCell; import edu.ualberta.med.biobank.widgets.grids.cell.UICellStatus; import edu.ualberta.med.scannerconfig.ScannerConfigPlugin; import edu.ualberta.med.scannerconfig.dmscanlib.ScanCell; import edu.ualberta.med.scannerconfig.preferences.scanner.profiles.ProfileManager; import gov.nih.nci.system.applicationservice.ApplicationException; public class PalletScanManagement { protected Map<RowColPos, PalletCell> cells = new HashMap<RowColPos, PalletCell>(); private int scansCount = 0; private boolean useScanner = true; private boolean scanTubeAloneMode = true; private ContainerType type; public PalletScanManagement() { try { this.type = ContainerTypeWrapper.getContainerTypesPallet96(SessionManager .getAppService(), SessionManager.getUser() .getCurrentWorkingSite()).get(0).getWrappedObject(); } catch (ApplicationException e) { BgcPlugin.openAsyncError("Error", "Unable to load pallet type 96", e); } } public PalletScanManagement(ContainerType containerType) { this.type = containerType; } public void launchScanAndProcessResult(final String plateToScan) { launchScanAndProcessResult(plateToScan, ProfileManager.ALL_PROFILE_NAME, false); } public void launchScanAndProcessResult(final String plateToScan, final String profile, final boolean isRescanMode) { IRunnableWithProgress op = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) { monitor.beginTask("Scan and process...", IProgressMonitor.UNKNOWN); try { launchScan(monitor, plateToScan, profile, isRescanMode); processScanResult(monitor); afterScanAndProcess(); } catch (RemoteConnectFailureException exp) { BgcPlugin.openRemoteConnectErrorMessage(exp); scanAndProcessError(null); } catch (Exception e) { BgcPlugin .openAsyncError( "Scan result error", e); String msg = e.getMessage(); if ((msg == null || msg.isEmpty()) && e.getCause() != null) { msg = e.getCause().getMessage(); } scanAndProcessError("ERROR: " + msg); } monitor.done(); } }; try { beforeThreadStart(); new ProgressMonitorDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell()).run(true, false, op); } catch (Exception e) { throw new RuntimeException(e); } } private void launchScan(IProgressMonitor monitor, String plateToScan, String profile, boolean rescanMode) throws Exception { monitor.subTask("Launching scan"); beforeScan(); Map<RowColPos, PalletCell> oldCells = cells; if (BiobankPlugin.isRealScanEnabled()) { int plateNum = BiobankPlugin.getDefault().getPlateNumber( plateToScan); if (plateNum == -1) { plateError(); BgcPlugin .openAsyncError( "Scan error", NLS.bind( "Plate with barcode {0} is not enabled", plateToScan)); return; } List<ScanCell> scanCells = null; try { scanCells = ScannerConfigPlugin.decodePlate(plateNum, profile); cells = PalletCell.convertArray(scanCells); } catch (Exception ex) { BgcPlugin .openAsyncError( "Scan error", ex, "Barcodes can still be scanned with the handheld 2D scanner."); return; } finally { scansCount++; afterScanBeforeMerge(); } } else { cells = getFakeScanCells(); scansCount++; afterScanBeforeMerge(); } Map<String, PalletCell> cellValues = getValuesMap(cells); if (rescanMode && oldCells != null) { // rescan: merge previous scan with new in case the scanner // wasn't able to scan well boolean rescanDifferent = false; for (Entry<RowColPos, PalletCell> entry : oldCells.entrySet()) { RowColPos rcp = entry.getKey(); PalletCell oldScannedCell = entry.getValue(); PalletCell newScannedCell = cells.get(rcp); boolean copyOldValue = false; if (PalletCell.hasValue(oldScannedCell)) { copyOldValue = true; if (PalletCell.hasValue(newScannedCell) && !oldScannedCell.getValue().equals( newScannedCell.getValue())) { // Different values at same position oldScannedCell .setInformation((oldScannedCell.getInformation() != null ? oldScannedCell .getInformation() : "") + " " + "Rescanned value is different"); oldScannedCell.setStatus(CellInfoStatus.ERROR); rescanDifferent = true; } else if (!PalletCell.hasValue(newScannedCell)) { // previous position has value - new has none PalletCell newPosition = cellValues.get(oldScannedCell .getValue()); if (newPosition != null) { // still there but moved to another position, so // don't copy previous scanned position copyOldValue = false; } } } if (copyOldValue) { cells.put(rcp, oldScannedCell); } } if (rescanDifferent) throw new Exception( "Scan error: Previously scanned specimens has been replaced. Please cancel and start again."); } afterSuccessfulScan(); } public void scanTubeAlone(MouseEvent e) { if (isScanTubeAloneMode()) { RowColPos rcp = ((ScanPalletWidget) e.widget) .getPositionAtCoordinates(e.x, e.y); if (rcp != null) { PalletCell cell = cells.get(rcp); if (canScanTubeAlone(cell)) { String value = scanTubeAloneDialog(rcp); if (value != null && !value.isEmpty()) { if (cell == null) { cell = new PalletCell(new ScanCell(rcp.getRow(), rcp.getCol(), value)); cells.put(rcp, cell); } else { cell.setValue(value); } try { postprocessScanTubeAlone(cell); } catch (Exception ex) { BgcPlugin.openAsyncError( "Scan tube error", ex); } } } } } } protected boolean canScanTubeAlone( @SuppressWarnings("unused") PalletCell cell) { return true; } private String scanTubeAloneDialog(RowColPos rcp) { ScanOneTubeDialog dlg = new ScanOneTubeDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(), cells, rcp, type); if (dlg.open() == Dialog.OK) { return dlg.getScannedValue(); } return null; } private Map<String, PalletCell> getValuesMap( Map<RowColPos, PalletCell> cells) { Map<String, PalletCell> valuesMap = new HashMap<String, PalletCell>(); for (Entry<RowColPos, PalletCell> entry : cells.entrySet()) { PalletCell cell = entry.getValue(); valuesMap.put(cell.getValue(), cell); } return valuesMap; } protected void beforeThreadStart() { // default does nothing } protected void beforeScan() { // default does nothing } protected Map<RowColPos, PalletCell> getFakeScanCells() throws Exception { return null; } @SuppressWarnings("unused") protected void processScanResult(IProgressMonitor monitor) throws Exception { // default does nothing } @SuppressWarnings("unused") protected void postprocessScanTubeAlone(PalletCell cell) throws Exception { // default does nothing } protected void afterScanBeforeMerge() { // default does nothing } protected void afterSuccessfulScan() { // default does nothing } protected void afterScanAndProcess() { // default does nothing } protected void plateError() { // default does nothing } protected void scanAndProcessError( @SuppressWarnings("unused") String errorMsg) { // default does nothing } public Map<RowColPos, PalletCell> getCells() { return cells; } public void onReset() { scansCount = 0; initCells(); } public void setUseScanner(boolean useScanner) { this.useScanner = useScanner; } private void initCells() { cells = new HashMap<RowColPos, PalletCell>(); } public int getScansCount() { return scansCount; } public void toggleScanTubeAloneMode() { // might want to remove this toggle thing if users don't ask for it back // scanTubeAloneMode = !scanTubeAloneMode; } public boolean isScanTubeAloneMode() { return scanTubeAloneMode; } public void initCellsWithContainer(ContainerWrapper container) { if (!useScanner) { cells.clear(); for (Entry<RowColPos, SpecimenWrapper> entry : container .getSpecimens().entrySet()) { RowColPos rcp = entry.getKey(); PalletCell cell = new PalletCell(new ScanCell(rcp.getRow(), rcp.getCol(), entry.getValue().getInventoryId())); cell.setSpecimen(entry.getValue()); cell.setStatus(UICellStatus.FILLED); cells.put(rcp, cell); } } } public void setContainerType(ContainerType containerType) { this.type = containerType; } public ContainerType getContainerType() { return type; } }