gda.scan.ScanDataPoint.java Source code

Java tutorial

Introduction

Here is the source code for gda.scan.ScanDataPoint.java

Source

/*-
 * Copyright  2009 Diamond Light Source Ltd., Science and Technology
 * Facilities Council Daresbury Laboratory
 *
 * This file is part of GDA.
 *
 * GDA is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License version 3 as published by the Free
 * Software Foundation.
 *
 * GDA is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along
 * with GDA. If not, see <http://www.gnu.org/licenses/>.
 */

package gda.scan;

import gda.data.DetectorDataWrapper;
import gda.data.PlottableDetectorData;
import gda.data.PlottableDetectorDataClone;
import gda.data.nexus.tree.NexusTreeProvider;
import gda.data.scan.datawriter.DataWriterBase;
import gda.device.Detector;
import gda.device.DeviceException;
import gda.device.Scannable;
import gda.device.scannable.ScannableUtils;
import gda.util.Serializer;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.ac.gda.util.map.MapUtils;

/**
 * This class holds information about the data collected at a single point on a scan. It is to be passed around between
 * objects for display \ recording of data.
 */
public class ScanDataPoint implements Serializable, IScanDataPoint {

    private static final Logger logger = LoggerFactory.getLogger(ScanDataPoint.class);

    private ScanInformation scanInfo = new ScanInformation();

    /**
     * The delimiter used by toString() method.
     */
    public static String delimiter = "\t";

    /**
     * The command typed to start the scan that this point is part of.
     */
    private String command = "";

    /**
     * The name of the gui panel which initiated this scan. This is used by the local JythonFacade to know which local
     * object to distribute this data point to for display.
     */
    private String creatorPanelName = "";

    //   /**
    //    * The result of calling {@link DataWriter#getCurrentFileName() getCurrentFilename()} on the {@link DataWriter}
    //    * owned by the scan which created this point. Could be used to uniquely identify where this data is being recorded
    //    * by the {@link DataWriter}.
    //    */
    //   private String currentFilename = "";

    /**
     * The current point number.
     */
    private int currentPointNumber = -1;

    /**
     * Vector<Object> of data from the detectors. Each element represents the data from the detector in the
     * corresponding element of the 'detectors' vector;
     */
    private Vector<Object> detectorData = new Vector<Object>();

    /**
     * The expanded header names for detectors in which the names are composed as detector name plus its element name.
     */
    private String[] detectorHeader = new String[0];

    //   /**
    //    * The detectors used in the scan.
    //    */
    //   private String[] detectorNames = new String[0];

    /**
     * The {@link gda.device.Detector} detectors that participate in the scan.
     */
    private transient Vector<Detector> detectors = new Vector<Detector>();

    /**
     * Formatting information for the scannable positions - used in the toString method. If an element is "" or null
     * then do not format that in the output.
     */
    private String[][] detectorFormats = new String[0][];

    //   /**
    //    * beamline name
    //    */
    //   private String instrument = "";
    //
    //   /**
    //    * total number of points in the scan
    //    */
    //   private int numberOfPoints = -1;

    /**
     * The expanded header names for scannable position in which the names are composed of the scannable name plus its
     * element name, i.e. scannable's InputNames and ExtraNames
     */
    private String[] scannableHeader = new String[0];

    /**
     * The current positions of the scannables. Each element represents the scannable in the corresponding element of
     * the 'scannables' vector;
     */
    private Vector<Object> scannablePositions = new Vector<Object>();

    /**
     * Formatting information for the scannable positions - used in the toString method.
     */
    private String[][] scannableFormats = new String[0][];

    //   /**
    //    * The scan identifier, such as the scan number.
    //    */
    //   private int scanIdentifier = -1;

    //   /**
    //    * The scannables which are part of the scan.
    //    */
    //   private String[] scannableNames = new String[0];

    /**
     * The {@link gda.device.Scannable} scannables that participate in the scan.
     */
    private transient Vector<Scannable> scannables = new Vector<Scannable>();

    /**
     * Unique identifier for the scan.
     */
    private String uniqueName = "";

    // values useful for plotting tools
    private List<IScanStepId> stepIds = new Vector<IScanStepId>();
    private int numberOfChildScans = 0;
    private ScanPlotSettings scanPlotSettings;
    /**
     * Is this data point contain child scan
     */
    private boolean hasChild = false;

    /**
     * 
     */
    public ScanDataPoint() {
    }

    /**
     * Unpack the ScanData object to fill this sdp rather than using accessor functions.
     * <p>
     * protected as only intended for use by the scandatapointserver
     * 
     * @param point
     * @param sdpt
     */
    protected ScanDataPoint(ScanData point, ScanDataPointVar sdpt) {
        uniqueName = point.uniqueName;
        scanInfo = point.scanInfo;
        //      scannableNames = point.scannableNames;
        //      detectorNames = point.detectorNames;
        scannableHeader = point.scannableHeader;
        detectorHeader = point.detectorHeader;
        hasChild = point.hasChild;
        //      scanIdentifier = point.scanIdentifier;
        creatorPanelName = point.creatorPanelName;
        //      currentFilename = point.currentFilename;
        numberOfChildScans = point.numberOfChildScans;
        //      instrument = point.instrument;
        //      numberOfPoints = point.numberOfPoints;
        command = point.command;
        scanPlotSettings = point.scanPlotSettings;
        //      scanDimensions = point.scanDimensions;

        currentPointNumber = sdpt.getCurrentPointNumber();
        detectorFormats = point.detectorFormats;
        scannableFormats = point.scannableFormats;

        scannablePositions = sdpt.getPositions();
        detectorData = sdpt.getDetectorData();

        Vector<IScanStepId> stepIds = new Vector<IScanStepId>();
        if (sdpt.getStepIds() != null) {
            Object[] dt = (Object[]) Serializer.toObject(sdpt.getStepIds());
            for (Object obj : dt) {
                stepIds.add((IScanStepId) obj);
            }
        }
        this.stepIds = stepIds;
    }

    /**
     * An alternative for populating this object. Can be used instead of repeated calls to
     * addScannable,addScannablePosition,addDetector,addDetectorData.
     * <p>
     * Note this makes calls to getPosition() in the scannables and readout() in the detectors.
     * 
     * @param allScannables
     * @param allDetectors
     * @throws DeviceException
     */
    @Override
    public void addScannablesAndDetectors(Vector<Scannable> allScannables, Vector<Detector> allDetectors)
            throws DeviceException {

        for (Scannable scannable : allScannables) {
            if (scannable.getOutputFormat().length == 0) {
                handleZeroInputExtraNameDevice(scannable);
            } else {
                this.addScannable(scannable);
                addPositionFromScannable(scannable);
            }
        }
        for (Detector scannable : allDetectors) {
            this.addDetector(scannable);
            addDataFromDetector(scannable);
        }
    }

    /**
     * Gets a Scannables position and adds it to the data point. Does not ass the Scannable itself.
     * 
     * @param scannable
     * @throws DeviceException
     */
    @Override
    public void addPositionFromScannable(Scannable scannable) throws DeviceException {
        this.addScannablePosition(scannable.getPosition(), scannable.getOutputFormat());
    }

    /**
     * Reads data from a detector and adds it to the point. Does not add the detector itself.
     * 
     * @param detector
     * @throws DeviceException
     */
    @Override
    public void addDataFromDetector(Detector detector) throws DeviceException {
        Object data = detector.readout();
        this.addDetectorData(data, ScannableUtils.getExtraNamesFormats(detector));
    }

    /**
     * Call getPosition on the zero-input-extra-names scannable. The zie must return null. This hook is used by some
     * Scannables to perform a task in a scan but return nothing.
     * 
     * @param zie
     * @throws DeviceException
     */
    static void handleZeroInputExtraNameDevice(Scannable zie) throws DeviceException {
        Object zeroInputExtraNameDevicePosition = zie.getPosition();
        if (zeroInputExtraNameDevicePosition != null) {
            final String msg = String.format(
                    "Scannable %s has no input or extra names defined. Its getPosition method should return null/None but returned: '%s'.",
                    zie.getName(), zeroInputExtraNameDevicePosition.toString());
            throw new DeviceException(msg);
        }
    }

    @Override
    public void addScannableWithPosition(Scannable scannable, Object position, String[] format) {
        this.addScannable(scannable);
        this.addScannablePosition(position, format);
    }

    /**
     * Add a piece of data to this object. Calls to this method must be made in the same order as calls to addDetector
     * to associate the data with the detector.
     * <p>
     * 
     * @param data
     */
    @Override
    public void addDetectorData(Object data, String[] format) {
        if (data != null) {
            this.detectorData.add(data);
            if (format == null || format.length == 0) {
                format = new String[] { "%s" };
            }
            detectorFormats = (String[][]) ArrayUtils.add(detectorFormats, format);
        }
    }

    /**
     * Replaces the detector data held by the object. The replacement vector must be the same length as the previous for
     * this sdp to be self-consistent.
     * <p>
     * protected as only intended for use by the scandatapointserver
     * 
     * @param newdata
     */
    protected void setDetectorData(Vector<Object> newdata, String[][] format) {
        this.detectorData = newdata;
        detectorFormats = format;
    }

    /**
     * Add a position to the array of positions. Calls to this method must be made in the same order as calls to
     * addScannable to associate the array of numbers with the scannable.
     * <p>
     * It is recommended to call setScannables instead.
     * 
     * @param data
     */
    @Override
    public void addScannablePosition(Object data, String[] format) {
        if (data != null) {
            scannablePositions.add(data);
            scannableFormats = (String[][]) ArrayUtils.add(scannableFormats, format);
        }
    }

    /**
     * Replaces the scannable positions data held by the object. The replacement array must be the same length as the
     * previous for this sdp to be self-consistent.
     * <p>
     * protected as only for use by the scandatapointserver
     * 
     * @param positions
     * @param formats
     */
    protected void setScannablePositions(Vector<Object> positions, String[][] formats) {
        this.scannablePositions = positions;
        this.scannableFormats = formats;
    }

    private String convertStringArrayToString(String[] array) {
        // Use StringBuilder rather than String addition for speed
        StringBuilder sb = new StringBuilder();
        sb.append("");

        boolean first = true;
        for (String s : array) {
            if (!first) {
                sb.append(delimiter);
            }
            sb.append(s);
            first = false;
        }
        return sb.toString();
    }

    /**
     * Add a detector to the list of detectors this object holds data from. This stores the name in the detectorHeader
     * array and detectorNames array. If its a countertimer is stored in the boolean array. The contents of the
     * detectorHeader and detectorNames arrays will be different if the detector is a countertimer.
     * <p>
     * Note this does not readout the detector! Data must be added by using the addData method.
     * 
     * @param det
     */
    @Override
    public void addDetector(Detector det) {
        //      detectorNames = (String[]) ArrayUtils.add(detectorNames, det.getName());
        scanInfo.setDetectorNames((String[]) ArrayUtils.add(scanInfo.getDetectorNames(), det.getName()));
        String[] extraNames = det.getExtraNames();
        if (extraNames != null && extraNames.length > 0) {
            detectorHeader = (String[]) ArrayUtils.addAll(detectorHeader, extraNames);
        } else {
            detectorHeader = (String[]) ArrayUtils.add(detectorHeader, det.getName());
        }
        detectors.add(det);
    }

    /**
     * Add a scannable to the list of scannables this object holds data on.
     * <p>
     * Note that this does not read the current position of the scannable.
     * 
     * @param scannable
     */
    @Override
    public void addScannable(Scannable scannable) {
        //      scannableNames = (String[]) ArrayUtils.add(scannableNames, scannable.getName());
        scanInfo.setScannableNames((String[]) ArrayUtils.add(scanInfo.getScannableNames(), scannable.getName()));
        scannableHeader = (String[]) ArrayUtils.addAll(scannableHeader, scannable.getInputNames());
        scannableHeader = (String[]) ArrayUtils.addAll(scannableHeader, scannable.getExtraNames());
        scannables.add(scannable);
    }

    /**
     * @return the gda command entered
     */
    @Override
    public String getCommand() {
        return command;
    }

    /**
     * Set the name of the panel which requested the scan which created this data point.
     * 
     * @return String
     */
    @Override
    public String getCreatorPanelName() {
        return creatorPanelName;
    }

    /**
     * @return String
     */
    @Override
    public String getCurrentFilename() {
        return scanInfo.getFilename();
    }

    /**
     * @return the current point number
     */
    @Override
    public int getCurrentPointNumber() {
        return currentPointNumber;
    }

    /**
     * Return the vector of detector data which this object is a carrier of.
     * 
     * @return Vector<Object>
     */
    @Override
    public Vector<Object> getDetectorData() {
        return detectorData;
    }

    Double[] allValuesAsDoubles = null;

    /**
     * Returns the values held by this ScanDataPoint of Scannables, Monitors and Detectors.
     * 
     * @return an array of Double of length getMonitorHeader().size() + getPositionHeader().size() +
     *         getDetectorHeader().size() if the conversion of a field to Double is not possible then the element of the
     *         array will be null
     * @throws IllegalArgumentException
     *             if the fields convert to too few values
     * @throws IndexOutOfBoundsException
     *             if the fields convert to too many values
     */
    @Override
    public Double[] getAllValuesAsDoubles() throws IllegalArgumentException, IndexOutOfBoundsException {
        if (allValuesAsDoubles == null) {
            Double[] scannablePosAsDoubles = getPositionsAsDoubles();
            Double[] detectorDataAsDoubles = getDetectorDataAsDoubles();

            Vector<Double> output = new Vector<Double>();
            output.addAll(Arrays.asList(scannablePosAsDoubles));
            output.addAll(Arrays.asList(detectorDataAsDoubles));
            allValuesAsDoubles = output.toArray(new Double[] {});
        }
        return allValuesAsDoubles;
    }

    /**
     * Just returns array of detector data.
     * 
     * @return all detector data.
     */
    @Override
    public Double[] getDetectorDataAsDoubles() {
        Vector<Double> vals = new Vector<Double>();
        if (getDetectorData() != null) {
            for (Object data : getDetectorData()) {
                PlottableDetectorData wrapper = (data instanceof PlottableDetectorData)
                        ? (PlottableDetectorData) data
                        : new DetectorDataWrapper(data);
                Double[] dvals = wrapper.getDoubleVals();
                vals.addAll(Arrays.asList(dvals));
            }
        }
        int expectedSize = getDetectorHeader().size();
        int actualSize = vals.size();
        if (actualSize != expectedSize) {
            throw new IllegalArgumentException("Detector data does not hold the expected number of fields actual:"
                    + actualSize + " expected:" + expectedSize);
        }
        return vals.toArray(new Double[] {});
    }

    /**
     * returns a vector of expanded detector header string for each data point.
     * 
     * @return a vector of expanded detector header string for each data point.
     */
    @Override
    public Vector<String> getDetectorHeader() {
        return new Vector<String>(Arrays.asList(detectorHeader));
    }

    /**
     * Return the list of names of detectors which this object holds data from.
     * 
     * @return Vector<String>
     */
    @Override
    public Vector<String> getDetectorNames() {
        return new Vector<String>(Arrays.asList(scanInfo.getDetectorNames()));
    }

    /**
     * The list of detectors this object refers to.
     * 
     * @return list of detectors this object refers to.
     */
    @Override
    public Vector<Detector> getDetectors() {
        return detectors;
    }

    @Override
    public boolean getHasChild() {
        return hasChild;
    }

    /**
     * Returns a string whose elements are separated by a mixture of tabs and spaces so that the columns are aligned
     * with the output from toString()
     * 
     * @return String - which could be used in an ascii print out of all the scan points from the same scan
     */
    @Override
    public String getHeaderString() {
        return getHeaderString(null);
    }

    @Override
    public String getHeaderString(ScanDataPointFormatter dataPointFormatter) {
        // work out the lengths of the header string and the lengths of each element from the toString method
        // and pad each to adjust

        String header = getDelimitedHeaderString();

        String data = toDelimitedString();

        String[] headerElements = header.split(delimiter);
        String[] dataElements = data.split(delimiter);

        if (headerElements.length != dataElements.length)
            throw new IllegalArgumentException("Number of parts in header '" + headerElements.length
                    + "' != number of parts in data '" + dataElements.length + "'");
        for (int i = 0; i < headerElements.length; i++) {
            int headerLength = headerElements[i].trim().length();
            int dataLength = dataElements[i].trim().length();

            int maxLength = dataLength > headerLength ? dataLength : headerLength;
            String format = "%" + maxLength + "s";

            headerElements[i] = String.format(format, headerElements[i].trim());
            dataElements[i] = String.format(format, dataElements[i].trim());
        }

        if (dataPointFormatter == null || !dataPointFormatter.isValid(this)) {
            return convertStringArrayToString(headerElements);
        }

        // Optionally a data formatter may be set on Scan data points.
        // This formats them in a custom format.
        return dataPointFormatter.getHeader(this, MapUtils.createLinkedMap(headerElements, dataElements));
    }

    @Override
    public String getDelimitedHeaderString() {
        String header = convertStringArrayToString(scannableHeader);
        if (detectorHeader.length > 0) {
            header += delimiter + convertStringArrayToString(detectorHeader);
        }
        return header.trim();
    }

    private String createStringFromPositions() {
        StringBuilder sb = new StringBuilder();
        sb.append("");
        int i = 0;
        for (Object position : scannablePositions) {
            String[] thisPosition;
            try {
                thisPosition = ScannableUtils.getFormattedCurrentPositionArray(position, scannableFormats[i].length,
                        scannableFormats[i]);
                for (String part : thisPosition) {
                    sb.append(part);
                    sb.append(delimiter);
                }
            } catch (Exception e) {
                // ignore so will get a truncated string
            }
            i++;
        }
        return sb.toString().trim();
    }

    private String createStringFromDetectorData() {
        StringBuilder sb = new StringBuilder("");
        int i = 0;
        for (Object dataItem : this.detectorData) {

            if (dataItem instanceof String || dataItem instanceof NexusTreeProvider
                    || dataItem instanceof PlottableDetectorDataClone) {
                sb.append(dataItem.toString());
                sb.append(delimiter);
            }
            /*
             * else use the first format if it is not empty
             */
            else if (this.detectorFormats[i] != null && this.detectorFormats[i].length > 0
                    && this.detectorFormats[i][0] != null && !this.detectorFormats[i][0].isEmpty()) {
                String[] thisPosition;
                try {
                    thisPosition = ScannableUtils.getFormattedCurrentPositionArray(dataItem,
                            detectorFormats[i].length, detectorFormats[i]);
                    for (String part : thisPosition) {
                        sb.append(part);
                        sb.append(delimiter);
                    }
                } catch (Exception e) {
                    logger.error("Error getting position", e);
                }
            }
            /*
             * else give up and get detector to return the string
             */
            else {
                sb.append(DataWriterBase.getDetectorData(dataItem, false));
                sb.append(delimiter);
            }
            i++;
        }
        return sb.toString().trim();

    }

    @Override
    public String getInstrument() {
        return scanInfo.getInstrument();
    }

    @Override
    public Vector<String> getNames() {
        Vector<String> allNames = new Vector<String>();
        allNames.addAll(getScannableNames());
        allNames.addAll(getDetectorNames());
        return allNames;
    }

    @Override
    public int getNumberOfChildScans() {
        return numberOfChildScans;
    }

    @Override
    public int getNumberOfPoints() {
        return scanInfo.getNumberOfPoints();
    }

    @Override
    public Vector<String> getPositionHeader() {
        return new Vector<String>(Arrays.asList(scannableHeader));
    }

    @Override
    public Vector<Object> getPositions() {
        return scannablePositions;
    }

    @Override
    public int getScanIdentifier() {
        return scanInfo.getScanNumber();
    }

    @Override
    public Vector<String> getScannableNames() {
        return new Vector<String>(Arrays.asList(scanInfo.getScannableNames()));
    }

    /**
     * Just returns array of positions. Strings will be an empty element.
     * 
     * @return all scannable positions.
     */
    @Override
    public Double[] getPositionsAsDoubles() {
        Vector<Double> vals = new Vector<Double>();
        if (getPositions() != null) {
            for (Object data : getPositions()) {
                PlottableDetectorData wrapper = new DetectorDataWrapper(data);
                Double[] dvals = wrapper.getDoubleVals();
                vals.addAll(Arrays.asList(dvals));
            }
        }
        if (vals.size() != getPositionHeader().size()) {
            throw new IllegalArgumentException("Position data does not hold the expected number of fields");
        }
        return vals.toArray(new Double[] {});
    }

    /**
     * @return all Scannable positions as strings using the given format
     */
    @Override
    public String[] getPositionsAsFormattedStrings() {

        String[] strings = new String[0];
        if (getPositions() != null) {
            int index = 0;
            for (Object data : getPositions()) {
                PlottableDetectorData wrapper = new DetectorDataWrapper(data);
                Double[] dvals = wrapper.getDoubleVals();
                String[] formattedVals = new String[dvals.length];
                String[] formats = this.scannableFormats[index];
                for (int j = 0; j < dvals.length; j++) {
                    formattedVals[j] = String.format(formats[j], dvals[j]);
                }
                strings = (String[]) ArrayUtils.addAll(strings, formattedVals);
                index++;
            }
        }
        if (strings.length != getPositionHeader().size()) {
            throw new IllegalArgumentException("Position data does not hold the expected number of fields");
        }
        return strings;
    }

    /**
     * The list of scannables this object refers to.
     * 
     * @return list of scannables this object refers to.
     */
    @Override
    public Vector<Scannable> getScannables() {
        return scannables;
    }

    @Override
    public ScanPlotSettings getScanPlotSettings() {
        return scanPlotSettings;
    }

    @Override
    public void setScanPlotSettings(ScanPlotSettings scanPlotSettings) {
        this.scanPlotSettings = scanPlotSettings;
    }

    @Override
    public int[] getScanDimensions() {
        return scanInfo.getDimensions();
    }

    @Override
    public void setScanDimensions(int[] scanDimensions) {
        scanInfo.setDimensions(scanDimensions);
    }

    /**
     * Unique information about this point.
     */
    @Override
    public String toString() {

        String identifier = getCurrentFilename() != null ? getCurrentFilename() : uniqueName;
        return "point " + (currentPointNumber) + " of " + scanInfo.getNumberOfPoints() + " for scan " + identifier;
    }

    /**
     * Returns a string whose elements are separated by a mixture of tabs and spaces so that the columns are aligned
     * with the output from getHeaderString().
     * <p>
     * To be used to create an ascii version of the data held by this object for priting to terminals or to ascii files.
     */
    @Override
    public String toFormattedString() {
        return toFormattedString(null);
    }

    @Override
    public String toFormattedString(ScanDataPointFormatter dataPointFormatter) {
        // work out the lengths of the header string and the lengths of each element from the toString method
        // and pad each to adjust

        String header = getDelimitedHeaderString();

        String data = toDelimitedString();

        String[] headerElements = header.split(delimiter);
        String[] dataElements = data.split(delimiter);

        for (int i = 0; i < headerElements.length; i++) {
            int headerLength = headerElements[i].trim().length();
            int dataLength = dataElements[i].trim().length();

            int maxLength = dataLength > headerLength ? dataLength : headerLength;
            String format = "%" + maxLength + "s";

            headerElements[i] = String.format(format, headerElements[i].trim());
            dataElements[i] = String.format(format, dataElements[i].trim());
        }

        if (dataPointFormatter == null || !dataPointFormatter.isValid(this)) {
            return convertStringArrayToString(dataElements);
        }

        // Optionally a data formatter may be set on Scan data points.
        // This formats them in a custom format.
        return dataPointFormatter.getData(this, MapUtils.createLinkedMap(headerElements, dataElements));
    }

    String delimitedString = null;

    /**
     * Returns a string of the information held by this object delimited by the static variable.
     * 
     * @return String
     */
    @Override
    public String toDelimitedString() {
        if (delimitedString == null) {
            StringBuilder sb = new StringBuilder(createStringFromPositions());
            sb.append(delimiter);
            sb.append(createStringFromDetectorData());
            delimitedString = sb.toString().trim();
        }
        return delimitedString;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + currentPointNumber;
        result = prime * result + ((stepIds == null) ? 0 : stepIds.hashCode());
        result = prime * result + ((uniqueName == null) ? 0 : uniqueName.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ScanDataPoint other = (ScanDataPoint) obj;
        if (currentPointNumber != other.currentPointNumber)
            return false;
        if (stepIds == null) {
            if (other.stepIds != null)
                return false;
        } else if (!stepIds.equals(other.stepIds))
            return false;
        if (uniqueName == null) {
            if (other.uniqueName != null)
                return false;
        } else if (!uniqueName.equals(other.uniqueName))
            return false;
        return true;
    }

    @Override
    public List<IScanStepId> getStepIds() {
        return stepIds;
    }

    @Override
    public void setStepIds(List<IScanStepId> stepIds) {
        this.stepIds = stepIds;
    }

    @Override
    public String getUniqueName() {
        return uniqueName;
    }

    @Override
    public void setUniqueName(String uniqueName) {
        this.uniqueName = uniqueName;
    }

    @Override
    public void setCommand(String command) {
        this.command = command;
    }

    @Override
    public void setCreatorPanelName(String creatorPanelName) {
        this.creatorPanelName = creatorPanelName;
    }

    @Override
    public void setCurrentFilename(String currentFilename) {
        scanInfo.setFilename(currentFilename);
    }

    @Override
    public void setCurrentPointNumber(int currentPointNumber) {
        this.currentPointNumber = currentPointNumber;
    }

    @Override
    public void setHasChild(boolean hasChild) {
        this.hasChild = hasChild;
    }

    @Override
    public void setInstrument(String instrument) {
        scanInfo.setInstrument(instrument);
    }

    /**
     * @param numberOfChildScans
     *            The numberOfChildScans to set.
     */
    @Override
    public void setNumberOfChildScans(int numberOfChildScans) {
        this.numberOfChildScans = numberOfChildScans;
    }

    @Override
    public void setNumberOfPoints(int numberOfPoints) {
        scanInfo.setNumberOfPoints(numberOfPoints);
    }

    @Override
    public void setScanIdentifier(int scanIdentifier) {
        scanInfo.setScanNumber(scanIdentifier);
    }

    @Override
    public String[][] getScannableFormats() {
        return scannableFormats;
    }

    @Override
    public void setScannableFormats(String[][] scannableFormats) {
        this.scannableFormats = scannableFormats;
    }

    @Override
    public void setDetectorHeader(String[] detectorHeader) {
        this.detectorHeader = detectorHeader;
    }

    @Override
    public String[] getScannableHeader() {
        return scannableHeader;
    }

    @Override
    public void setScannableHeader(String[] scannableHeader) {
        this.scannableHeader = scannableHeader;
    }

    @Override
    public Vector<Object> getScannablePositions() {
        return scannablePositions;
    }

    @Override
    public void setScannablePositions(Vector<Object> scannablePositions) {
        this.scannablePositions = scannablePositions;
    }

    @Override
    public String[][] getDetectorFormats() {
        return detectorFormats;
    }

    @Override
    public void setDetectorFormats(String[][] detectorFormats) {
        this.detectorFormats = detectorFormats;
    }

    /**
     * Searches the scannables for one of a given name. Used to avoid searches being in many places.
     * 
     * @param name
     * @return Scannable if it exists or null
     */
    @Override
    public Scannable getScannable(final String name) {
        final Iterator<Scannable> it = getScannables().iterator();
        while (it.hasNext()) {
            final Scannable s = it.next();
            if (s.getName().equals(name))
                return s;
        }
        return null;
    }

    /**
     * Searches the scannables for one of a given name. Works for scannables where name is declared and the actual
     * scannable is not sent over.
     * 
     * @param name
     * @return true if it exists or false
     */
    @Override
    public boolean isScannable(final String name) {
        final Iterator<String> it = getScannableNames().iterator();
        while (it.hasNext()) {
            final String n = it.next();
            if (n.equals(name))
                return true;
        }
        return getScannable(name) != null;
    }

    /**
     * Searches the detectors for one of a given name. Used to avoid searches being in many places.
     * 
     * @param name
     * @return Detector if it exists or null
     */
    @Override
    public Detector getDetector(final String name) {
        final Iterator<Detector> it = getDetectors().iterator();
        while (it.hasNext()) {
            final Detector s = it.next();
            if (s.getName().equals(name))
                return s;
        }
        return null;
    }

    /**
     * Searches the detectors for one of a given name. Works for detectors where name is declared and the actual
     * detector is not sent over.
     * 
     * @param name
     * @return true if it exists or false
     */
    @Override
    public boolean isDetector(String name) {
        final Iterator<String> it = getDetectorNames().iterator();
        while (it.hasNext()) {
            final String n = it.next();
            if (n.equals(name))
                return true;
        }
        return getDetector(name) != null;
    }

    @Override
    public ScanInformation getScanInformation() {
        return scanInfo;
    }

    public void setScanInformation(ScanInformation newScanInfo) {
        scanInfo = newScanInfo;
    }
}