package org.spview.filehandler;

import org.spview.gui.OpusDialog;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//----------------------------------------------------------------------------------------------
// ** STRUCTURES IN OPUS FILES **

class Header
{
    // ***** DATA *****
    public int	magic_number;			// Magic number (= 0xFEFE0A0AL for OPUS files)
    public double pgm_ver;				// Program Version Number
    public int	dir_ptr;				// Pointer to first directory in bytes
    public int	max_entries;			// Max size of directory in terms of blocks
    public int	cur_entries;			// Current size of directory in terms of blocks
}

//----------------------------------------------------------------------------------------------

class DirectoryEntry
{
    // ***** DATA *****
    public int type;                    // Directory block type
    public int length;                  // Length in 32 bits words
    public int pointer;                 // Offset File Pointer (in bytes)
}

//----------------------------------------------------------------------------------------------

class ParameterBlock implements Serializable
{
    // ***** DATA *****
    public String name;
    public short type;
    public short rs;

}

class data_status_parameters {
    boolean valid;						// true when data available

    int	pointer;					// Pointer to the data points
    int length;						// Number of points (as float)

    int DPF;						// data point format (long, float, ...)
    int NPT;						// number of data points
    double FXV;						// 1st X value
    double LXV;						// last X value
    double CSF;						// common factor for all Y-values ("SCALING FACTOR")
    double MXY;						// maximum Y value
    double MNY;						// minimum Y value
    String DXU;	                    // data X-units (WN, MI, LGW, MIN, PNT)
//    int DER;						// derivative (0, 1, 2, ...)
    String DAT;                 	// date
    String TIM;	                    // time
}


class instrument_parameters {
    boolean	valid;						// true when data available
    boolean	supported_instrument;		// true if instrument an IFS125HR, IFS120HR or IFS120M

    double	HFL,						// High folding limit
            LFL;						// Low folding limit
    long	DFR,						// Digital filter reduction
            DFC;						// Number of filter coef.
    double	HFF,						// Digital filter HFL
            LFF;						// Digital filter LFL
    long	ASG,						// Actual signal gain
            ARG,						// Actual ref. signal gain
            ALF,						// Actual low pass filter
            AHF,						// Actual high pass filter
            ASS,						// Number of sample scans
            ARS,						// Number of background scans
            GFW,						// Number of good FW scans
            GBW,						// Number of good BW scans
            BFW,						// Number of bad FW scans
            BBW;						// Number of bad BW scans
    double	DUR;						// Scan time (sec)
    long	RSN;						// Running sample number
    int		PKA;						// Peak amplitude
    long	PKL;						// Peak location
    int		PRA;						// Backward peak amplitude
    long	PRL,						// Backward peak location
            SSM,						// Sample spacing multiplicator
            SSP,						// Sample spacing divisor
            SGP,						// Switch gain position
            SGW;						// Gain switch window
    String	INS,		                // Instrument type
            ITF;                		// Interface type for optic
    long	SIM,						// Simulation mode
            DEB,						// Debug printer mode
            LOG,						// Logfile for measurement
            ADR;						// AQP address
    double	RMX;						// Resolution limit
    long	PLL,						// Maximum PLL setting
            FFT,						// Maximum FT size in K
            MXD;						// Maximum ADC state in Hz
    double	FOC;						// Focal length
    long	ABP;						// Absolute peak position in Laser*2
    double	LWN,						// Laser wavenumber
            RLW,						// Raman laser wavenumber
            NLA,						// Non-linearity correction: ALPHA
            NLB;						// Non-linearity correction: BETA
}

class acquisition_parameters {
    boolean	valid;						// true when data available

    String SGN;		                    // Signal gain, sample
    String RGN;		                    // Signal gain, background
    long   GSW;		                    // Gain switch window
    String GSG;		                    // Gain switch gain
    String AQM;		                    // Acquisition mode
    long   AQR;		                    // Acquisition to RAM
    long   NSS;		                    // Number of scans
    double MIN;		                    // Measurement duration in min.
    String COR;		                    // Correlation test mode
    long   DLY;						    // Delay before measurement
    double HFW;						    // Wanted high frequency limit
    double LFW;						    // Wanted low frequency limit
    double RES;						    // Resolution
    long   TDL;						    // To do list
    String PLF;		                    // Result spectrum
}

class ft_parameters {
    boolean	valid;						// true when data available

    String	APF;		                // Apodization function
    double	HFQ;						// High frequency cutoff
    double  LFQ;						// Low frequency cutoff
    String	PHZ;		                // Phase correction mode
    double	PHR;						// Phase resolution
    long	PIP;						// Phase interferogram points
    long    PTS;						// Phase transform size
    long    DIG;						// Digital filter
    String	SPZ;		                // Stored phase mode
    String  ZFF;		                // Zero filling factor
}

class processing_parameters {
    boolean	valid;						// true when data available

    String	APT;		                // Aperture
    String  BMS;		                // Beamsplitter
    String  DTC;		                // Detector
    String  OPF;		                // Optical filter
    String  PGN;		                // Preamplifier gain
    String  CHN;		                // Measurement channel
    String  SRC;		                // Source
    String  VEL;		                // Scanner velocity
    String  HPF;		                // High pass filter
    String  LPF;		                // Low pass filter
}

class sample_origin_parameters {
    boolean	valid;						// true when data available

    String	SNM;		                // Sample name
    String  SFM;		                // Sample form
    String  CNM;		                // Chemist name
    String  HIS;		                // History of last operations leading to this file
    String  PTH;		                // Measurement path
    String  EXP;		                // Experiment
    String  NAM;		                // Filename
    String  IST;		                // Instrument status
}

public class OpusFile {
    private enum data_type { DT_SPEC, DT_IGM, DT_PHAS, DT_ABS, DT_TR, DT_COUNT, DT_NONE }
    private final String[] data_type_string = { "Spectrum", "Inteferogram", "Phase Spectrum", "Absorbance Spectrum", "Transmitance Spectrum" };
    // Possible types (cf "Description of the OPUS datafile format", JGR 23.1.92, p.6)
    private enum datafile_format {INT_32, REAL64, STRING, ENUM, SENUM}

    // Masks and constants to determine the type of data in Opus files
    // See "Description of the OPUS datafile format", JGR 23.1.92

    // ** SHIFTS and MASKS
    private static final long DBSCPLX = 0L, DBMCPLX = 3L,        // Bits 0-1: Kind of data
                              //DBSSTYP = 2L, DBMSTYP = 3L,        // Bits 2-3: Type of data
                              DBSPARM = 4L, DBMPARM = 63L,       // Bits 4-9: Parameters
                              DBSDATA = 10L, DBMDATA = 7L;       // Bits 10-16: Only 10-12 taken into account

    private static final long DBBCPLX = DBMCPLX << DBSCPLX,      // Isolate data type no. 1
                              //DBBSTYP = DBMSTYP << DBSSTYP,      // data type no. 2
                              DBBPARM = DBMPARM << DBSPARM,      // parameters
                              DBBDATA = DBMDATA << DBSDATA;      // data

    // ** CONSTANTS
    private static final long /*DBTREAL = 1L,*/        // Real part of complex data -> DBMCPLX
                              //DBTIMAG = 2L,        // Imag part of complex data
                              DBTAMPL = 3L,        // Amplitude data

                              //DBTSAMP = 1L,        // Sample data -> DBMSTYP
                              //DBTREF = 2L,         // Reference data
                              //DBTRATIO = 3L,       // Ratioed data

                              DBTDSTAT = 1L,        // Data status parameter -> DBMPARM
                              DBTINSTR = 2L,        // Instrument status parameters
                              DBTAQPAR = 3L,        // Standard acquisition parameters
                              DBTFTPAR = 4L,        // FT parameters
                              DBTPRCPAR = 6L,       // Processing (optics) parameters
                              DBTORGPAR = 10L,      // Sample origin parameters

                              DBTSPEC = 1L,         // Spectrum, undefined Y-units -> DBMDATA
                              DBTIGRM = 2L,         // Interferogram
                              DBTPHAS = 3L,         // Phase spectrum
                              DBTAB = 4L,           // Absorbance spectrum
                              DBTTR = 5L,           // Transmittance spectrum
                              DBTDIR = 13L;         // DIRECTORY
    // All other values -> Spectrum assumed (DBTSPEC).

    private static final long DBBAMPL = DBTAMPL << DBSCPLX,        // Shifted masks
                              //DBBIMAG = DBTIMAG << DBSCPLX,
                              //DBBREAL = DBTREAL << DBSCPLX,

                              //DBBSAMP = DBTSAMP << DBSSTYP,
                              //DBBREF = DBTREF << DBSSTYP,
                              //DBBRATIO = DBTRATIO << DBSSTYP,

                              DBBDSTAT = DBTDSTAT << DBSPARM,
                              DBBINSTR = DBTINSTR << DBSPARM,
                              DBBAQPAR = DBTAQPAR << DBSPARM,
                              DBBFTPAR = DBTFTPAR << DBSPARM,
                              DBBPRCPAR = DBTPRCPAR << DBSPARM,
                              DBBORGPAR = DBTORGPAR << DBSPARM,

                              DBBSPEC = DBTSPEC << DBSDATA,
                              DBBIGRM = DBTIGRM << DBSDATA,
                              DBBPHAS = DBTPHAS << DBSDATA,
                              DBBAB = DBTAB << DBSDATA,
                              DBBTR = DBTTR << DBSDATA,
                              DBBDIR = DBTDIR << DBSDATA;

    private final String name;
    ArrayList<Double> alx = new ArrayList<>(); // frequency
    ArrayList<Double> aly = new ArrayList<>(); // intensity

    private final Header opusHeader = new Header();
    private DirectoryEntry[] opusDirectory;
    private final ParameterBlock obp = new ParameterBlock();

    private static final instrument_parameters ins = new instrument_parameters();
    private static final acquisition_parameters acq = new acquisition_parameters();
    private static final sample_origin_parameters so = new sample_origin_parameters();
    private final data_status_parameters[] dsp = new data_status_parameters[data_type.DT_COUNT.ordinal()];

    private int nbxy; // nb of points

    boolean isCancelled = false;

    /**
     * Construct a new Opusfile.
     *
     * @param cname file name
     */
    public OpusFile(String cname) {
        name = cname; // file name

        nbxy = 0; // nb of points
    }

    /**
     * Get name selection string.
     */
    public String getname() {

        return name;
    }

    private boolean readHeader(File f) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            opusHeader.magic_number = dataInputStream.readInt(); // 4 bytes
            opusHeader.pgm_ver = dataInputStream.readDouble(); // 8 bytes
            opusHeader.dir_ptr = dataInputStream.readInt(); // 4 bytes
            opusHeader.max_entries = dataInputStream.readInt(); // 4 bytes
            opusHeader.cur_entries = dataInputStream.readInt(); // 4 bytes

            if (opusHeader.magic_number != 0xFEFE0A0A) return false;

            System.out.println("OPUS Program Version: " + opusHeader.pgm_ver + "\tDirectory address: "
                    + opusHeader.dir_ptr + "\tMax. entries: " + opusHeader.max_entries + "\tCurrent: " + opusHeader.cur_entries);
            return true;
        }
    }

    private boolean readDirectoryEntry(File f) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(24); // --> skip header

            for (int l = 0; l < opusHeader.cur_entries; l++) {
                DirectoryEntry directory = new DirectoryEntry();
                directory.type = dataInputStream.readInt();
                directory.length = dataInputStream.readInt();
                directory.pointer = dataInputStream.readInt();

                opusDirectory[l] = directory;
            }
        }
        return true;
    }

    private void readDataStatusParameters(File f, int pointer, data_status_parameters d) throws IOException {

        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(pointer);

            d.valid = false;
            label:
            while (true) {
                byte[] bytes = dataInputStream.readNBytes(4);
                obp.name = new String(bytes,0,3, StandardCharsets.US_ASCII);
                obp.type = dataInputStream.readShort();
                obp.rs = dataInputStream.readShort();
                switch (obp.name) {
                    case "DPF":
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        d.DPF = dataInputStream.readInt();
                        break;
                    case "NPT":
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        d.NPT = dataInputStream.readInt();
                        break;
                    case "FXV":
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        d.FXV = dataInputStream.readDouble();
                        break;
                    case "LXV":
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        d.LXV = dataInputStream.readDouble();
                        break;
                    case "CSF":
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        d.CSF = dataInputStream.readDouble();
                        break;
                    case "DXU": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        d.DXU = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "MXY":
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        d.MXY = dataInputStream.readDouble();
                        break;
                    case "MNY":
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        d.MNY = dataInputStream.readDouble();
                        break;
                    case "DAT": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        d.DAT = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "TIM": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        d.TIM = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "END":
                        break label;
                    default: {
                        int length = obp.rs << 1;
                        dataInputStream.readNBytes(length);
                        break;
                    }
                }
            }
            // Data exist
            d.valid = true;
        }
    }

    private void readInstrumentParameters(File f, int pointer) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(pointer);

            OpusFile.ins.valid = false;
            label:
            while (true) {
                byte[] bytes = dataInputStream.readNBytes(4);
                obp.name = new String(bytes, 0, 3, StandardCharsets.US_ASCII);
                obp.type = dataInputStream.readShort();
                obp.rs = dataInputStream.readShort();
                switch (obp.name) {
                    case "HFL": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.HFL = dataInputStream.readDouble();
                        break;
                    }
                    case "LFL": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.LFL = dataInputStream.readDouble();
                        break;
                    }
                    case "DFR": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.DFR = dataInputStream.readInt();
                        break;
                    }
                    case "DFC": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.DFC = dataInputStream.readInt();
                        break;
                    }
                    case "HFF": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.HFF = dataInputStream.readDouble();
                        break;
                    }
                    case "LFF": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.LFF = dataInputStream.readDouble();
                        break;
                    }
                    case "ASG": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ASG = dataInputStream.readInt();
                        break;
                    }
                    case "ARG": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ARG = dataInputStream.readInt();
                        break;
                    }
                    case "ALF": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ALF = dataInputStream.readInt();
                        break;
                    }
                    case "AHF": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.AHF = dataInputStream.readInt();
                        break;
                    }
                    case "ASS": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ASS = dataInputStream.readInt();
                        break;
                    }
                    case "ARS": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ARS = dataInputStream.readInt();
                        break;
                    }
                    case "GFW": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.GFW = dataInputStream.readInt();
                        break;
                    }
                    case "GBW": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.GBW = dataInputStream.readInt();
                        break;
                    }
                    case "BFW": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.BFW = dataInputStream.readInt();
                        break;
                    }
                    case "BBW": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.BBW = dataInputStream.readInt();
                        break;
                    }
                    case "DUR": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.DUR = dataInputStream.readDouble();
                        break;
                    }
                    case "RSN": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.RSN = dataInputStream.readInt();
                        break;
                    }
                    case "PKA": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.PKA = dataInputStream.readInt();
                        break;
                    }
                    case "PKL": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.PKL = dataInputStream.readInt();
                        break;
                    }
                    case "PRA": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.PRA = dataInputStream.readInt();
                        break;
                    }
                    case "PRL": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.PRL = dataInputStream.readInt();
                        break;
                    }
                    case "SSM": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.SSM = dataInputStream.readInt();
                        break;
                    }
                    case "SSP": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.SSP = dataInputStream.readInt();
                        break;
                    }
                    case "SGP": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.SGP = dataInputStream.readInt();
                        break;
                    }
                    case "SGW": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.SGW = dataInputStream.readInt();
                        break;
                    }
                    case "INS": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.ins.INS = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "ITF": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.ins.ITF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "SIM": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.SIM = dataInputStream.readInt();
                        break;
                    }
                    case "DEB": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.DEB = dataInputStream.readInt();
                        break;
                    }
                    case "LOG": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.LOG = dataInputStream.readInt();
                        break;
                    }
                    case "ADR": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ADR = dataInputStream.readInt();
                        break;
                    }
                    case "RMX": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.RMX = dataInputStream.readDouble();
                        break;
                    }
                    case "PLL": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.PLL = dataInputStream.readInt();
                        break;
                    }
                    case "FFT": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.FFT = dataInputStream.readInt();
                        break;
                    }
                    case "MXD": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.MXD = dataInputStream.readInt();
                        break;
                    }
                    case "FOC": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.FOC = dataInputStream.readDouble();
                        break;
                    }
                    case "ABP": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.ins.ABP = dataInputStream.readInt();
                        break;
                    }
                    case "LWN": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.LWN = dataInputStream.readDouble();
                        break;
                    }
                    case "RLW": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.RLW = dataInputStream.readDouble();
                        break;
                    }
                    case "NLA": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.NLA = dataInputStream.readDouble();
                        break;
                    }
                    case "NLB": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.ins.NLB = dataInputStream.readDouble();
                        break;
                    }
                    case "END":
                        break label;
                    default: {
                        int length = obp.rs << 1;
                        dataInputStream.readNBytes(length);
                        break;
                    }
                }
            }
            // Instrument type and maximum values
            switch (OpusFile.ins.INS) {
                case "IFS125":
                case "IFS120 to 125 HR upgrade":
                    OpusFile.ins.supported_instrument = true;
                    OpusFile.ins.RMX = 0.00126;
                    OpusFile.ins.PLL = 4L;
                    OpusFile.ins.FFT = 64000L;
                    OpusFile.ins.MXD = 80000L;
                    break;
                case "IFS120":
                    OpusFile.ins.supported_instrument = true;
                    OpusFile.ins.RMX = 0.00185;
                    OpusFile.ins.PLL = 8L;
                    OpusFile.ins.FFT = 2048L;
                    OpusFile.ins.MXD = 200000L;
                    break;
                case "IFS120M":
                    OpusFile.ins.supported_instrument = true;
                    OpusFile.ins.RMX = 0.0035;
                    OpusFile.ins.PLL = 8L;
                    OpusFile.ins.FFT = 2048L;
                    OpusFile.ins.MXD = 200000L;
                    break;
                default:
                    OpusFile.ins.supported_instrument = false;
                    break;
            }
            // Data exist
            OpusFile.ins.valid = true;
        }
    }

    private void readStandardAcquisitionParameters(File f, int pointer) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(pointer);

            OpusFile.acq.valid = false;
            label:
            while (true) {
                byte[] bytes = dataInputStream.readNBytes(4);
                obp.name = new String(bytes, 0, 3, StandardCharsets.US_ASCII);
                obp.type = dataInputStream.readShort();
                obp.rs = dataInputStream.readShort();
                switch (obp.name) {
                    case "SGN": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.acq.SGN = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "RGN": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.acq.RGN = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "GSW": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.acq.GSW = dataInputStream.readInt();
                        break;
                    }
                    case "GSG": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.acq.GSG = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "AQM": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.acq.AQM = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "AQR": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.acq.AQR = dataInputStream.readInt();
                        break;
                    }
                    case "NSS": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.acq.NSS = dataInputStream.readInt();
                        break;
                    }
                    case "MIN": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.acq.MIN = dataInputStream.readDouble();
                        break;
                    }
                    case "COR": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.acq.COR = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "DLY": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.acq.DLY = dataInputStream.readInt();
                        break;
                    }
                    case "HFW": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.acq.HFW = dataInputStream.readDouble();
                        break;
                    }
                    case "LFW": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.acq.LFW = dataInputStream.readDouble();
                        break;
                    }
                    case "RES": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        OpusFile.acq.RES = dataInputStream.readDouble();
                        break;
                    }
                    case "TDL": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        OpusFile.acq.TDL = dataInputStream.readInt();
                        break;
                    }
                    case "PLF": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.acq.PLF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "END":
                        break label;
                    default: {
                        int length = obp.rs << 1;
                        dataInputStream.readNBytes(length);
                        break;
                    }
                }
            }
            // Data exist
            OpusFile.acq.valid = true;
        }
    }

    private void readFtParameters(File f, int pointer, ft_parameters ft) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(pointer);

            ft.valid = false;
            label:
            while (true) {
                byte[] bytes = dataInputStream.readNBytes(4);
                obp.name = new String(bytes, 0, 3, StandardCharsets.US_ASCII);
                obp.type = dataInputStream.readShort();
                obp.rs = dataInputStream.readShort();
                switch (obp.name) {
                    case "APF": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        ft.APF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "HFQ": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        ft.HFQ = dataInputStream.readDouble();
                        break;
                    }
                    case "LFQ": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        ft.LFQ = dataInputStream.readDouble();
                        break;
                    }
                    case "PHZ": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        ft.PHZ = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "PHR": {
                        assert (obp.type == datafile_format.REAL64.ordinal());
                        ft.PHR = dataInputStream.readDouble();
                        break;
                    }
                    case "PIP": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        ft.PIP = dataInputStream.readInt();
                        break;
                    }
                    case "PTS": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        ft.PTS = dataInputStream.readInt();
                        break;
                    }
                    case "DIG": {
                        assert (obp.type == datafile_format.INT_32.ordinal());
                        ft.DIG = dataInputStream.readInt();
                        break;
                    }
                    case "SPZ": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        ft.SPZ = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "ZFF": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        ft.ZFF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "END":
                        break label;
                    default: {
                        int length = obp.rs << 1;
                        dataInputStream.readNBytes(length);
                        break;
                    }
                }
            }
            // Data exist
            ft.valid = true;
        }
    }

    private void readProcessingParameters(File f, int pointer, processing_parameters proc) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(pointer);

            proc.valid = false;
            label:
            while (true) {
                byte[] bytes = dataInputStream.readNBytes(4);
                obp.name = new String(bytes, 0, 3, StandardCharsets.US_ASCII);
                obp.type = dataInputStream.readShort();
                obp.rs = dataInputStream.readShort();
                switch (obp.name) {
                    case "APT": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.APT = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "BMS": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.BMS = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "DTC": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.DTC = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "OPF": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.OPF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "PGN": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.PGN = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "CHN": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.CHN = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "SRC": {
                        assert (obp.type == datafile_format.SENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.SRC = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "VEL": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.VEL = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "HPF": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.HPF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "LPF": {
                        assert (obp.type == datafile_format.ENUM.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        proc.LPF = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "END":
                        break label;
                    default: {
                        int length = obp.rs << 1;
                        dataInputStream.readNBytes(length);
                        break;
                    }
                }
            }
            // Data exist
            proc.valid = true;
        }
    }

    private void readSampleOriginParameters(File f, int pointer) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(f))) {
            dataInputStream.readNBytes(pointer);

            OpusFile.so.valid = false;
            label:
            while (true) {
                byte[] bytes = dataInputStream.readNBytes(4);
                obp.name = new String(bytes, 0, 3, StandardCharsets.US_ASCII);
                obp.type = dataInputStream.readShort();
                obp.rs = dataInputStream.readShort();
                switch (obp.name) {
                    case "SNM": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.SNM = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "SFM": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.SFM = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "CNM": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.CNM = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "HIS": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.HIS = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "PTH": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.PTH = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "EXP": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.EXP = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "NAM": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.NAM = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "IST": {
                        assert (obp.type == datafile_format.STRING.ordinal());
                        int length = obp.rs << 1;
                        byte[] buf = dataInputStream.readNBytes(length);
                        OpusFile.so.IST = new String(buf, 0, length, StandardCharsets.US_ASCII).trim();
                        break;
                    }
                    case "END":
                        break label;
                    default: {
                        int length = obp.rs << 1;
                        dataInputStream.readNBytes(length);
                        break;
                    }
                }
            }
            // Data exist
            OpusFile.so.valid = true;
        }
    }

    private static<T> List<T> reverseList(List<T> list) {
        List<T> reverse = new ArrayList<>(list);
        Collections.reverse(reverse);
        return reverse;
    }

    private void extractXY(File file, data_status_parameters dsp) throws IOException {
        try (EndianDataInputStream dataInputStream = new EndianDataInputStream(new FileInputStream(file))) {
            double x_min = dsp.FXV, x_max = dsp.LXV; boolean ascending = true;
            if(x_min > x_max) {
                double tmp;
                ascending = false;
                tmp = x_min;
                x_min = x_max;
                x_max = tmp;
            }
            nbxy = dsp.NPT;
            double point_spacing = (x_max - x_min)/(double)(nbxy - 1), cur_x = x_min, d = 1.0;
            int data_ptr = dsp.pointer; double scale_factor = dsp.CSF;

            dataInputStream.readNBytes(data_ptr);

            for (int i = 0; i < nbxy; ++i, d += 1.0) {
                alx.add(cur_x); cur_x = d; cur_x *= point_spacing; cur_x += x_min;
                float f = dataInputStream.readFloat();
                aly.add(scale_factor * (double) f);
            }
            if(!ascending) {
                aly = (ArrayList<Double>) reverseList(aly);
            }
        }
    }

    /* Yet we only accept wn as units */
    private boolean checkUnits(data_status_parameters dsp) {
        /* if null we assume it is wn by default */
        if (dsp.DXU == null) return true;
        return dsp.DXU.equals("WN");
    }

    static public String InstrumentParameters() {
        if (!so.valid) {
            System.out.println("Instrument parameters not available");
            return null;
        }

        // Peak locations
        String szPKL;
        if(ins.PKL > 0L) {
            szPKL = String.format("%d points", ins.PKL);
        }
        else {
            szPKL = "None";
        }
        String szPRL;
        if(ins.PRL > 0L) {
            szPRL = String.format("%d points", ins.PRL);
        }
        else {
            szPRL = "None";
        }

        return String.format("<h2>Instrument parameters</h2>" +
                        "<p>High folding limit: %.6f cm-1</p><p>Low folding limit: %.6f cm-1</p><p>" +
                        "Digital filter reduction: %d</p><p>Number of filter coefficients: %d</p><p>" +
                        "Digital filter HFL: %.6f cm-1</p><p>Digital filter LFL: %.6f cm-1</p><p>" +
                        "Actual signal gain: %d</p><p>Actual reference signal gain: %d</p><p>" +
                        "Actual low pass filter: %d</p><p>Actual high pass filter: %d</p><p>" +
                        "Number of sample scans: %d</p><p>Number of background scans: %d</p><p>" +
                        "Number of good FW scans: %d</p><p>Number of good BW scans: %d</p><p>" +
                        "Number of bad FW scans: %d</p><p>Number of bad BW scans: %d</p><p>" +
                        "Scan time: %.3f sec.</p><p>Running sample number: %d</p><p>" +
                        "Peak amplitude (at ADC): %d counts (%.0f mV)</p><p>" +
                        "Peak location: %s</p><p>" +
                        "Backward peak amplitude (ADC): %d counts (%.0f mV)</p><p>" +
                        "Backward peak location: %s</p><p>" +
                        "Sample spacing multiplicator: %d</p><p>Sample spacing divisor: %d</p><p>" +
                        "Switch gain position: %d points</p><p>Gain switch window: %d points</p><p>" +
                        "Instrument type: %s</p><p>Interface type for optic: %s</p><p>" +
                        "Simulation mode: %d</p><p>Debug printer mode: %d</p><p>" +
                        "Logfile for measurement: %d</p><p>AQP address: %d</p><p>" +
                        "Resolution limit: %.5f cm-1</p><p>Maximum PLL setting: %d</p><p>" +
                        "Maximum FT size in K: %d kBytes</p><p>Maximum ADC state: %d Hz</p><p>" +
                        "Focal length: %.1f mm</p><p>Absolute peak position in Laser*2: %d</p><p>" +
                        "Absolute peak position: %.4f cm</p><p>" +
                        "Laser wavenumber: %.2f cm-1</p><p>Raman laser wavenumber</p><p>Not applicable</p><p>" +
                        "Alpha (Non-Linearity correction): %.6f</p><p>Beta (NL correction): %.6f",
                ins.HFL, ins.LFL, ins.DFR, ins.DFC, ins.HFF, ins.LFF,
                ins.ASG, ins.ARG, ins.ALF, ins.AHF, ins.ASS, ins.ARS,
                ins.GFW, ins.GBW, ins.BFW, ins.BBW, ins.DUR, ins.RSN,
                ins.PKA, 1000.0*(double)(ins.PKA)/32768.0, szPKL,
                ins.PRA, 1000.0*(double)(ins.PRA)/32768.0, szPRL,
                ins.SSM, ins.SSP, ins.SGP, ins.SGW, ins.INS,
                ins.ITF, ins.SIM, ins.DEB, ins.LOG, ins.ADR, ins.RMX,
                ins.PLL, ins.FFT, ins.MXD, ins.FOC, ins.ABP,
                ((ins.LWN > 0.0) ? (double)(ins.ABP)/(2.0*ins.LWN) : 0.0),
                ins.LWN, ins.NLA, ins.NLB);
    }

    static public String SampleOriginParameters() {
        if (!so.valid) {
            System.out.println("Sample Origin parameters not available");
            return null;
        }

        // Write information
        return String.format("<h2>Sample origin parameters</h2>" +
                "<p>Sample name: %s</p><p>Sample form: %s</p><p>Chemist name: %s</p><p>" +
                        "History of ops. leading to this file: %s</p><p>Measurement path: %s</p><p>" +
                        "Experiment: %s</p><p>Filename: %s</p>", so.SNM, so.SFM, so.CNM,
                so.HIS, so.PTH, so.EXP, so.NAM);
    }

    static public String AcquisitionParameters() {
        if (!acq.valid) {
            System.out.println("Acquisition parameters not available");
            return null;
        }
        String szSGN;
        String szRGN;
        // SGN, RGN
        if (acq.SGN != null) {
            long lTmp = Long.parseLong(acq.SGN);
            if (lTmp >= 0L) {
                szSGN = Double.toString(Math.pow(2, (double) lTmp));
            } else {
                szSGN = "Automatic";
            }
        } else {
            szSGN = "N/A";
        }
        if (acq.RGN != null) {
            long lTmp = Long.parseLong(acq.RGN);
            if (lTmp >= 0L) {
                szRGN = Double.toString(Math.pow(2, (double) lTmp));
            } else {
                szRGN = "Automatic";
            }
        } else {
            szRGN = "N/A";
        }
        // Acquisition mode
        String[] szAcq = { "SN", "DN", "SF", "SD", "DD", "DF" };
        String[] szAcqMode = { "Single Sided", "Double Sided",
                "Single Sided, Fast return", "Single Sided, Forward-Backward",
                "Double Sided, Forward-Backward", "Double Sided, Fast return",
                "Unknown" };
        int i;
        for(i = 0; i < 6; i++) {
            if((acq.AQM.equals(szAcq[i])))
                break;
        }
        // Result spectrum
        String[] szPLF = { "TR", "AB", "KM", "RAM", "EMI", "RFL", "LRF", "ATR", "PAS" };
        String[] szResSpec = { "Transmittance", "Absorbance",
                "Kubelka Munk", "Raman Spectrum", "Emission", "Reflectance",
                "Log Reflectance", "ATR Spectrum", "PAS Spectrum", "Unknown" };
        int j;
        for(j = 0; j < 9; j++) {
            if((acq.PLF.equals(szPLF[j])))
                break;
        }

        return String.format("<h2>Acquisition parameters</h2>" +
                "<p>Signal gain, sample: %s [%s]</p><p>Signal gain, background: %s [%s]</p><p>" +
                        "Gain switch window: %d points</p><p>Gain switch gain: %s</p><p>" +
                        "Acquisition mode: t%s [%s]</p><p>Number of scans: %d</p><p>" +
                        "Measurement duration: %.2f min.</p><p>Correlation test mode: %s</p><p>" +
                        "Delay before measurement: %d sec.</p><p>Wanted high frequency limit: %.4f cm-1</p><p>" +
                        "Wanted low frequency limit: %.4f cm-1</p><p>Resolution: %.4f cm-1</p><p>" +
                        "To do list: %d</p><p>Result spectrum: %s [%s]</p>",
                szSGN, acq.SGN, szRGN, acq.RGN, acq.GSW, acq.GSG, szAcqMode[i],
                acq.AQM, acq.NSS, acq.MIN, acq.COR, acq.DLY, acq.HFW, acq.LFW,
                acq.RES, acq.TDL, szResSpec[j], acq.PLF);
    }

    public boolean getCancelled() {
        return isCancelled;
    }

    public ArrayList<Double> get_XArray() {
        return alx;
    }

    public ArrayList<Double> get_YArray() {
        return aly;
    }

    public boolean read() throws IOException {
        File file = new File(name);

        if (!readHeader(file)) {
            System.out.println("Not an OPUS file");
            return false;
        }
        opusDirectory = new DirectoryEntry[opusHeader.cur_entries];

        if (!readDirectoryEntry(file)) {
            System.out.println("Error reading Directory Entry");
            return false;
        }

        for (int i = 0; i < opusHeader.cur_entries; i++) {
            // Skip directory block
            if (opusDirectory[i].type == DBBDIR) continue;

            long data = opusDirectory[i].type & DBBDATA;
            if (data != 0L) {
                // DATA POINTS OR DATA STATUS PARAMETERS BLOCK
                // -> Determine the kind of information available here
                //    (Any DBBSTYP is OK)
                if ((opusDirectory[i].type & DBBCPLX) != DBBAMPL) {
                    // Error: Unknown data type (DBBREAL, DBBIMAG or something else...?)
                    continue;
                }
                // Compute index into 'dsp' (from 0 to )
                if (data != DBBSPEC && data != DBBIGRM
                        && data != DBBPHAS && data != DBBAB
                        && data != DBBTR) {
                    // Error: Unsupported data type
                    continue;
                }
                data /= DBBSPEC;
                --data;

                if (dsp[(int)data] == null) dsp[(int)data] = new data_status_parameters();
                if ((opusDirectory[i].type & DBBDSTAT) != 0L) {
                    // Get data status parameters
                    readDataStatusParameters(file, opusDirectory[i].pointer, dsp[(int)data]);
                } else {
                    // Store data pointer and length
                    dsp[(int)data].pointer = opusDirectory[i].pointer;
                    dsp[(int)data].length = opusDirectory[i].length;
                }
            } else {
                // INSTRUMENT, ACQUISITION, FT, ... PARAMETERS
                long type = opusDirectory[i].type & DBBPARM;
                if (type == DBBINSTR) {
                    // INSTRUMENT PARAMETERS
                    readInstrumentParameters(file, opusDirectory[i].pointer);
                } else if (type == DBBAQPAR) {
                    // STANDARD ACQUISITION PARAMETERS
                    readStandardAcquisitionParameters(file, opusDirectory[i].pointer);
                } else if (type == DBBFTPAR) {
                    // FT PARAMETERS
                    ft_parameters ft = new ft_parameters();
                    readFtParameters(file, opusDirectory[i].pointer, ft);
                } else if (type == DBBPRCPAR) {
                    // PROCESSING PARAMETERS
                    processing_parameters proc = new processing_parameters();
                    readProcessingParameters(file, opusDirectory[i].pointer, proc);
                } else if (type == DBBORGPAR) {
                    // SAMPLE ORIGIN PARAMETERS
                    readSampleOriginParameters(file, opusDirectory[i].pointer);
                } else {
                    // NONE OF THE ABOVE
                }
            }
        }

        int count = 0, i = 0;
        ArrayList<String> values = new ArrayList<>();

        for (data_status_parameters d : dsp) {
            if (d != null && d.valid) {
                values.add(data_type_string[i]);
                count++;
            }
            i++;
        }
        if (count > 0) {
            OpusDialog dialog = new OpusDialog(values.toArray(new String[0]), data_type_string[data_type.DT_ABS.ordinal()]);
            Object selected = dialog.getSelected();
            if (selected != null) { //null if the user cancels.
                String selectedString = selected.toString();
                for (int k = 0; k < data_type.DT_COUNT.ordinal(); k++) {
                    if (data_type_string[k].equals(selectedString)) {
                        if (checkUnits(dsp[k])) {
                            extractXY(file, dsp[k]);
                            return true;
                        } else {
                            System.out.println("Units not handled");
                            return false;
                        }
                    }
                }
            } else{
                System.out.println("User cancelled");
                isCancelled = true;
                return true;
            }
        }
        return false;
    }
}