function varargout = process_import_surfaces( varargin )
% PROCESS_IMPORT_SURFACES: Import three surfaces in the database.

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2012

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Import surfaces';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = {'Import', 'Import anatomy'};
    sProcess.Index       = 3;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/ImportAnatomy#Import_the_anatomy';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'import'};
    sProcess.OutputTypes = {'import'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 0;
    sProcess.isSeparator = 1;
    % File selection options
    SelectOptions = {...
        '', ...                                % Filename
        '', ...                                % FileFormat
        'open', ...                            % Dialog type: {open,save}
        'Import surface file...', ...          % Window title
        'ImportAnat', ...                      % LastUsedDir: {ImportData,ImportChannel,ImportAnat,ExportChannel,ExportData,ExportAnat,ExportProtocol,ExportImage,ExportScript}
        'single', ...                          % Selection mode: {single,multiple}
        'files', ...                           % Selection mode: {files,dirs,files_and_dirs}
        bst_get('FileFilters', 'surface'), ... % Get all the available file formats
        'SurfaceIn'};                          % DefaultFormats: {ChannelIn,DataIn,DipolesIn,EventsIn,MriIn,NoiseCovIn,ResultsIn,SspIn,SurfaceIn,TimefreqIn
    % Option: Subject name
    sProcess.options.subjectname.Comment = 'Subject name:';
    sProcess.options.subjectname.Type    = 'subjectname';
    sProcess.options.subjectname.Value   = 'NewSubject';
    % Option: Head surface
    sProcess.options.headfile.Comment = 'Head surface:';
    sProcess.options.headfile.Type    = 'filename';
    sProcess.options.headfile.Value   = SelectOptions;
    % Option: Hemisphere 1
    sProcess.options.cortexfile1.Comment = 'Hemisphere 1:';
    sProcess.options.cortexfile1.Type    = 'filename';
    sProcess.options.cortexfile1.Value   = SelectOptions;
    % Option: Hemisphere 2
    sProcess.options.cortexfile2.Comment = 'Hemisphere 2:';
    sProcess.options.cortexfile2.Type    = 'filename';
    sProcess.options.cortexfile2.Value   = SelectOptions;
    % Option: Inner skull
    sProcess.options.innerfile.Comment = 'Inner skull:';
    sProcess.options.innerfile.Type    = 'filename';
    sProcess.options.innerfile.Value   = SelectOptions;
    % Option: Outer skull
    sProcess.options.outerfile.Comment = 'Outer skull:';
    sProcess.options.outerfile.Type    = 'filename';
    sProcess.options.outerfile.Value   = SelectOptions;
    % Option: Number of vertices
    sProcess.options.nverthead.Comment = 'Number of vertices (head): ';
    sProcess.options.nverthead.Type    = 'value';
    sProcess.options.nverthead.Value   = {7000, '', 0};
    % Option: Number of vertices
    sProcess.options.nvertcortex.Comment = 'Number of vertices (cortex): ';
    sProcess.options.nvertcortex.Type    = 'value';
    sProcess.options.nvertcortex.Value   = {15000, '', 0};
    % Option: Number of vertices
    sProcess.options.nvertskull.Comment = 'Number of vertices (skull): ';
    sProcess.options.nvertskull.Type    = 'value';
    sProcess.options.nvertskull.Value   = {7000, '', 0};
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess) %#ok<DEFNU>
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInputs) %#ok<DEFNU>
    OutputFiles = {};

    % ===== GET OPTIONS =====
    % Get subject name
    SubjectName = file_standardize(sProcess.options.subjectname.Value);
    if isempty(SubjectName)
        bst_report('Error', sProcess, [], 'Subject name is empty.');
        return
    end
    % Get filenames to import
    HeadFile      = sProcess.options.headfile.Value{1};
    HeadFormat    = sProcess.options.headfile.Value{2};
    CortexFile1   = sProcess.options.cortexfile1.Value{1};
    CortexFormat1 = sProcess.options.cortexfile1.Value{2};
    CortexFile2   = sProcess.options.cortexfile2.Value{1};
    CortexFormat2 = sProcess.options.cortexfile2.Value{2};
    InnerFile     = sProcess.options.innerfile.Value{1};
    InnerFormat   = sProcess.options.innerfile.Value{2};
    OuterFile     = sProcess.options.outerfile.Value{1};
    OuterFormat   = sProcess.options.outerfile.Value{2};
    if isempty([HeadFile, CortexFile1, InnerFile, OuterFile])
        bst_report('Error', sProcess, [], 'Not enough files selected.');
        return
    end
    % Number of vertices
    nVertHead   = sProcess.options.nverthead.Value{1};
    nVertCortex = sProcess.options.nvertcortex.Value{1};
    nVertSkull  = sProcess.options.nvertskull.Value{1};
    if isempty(nVertCortex) || (nVertCortex < 50) || isempty(nVertHead) || (nVertHead < 50) || isempty(nVertSkull) || (nVertSkull < 50)
        bst_report('Error', sProcess, [], 'Invalid number of vertices.');
        return
    end
    % Divide by number of cortex files
    if ~isempty(CortexFile2)
        nVertCortex = nVertCortex / 2;
    end

    % ===== GET/CREATE SUBJECT =====
    % Get subject
    [sSubject, iSubject] = bst_get('Subject', SubjectName);
    % Create subject is it does not exist yet
%     if isempty(sSubject)
%         [sSubject, iSubject] = db_add_subject(SubjectName);
%     end
    if isempty(iSubject)
        bst_report('Error', sProcess, [], ['Subject "' SubjectName '" does not exist.']);
        return
    end
    % Check if a MRI is available for the subject
    if isempty(sSubject.Anatomy)
        bst_report('Error', sProcess, [], ['No MRI available for subject "' SubjectName '".']);
        return
    end
    % The subject can't be using the default anatomy
    if (iSubject ~= 0) && sSubject.UseDefaultAnat
        bst_report('Error', sProcess, [], ['Subject "' SubjectName '" is using the default anatomy (read-only).']);
        return
    end

    % ===== HEAD FILE =====
    if ~isempty(HeadFile)
        % Import file
        [iScalp, OldHeadFile] = import_surfaces(iSubject, HeadFile, HeadFormat, 0);
        OldHeadFile = OldHeadFile{1};
        % Set the file type
        OldHeadFile = db_surface_type(OldHeadFile, 'Scalp');
        % Downsample
        NewHeadFile = tess_downsize(OldHeadFile, nVertHead, 'reducepatch');
        % Delete intial file
        if ~file_compare(OldHeadFile, NewHeadFile)
            file_delete(file_fullpath(OldHeadFile), 1);
            NewHeadFile = file_fullpath(NewHeadFile);
        end
        % Update Comment field
        HeadMat.Comment = 'Head';
        bst_save(file_fullpath(NewHeadFile), HeadMat, 'v7', 1);
    end

    % ===== CORTEX FILE =====
    % First hemisphere
    if ~isempty(CortexFile1)
        % Import file
        [iCortex1, OldCortexFile1] = import_surfaces(iSubject, CortexFile1, CortexFormat1, 0);
        OldCortexFile1 = OldCortexFile1{1};
        % Downsample
        NewCortexFile1 = tess_downsize(OldCortexFile1, nVertCortex, 'reducepatch');
        % Delete intial file
        if ~file_compare(NewCortexFile1, OldCortexFile1)
            file_delete(file_fullpath(OldCortexFile1), 1);
            NewCortexFile1 = file_fullpath(NewCortexFile1);
        end
    end
    % Second hemisphere
    if ~isempty(CortexFile2)
        % Import file
        [iCortex2, OldCortexFile2] = import_surfaces(iSubject, CortexFile2, CortexFormat2, 0);
        OldCortexFile2 = OldCortexFile2{1};
        % Downsample
        NewCortexFile2 = tess_downsize(OldCortexFile2, nVertCortex, 'reducepatch');
        % Delete intial file
        if ~file_compare(NewCortexFile2, OldCortexFile2)
            file_delete(file_fullpath(OldCortexFile2), 1);
            NewCortexFile2 = file_fullpath(NewCortexFile2);
        end
    end
    % Merge hemispheres
    if ~isempty(CortexFile1) && ~isempty(CortexFile2)
        CortexFile = tess_concatenate({NewCortexFile1, NewCortexFile2}, 'cortex');
        % Delete separate hemispheres
        file_delete({file_fullpath(NewCortexFile1), file_fullpath(NewCortexFile2)}, 1);
    % Only one hemisphere
    elseif ~isempty(CortexFile1)
        CortexFile = NewCortexFile1;
        % Update Comment field for Head file
        CortexMat.Comment = 'Cortex';
        bst_save(CortexFile, CortexMat, 'v7', 1);
    end
    % Set file type
    if ~isempty(CortexFile1) || ~isempty(CortexFile2)
        CortexFile = db_surface_type(CortexFile, 'Cortex');
    end

    % ===== INNER SKULL =====
    if ~isempty(InnerFile)
        % Import file
        [iInner, OldInnerFile] = import_surfaces(iSubject, InnerFile, InnerFormat, 0);
        OldInnerFile = OldInnerFile{1};
        % Set the file type
        OldInnerFile = db_surface_type(OldInnerFile, 'InnerSkull');
        % Downsample
        NewInnerFile = tess_downsize(OldInnerFile, nVertSkull, 'reducepatch');
        % Update Comment field
        InnerMat.Comment = 'Inner skull';
        bst_save(file_fullpath(NewInnerFile), InnerMat, 'v7', 1);
        % Delete intial file
        if ~file_compare(OldInnerFile, NewInnerFile)
            file_delete(file_fullpath(OldInnerFile), 1);
        end
    end

    % ===== OUTER SKULL =====
    if ~isempty(OuterFile)
        % Import file
        [iOuter, OldOuterFile] = import_surfaces(iSubject, OuterFile, OuterFormat, 0);
        OldOuterFile = OldOuterFile{1};
        % Set the file type
        OldOuterFile = db_surface_type(OldOuterFile, 'OuterSkull');
        % Downsample
        NewOuterFile = tess_downsize(OldOuterFile, nVertSkull, 'reducepatch');
        % Update Comment field
        OuterMat.Comment = 'Outer skull';
        bst_save(file_fullpath(NewOuterFile), OuterMat, 'v7', 1);
        % Delete intial file
        if ~file_compare(OldOuterFile, NewOuterFile)
            file_delete(file_fullpath(OldOuterFile), 1);
        end
    end

    % Reload subject folder (necessary, because we deleted manually some files,
    % without removing their references in the database)
    db_reload_subjects(iSubject);

    OutputFiles = {'import'};
end


function createReadmeSession(info)
% function createReadmeSession
%
% Dialog box to get basic descriptors of session.
% Writes these to Readme file.
% Called by mrCreateReadme.m
%
% djh, 9.4.01
% ras, 01/12/04: added 'RessCoil' and 'fMRICoil' to list of available
% coils.
% ras, 04/18/04: also added 'Posthead-ReceiveOnly' to coil list.
% ras, 03/30/05: uses info from existing readme if supplied.
% ras, 08/11/06: tries to get protocl from headers.
global mrSESSION dataTYPES

if notDefined('info')
    % set blank default vals, or vals from mrSESSION
    defaults = {...
            mrSESSION.sessionCode, mrSESSION.description,...
            mrSESSION.subject,'','','','',...
            num2str(mrSESSION.examNum),'',''...
        };

    % try to get protocol from header
    try
        w = dir('Raw/Anatomy/Inplane/I*');
        firstIfile = fullfile('Raw', 'Anatomy', 'Inplane', w(1).name);
        [img hdr] = mrReadIfile(firstIfile);
        defaults{10} = hdr.series.prtcl;
    end

else
    % get defaults from existing Readme.txt file
    defaults = {...
            info.session, info.description,...
            info.subject, info.operator, ...
            info.operator, info.magnet, info.coil...
            info.examNum, info.sliceOrientation,...
            info.protocol...
    };
end

c=0;

title = 'SESSION IDENTIFIERS';

c=c+1;
dlg(c).string = 'Session code:';
dlg(c).fieldName = 'sessionCode';
dlg(c).style = 'edit';
dlg(c).value = defaults{1};

c=c+1;
dlg(c).string = 'Description:';
dlg(c).fieldName = 'description';
dlg(c).style = 'edit';
dlg(c).value = defaults{2};
c=c+1;
dlg(c).string = 'Subject:';
dlg(c).fieldName = 'subject';
dlg(c).style = 'edit';
dlg(c).value = defaults{3};

c=c+1;
dlg(c).string = 'Operator:';
dlg(c).fieldName = 'operator';
dlg(c).style = 'edit';
dlg(c).value = defaults{4};

c=c+1;
dlg(c).string = 'Recon/Readme by:';
dlg(c).fieldName = 'scribe';
dlg(c).style = 'edit';
dlg(c).value = defaults{5};

c=c+1;
dlg(c).string = 'Magnet:';
dlg(c).fieldName = 'magnet';
dlg(c).style = 'popupmenu';
dlg(c).list = {'1.5 T', '3 T'};
dlg(c).choice = 2;
dlg(c).value = defaults{6};

c=c+1;
dlg(c).string = 'Coil:';
dlg(c).fieldName = 'coil';
dlg(c).style = 'popupmenu';
dlg(c).list = {'Posthead',  'RessCoil', 'fMRICoil', 'Posthead-ReceiveOnly','Helmet-head','Small-head', 'GE-head', 'Flex-quad'};
dlg(c).choice = 1;
dlg(c).value = defaults{7};

c=c+1;
dlg(c).fieldName = 'examNumber';
dlg(c).string = 'Exam number:';
dlg(c).style = 'edit';
dlg(c).value = defaults{8};

c=c+1;
dlg(c).string = 'Slice orientation:';
dlg(c).fieldName = 'sliceOrientation';
dlg(c).style = 'popupmenu';
dlg(c).list = {'Oblique', 'Coronal', 'Axial', 'Saggital'};
dlg(c).choice = 1;
dlg(c).value = defaults{9};

c=c+1;
dlg(c).string = 'Protocol name:';
dlg(c).fieldName = 'protocol';
dlg(c).style = 'edit';
dlg(c).value = defaults{10};

% Prepare to make dialog box, make it
height = 1;
vSkip = 0.12;
pos = [35,10,80,length(dlg)*(height+vSkip)+3];
x = 1;
y = length(dlg)*(height+vSkip)+1;
editWidth = 40;
stringWidth = 30;
for uiNum = 1:length(dlg)
    dlg(uiNum).stringPos = [x,y,stringWidth,height];
    dlg(uiNum).editPos = [x+stringWidth-1,y,editWidth,height];
    y = y-(height+vSkip);
end
resp = generaldlg(dlg, pos, title);

% Write to Readme.txt
[fid, message] = fopen('Readme.txt', 'w');
if (~exist('message','var'))
    message='default message';
end

if fid == -1
    warndlg(message);
    return
end

for i = 1:length(dlg)
    fprintf(fid, '%s %s\n', dlg(i).string, resp.(dlg(i).fieldName));
end

status = fclose(fid);
if status == -1
    warndlg(messsage);
    return
end

return


% mff_importpnsset - import information from MFF 'pnsSet.xml' file
%
% Usage:
%   chaninfo = mff_importpnsset(mffFile);
%
% Inputs:
%  mffFile - filename/foldername for the MFF file
%
% Output:
%  chaninfo - EEGLAB channel location structure

% This file is part of mffmatlabio.
%
% mffmatlabio is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% mffmatlabio 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 mffmatlabio.  If not, see <https://www.gnu.org/licenses/>.

function [chaninfo, rVal] = mff_importpnsset(mffFile)

chanlocs = [];
rVal = true;

p = fileparts(which('mff_importsignal.m'));
warning('off', 'MATLAB:Java:DuplicateClass');
javaaddpath(fullfile(p, 'MFF-1.2.2-jar-with-dependencies.jar'));
warning('on', 'MATLAB:Java:DuplicateClass');

% Create an MFFFactory object.
mfffactorydelegate = javaObject('com.egi.services.mff.api.LocalMFFFactoryDelegate');
mfffactory = javaObject('com.egi.services.mff.api.MFFFactory', mfffactorydelegate);

% Create Signal object and read in event track file.
% Note that 3 is the value associated with the event track resource type.
pnsURI = fullfile(mffFile, 'pnsSet.xml');
pnsType = javaObject('com.egi.services.mff.api.MFFResourceType', javaMethod('valueOf', 'com.egi.services.mff.api.MFFResourceType$MFFResourceTypes', 'kMFF_RT_PNSSet'));
pns = mfffactory.openResourceAtURI(pnsURI, pnsType);

chaninfo = [];
if ~isempty(pns)

    if pns.loadResource()

        sensors = pns.getPNSSensors();

        if ~isempty(sensors )

            for iSensor = 1:sensors.size
                sensor = sensors.get(iSensor-1);
                chaninfo(iSensor).labels = char(sensor.getName);
                chaninfo(iSensor).type   = 'PNS';
            end

        end
    else
        fprintf('Error: pnsSet ressource is null\n');
        rVal = false;
    end

else

    rVal = false;

end


function [spike] = ft_read_spike(filename, varargin)

% FT_READ_SPIKE reads spike timestamps and waveforms from various data formats.
%
% Use as
%  [spike] = ft_read_spike(filename, ...)
%
% Additional options should be specified in key-value pairs and can be
%   'spikeformat' = string, described the fileformat (default is automatic)
%
% The following file formats are supported
%   'blackrock_nev'
%   'mclust_t'
%   'neuralynx_ncs'
%   'neuralynx_nse'
%   'neuralynx_nst'
%   'neuralynx_ntt'
%   'neuralynx_nts'
%   'neuroshare'
%   'neurosim_spikes'
%   'nwb'
%   'plexon_ddt'
%   'plexon_nex'
%   'plexon_nex5'
%   'plexon_plx'
%   'wave_clus'
%
% The output spike structure usually contains
%   spike.label     = 1xNchans cell-array, with channel labels
%   spike.waveform  = 1xNchans cell-array, each element contains a matrix (Nleads x Nsamples X Nspikes)
%   spike.waveformdimord = '{chan}_lead_time_spike'
%   spike.timestamp = 1xNchans cell-array, each element contains a vector (1 X Nspikes)
%   spike.unit      = 1xNchans cell-array, each element contains a vector (1 X Nspikes)
% and is described in more detail in FT_DATATYPE_SPIKE
%
% See also FT_DATATYPE_SPIKE, FT_READ_HEADER, FT_READ_DATA, FT_READ_EVENT

% Copyright (C) 2007-2021 Robert Oostenveld, Arjen Stolk
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% optionally get the data from the URL and make a temporary local copy
filename = fetch_url(filename);

if ~exist(filename,'file')
  ft_error('File or directory does not exist')
end

% get the options
spikeformat = ft_getopt(varargin, 'spikeformat');

% optionally get the data from the URL and make a temporary local copy
filename = fetch_url(filename);

if isempty(spikeformat)
  % only do the autodetection if the format was not specified
  spikeformat = ft_filetype(filename);
end

switch spikeformat
  case {'neurosim_spikes' 'neurosim_ds'}
    spike = read_neurosim_spikes(filename);

  case {'neuralynx_ncs' 'plexon_ddt'}
    % these files only contain continuous data
    ft_error('file does not contain spike timestamps or waveforms');

  case 'matlab'
    % plain MATLAB file with a single variable in it
    load(filename, 'spike');

  case 'mclust_t'
    fp = fopen(filename, 'rb', 'ieee-le');
    H = ReadHeader(fp);
    fclose(fp);
    % read only from one file
    S = read_mclust_t({filename});
    spike.hdr = H(:);
    [p, f, x] = fileparts(filename);
    spike.label     = {f};  % use the filename as label for the spike channel
    spike.timestamp = S;
    spike.hdr       = H;

  case 'wave_clus'
    load(filename, 'cluster_class', 'spikes', 'par'); % load the mat file
    clusters = sort(unique(cluster_class(:,1))); % detected clusters
    clusters(clusters==0) = []; % remove rejected cluster (indexed by zeros)
    nclust = numel(clusters);
    [p, f, x] = fileparts(filename);
    t = tokenize(f, '_'); % extract channel name
    spike.label     = cell(1,nclust);
    spike.unit      = cell(1,nclust);
    spike.waveform  = cell(1,nclust);
    spike.timestamp = cell(1,nclust);
    spike.hdr       = par;
    for cl = 1:nclust
      unit_idx                  = cluster_class(:,1)==cl;
      spike.label{cl}           = [t{2} '-' num2str(cl)];
      spike.timestamp{cl}       = cluster_class(unit_idx,2)';
      spike.waveform{cl}(1,:,:) = spikes(unit_idx,:)';
      spike.unit{cl}            = cluster_class(unit_idx,1)';
    end
    fprintf('note that wave_clus timestamps are typically expressed in millisec and not in samples\n')

  case 'neuralynx_nse'
    % single channel file, read all records
    nse = read_neuralynx_nse(filename);
    if isfield(nse.hdr, 'NLX_Base_Class_Name')
      spike.label   = {nse.hdr.NLX_Base_Class_Name};
    else
      spike.label   = {nse.hdr.AcqEntName};
    end
    spike.timestamp = {nse.TimeStamp};
    spike.waveform  = {nse.dat};
    spike.unit      = {nse.CellNumber};
    spike.hdr       = nse.hdr;

  case 'neuralynx_nst'
    % single channel stereotrode file, read all records
    nst = read_neuralynx_nst(filename, 1, inf);
    if isfield(nst.hdr, 'NLX_Base_Class_Name')
      spike.label   = {nst.hdr.NLX_Base_Class_Name};
    else
      spike.label   = {nst.hdr.AcqEntName};
    end
    spike.timestamp = {nst.TimeStamp};
    spike.waveform  = {nst.dat};
    spike.unit      = {nst.CellNumber};
    spike.hdr       = nst.hdr;

  case 'neuralynx_ntt'
    % single channel stereotrode file, read all records
    ntt = read_neuralynx_ntt(filename);
    if isfield(ntt.hdr, 'NLX_Base_Class_Name')
      spike.label   = {ntt.hdr.NLX_Base_Class_Name};
    else
      spike.label   = {ntt.hdr.AcqEntName};
    end
    spike.timestamp = {ntt.TimeStamp};
    spike.waveform  = {ntt.dat};
    spike.unit      = {ntt.CellNumber};
    spike.hdr       = ntt.hdr;

  case 'neuralynx_nts'
    % single channel file, read all records
    nts = read_neuralynx_nts(filename);
    if isfield(nte.hdr, 'NLX_Base_Class_Name')
      spike.label   = {nts.hdr.NLX_Base_Class_Name};
    else
      spike.label   = {nts.hdr.AcqEntName};
    end
    spike.timestamp = {nts.TimeStamp(:)'};
    spike.waveform  = {zeros(0,length(nts.TimeStamp))};  % does not contain waveforms
    spike.unit      = {zeros(0,length(nts.TimeStamp))};  % does not contain units
    spike.hdr       = nts.hdr;

  case 'plexon_nex'
    % a single file can contain multiple channels of different types
    hdr  = read_plexon_nex(filename);
    typ  = [hdr.VarHeader.Type];
    chan = 0;

    spike.label     = {};
    spike.timestamp = {};
    spike.waveform  = {};
    spike.unit      = {};

    for i=1:length(typ)
      if typ(i)==0
        % neurons, only timestamps
        nex = read_plexon_nex(filename, 'channel', i);
        nspike = length(nex.ts);
        chan = chan + 1;
        spike.label{chan}     = deblank(hdr.VarHeader(i).Name);
        spike.waveform{chan}  = zeros(0, nspike);
        spike.unit{chan}      = nan(1,nspike);
        spike.timestamp{chan} = nex.ts;
      elseif typ(i)==3
        % neurons, timestamps and waveforms
        nex = read_plexon_nex(filename, 'channel', i);
        chan = chan + 1;
        nspike = length(nex.ts);
        spike.label{chan}     = deblank(hdr.VarHeader(i).Name);
        spike.waveform{chan}  = permute(nex.dat,[3 1 2]);
        spike.unit{chan}      = nan(1,nspike);
        spike.timestamp{chan} = nex.ts;
      end
    end
    spike.hdr = hdr;

  case 'plexon_nex5'
    % a single file can contain multiple channels of different types
    hdr  = read_nex5(filename);
    typ  = [hdr.VarHeader.Type];
    chan = 0;

    spike.label     = {};
    spike.timestamp = {};
    spike.waveform  = {};
    spike.unit      = {};

    for i=1:length(typ)
      if typ(i)==0
        % neurons, only timestamps
        nex = read_nex5(filename, 'channel', i);
        nspike = length(nex.ts);
        chan = chan + 1;
        spike.label{chan}     = deblank(hdr.VarHeader(i).Name);
        spike.waveform{chan}  = zeros(0, nspike);
        spike.unit{chan}      = nan(1,nspike);
        % spike.timestamp{chan} are the raw timestamps as recorded by the hardware system
        spike.timestamp{chan} = nex.ts;
      elseif typ(i)==3
        % waveform variables: timestamps and waveforms
        nex = read_nex5(filename, 'channel', i);
        chan = chan + 1;
        nspike = length(nex.ts);
        spike.label{chan}     = deblank(hdr.VarHeader(i).Name);
        spike.waveform{chan}  = permute(nex.dat,[3 1 2]);
        spike.unit{chan}      = nan(1,nspike);
        % spike.timestamp{chan} are the raw timestamps as recorded by the hardware system
        spike.timestamp{chan} = nex.ts;
      end
    end
    spike.hdr = hdr;

  case 'plexon_plx'
    % read the header information
    hdr   = read_plexon_plx(filename);
    nchan = length(hdr.ChannelHeader);
    typ   = [hdr.DataBlockHeader.Type];
    unit  = [hdr.DataBlockHeader.Unit];
    chan  = [hdr.DataBlockHeader.Channel];

    for i=1:nchan
      % select the data blocks that contain spike waveforms and that belong to this channel
      sel = (typ==1 & chan==hdr.ChannelHeader(i).Channel);

      if any(sel)
        % get the timestamps that correspond with this spike channel
        tsl = [hdr.DataBlockHeader(sel).TimeStamp];
        tsh = [hdr.DataBlockHeader(sel).UpperByteOf5ByteTimestamp];
        % convert the 16 bit high timestamp into a 32 bit integer
        ts = timestamp_plexon(tsl, tsh);
        spike.timestamp{i} = ts;
        spike.unit{i}      = unit(sel);
      else
        % this spike channel is empty
        spike.timestamp{i} = [];
        spike.unit{i}      = [];
      end
    end
    for i=1:nchan
      spike.label{i}    = deblank(hdr.ChannelHeader(i).Name);
      spike.waveform{i} = permute(read_plexon_plx(filename, 'ChannelIndex', i, 'header', hdr),[3 1 2]);
    end
    spike.hdr = hdr;

  case 'neuroshare' % NOTE: still under development
    % check that the required neuroshare toolbox is available
    ft_hastoolbox('neuroshare', 1);

    tmp = read_neuroshare(filename, 'readspike', 'yes');
    spike.label = {tmp.hdr.entityinfo(tmp.list.segment).EntityLabel};
    for i=1:length(spike.label)
      spike.waveform{i}  = tmp.spikew.data(:,:,i);
      spike.timestamp{i} = tmp.spikew.timestamp(:,i)';
      spike.unit{i}      = tmp.spikew.unitID(:,i)';
    end

  case 'neuroscope'
    % the information about the spikes is represented in:
    % x.clu.y or x.res.y (containing the timing +cluster info)
    % x.spk.y (containing the waveform info)
    % x.fet.y (containing features: do we need this?)

    if isfolder(filename)
      tmp = dir(filename);
      filenames = {tmp.name}';
    end

    % read the header
    filename_hdr = filenames{~cellfun('isempty',strfind(filenames,'.xml'))};
    hdr          = ft_read_header(fullfile(filename,filename_hdr), 'headerformat', 'neuroscope_xml');
    spikegroups  = hdr.orig.spikeGroups;
    fsample      = hdr.orig.rates.wideband;

    filename_clu = filenames(~cellfun('isempty',strfind(filenames,'.clu')));
    filename_spk = filenames(~cellfun('isempty',strfind(filenames,'.spk')));

    % FIXME should we do a sanity check on whether the clu and spk actually
    % belong together?

    c = cell(numel(filename_clu),1);
    w = cell(numel(filename_spk),1);
    for k = 1:numel(filename_clu)
      c{k} = LoadSpikeTimes(fullfile(filename,filename_clu{k}), fsample);
    end
    for k = 1:numel(filename_spk)
      w{k} = LoadSpikeWaveforms(fullfile(filename,filename_spk{k}),numel(spikegroups.groups{k}),spikegroups.nSamples(k));
    end

    spike = [];
    spike.label = cell(hdr.orig.spikeGroups.nGroups,1);
    spike.hdr   = hdr;
    spike.unit      = cell(1,numel(spike.label));
    spike.waveform  = cell(1,numel(spike.label));
    spike.timestamp = cell(1,numel(spike.label));

    for k = 1:numel(spike.label)
      sel = find(c{k}(:,3)>1); % values >1 corresponds to individual units, 0 = noise, 1 = MUA

      % the times are defined in s, convert to original time stamps
      timestamps = c{k}(sel,1) * hdr.orig.rates.wideband;
      if any(abs(timestamps-round(timestamps))>1e-5)
        ft_error('there seems to be a mismatch between the spike times and the expected integer-valued timestamps');
      end

      spike.timestamp{k} = round(timestamps(:))';
      spike.waveform{k}  = permute(w{k}(sel,:,:), [2 3 1]);
      spike.unit{k}      = c{k}(sel,3)';
      spike.label{k}     = sprintf('spikegroup%03d',k);
    end

  case 'nwb'
    ft_hastoolbox('MatNWB', 1);
    spike = read_nwb_spike(filename);

  case {'blackrock_nev'}
    % use the NPMK toolbox for the file reading
    ft_hastoolbox('NPMK', 1);

    % ensure that the filename contains a full path specification,
    % otherwise the low-level function fails
    [p, f, x] = fileparts(filename);
    if ~isempty(p)
      % this is OK
    elseif isempty(p)
      filename = which(filename);
    end

    % 'nosave' prevents the automatic conversion of the .nev file as a .mat file
    nev = openNEV(filename, 'nosave');

    nchan = length(nev.ElectrodesInfo);
    for i=1:nchan
      spike.label{i} = deblank(nev.ElectrodesInfo(i).ElectrodeLabel(:)');
      if isfield(nev.Data, 'Spikes')
        % select the spikes that were detected on this electrode
        sel = nev.Data.Spikes.Electrode;
        spike.timestamp{i} = nev.Data.Spikes.TimeStamp(sel);
        spike.unit{i}      = nev.Data.Spikes.Unit(sel);
        spike.waveform{i}  = nev.Data.Spikes.Waveform(sel);
      end
    end

  otherwise
    ft_error(['unsupported data format (' spikeformat ')']);
end

% add the waveform
if isfield(spike,'waveform')
  spike.dimord = '{chan}_lead_time_spike';
end


function name = p12_name ( )

%*****************************************************************************80
%
%% P12_NAME returns the name of problem 12.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string NAME, the name of the problem.
%
  name = 'BFN02';

  return
end


%MVTBDEMO 	Machine Vision toolbox demonstrations
%
% Displays popup menu of toolbox demonstration scripts that illustrate:
%   - image processing
%   - feature extraction
%   - visual servoing
%
% Notes::
% - The scripts require the user to periodically hit <Enter> in order to move
%   through the explanation.
% - Set PAUSE OFF if you want the scripts to run completely automatically.

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
function mvtbdemo(timeout)
    echo off
    close all
    echo off
    clear all
    delete( get(0, 'Children') );

    % find the path to the demos
    if exist('mvtbdemo', 'file') == 2
        tbpath = fileparts(which('mvtbdemo'));
        demopath = fullfile(tbpath, 'demos');
    end

    opts = {'begin', 'path', demopath};

    % if a timeout interval is given, add this to the options
    if nargin > 0
        opts = {opts, 'delay', timeout};
    end

    fprintf('------------------------------------------------------------\n');
    fprintf('Many of these demos print tutorial text and MATLAB commmands in the console window.\n');
    fprintf('Read the text and press <enter> to move on to the next command\n');
    fprintf('At the end of the tutorial/demo you can choose the next one from the graphical menu.\n');
    fprintf('------------------------------------------------------------\n');

    demos = {
        'Basics', 'files';
        'Image/Movie file', 'moviegrab';
        'Image/Webcam', 'webcam';
        'Image/Google Earth', 'earthgrab';
        'Image/Live video', 'livevideo';
        'Image/Track object', 'trackblue';
        'Application/Mosaicing', 'mosaic';
        'Application/ICP', 'icp';              % broken
        'Application/Line Fit', 'linefit';     % broken
        'Application/Hough transform', 'hough';
        'Application/Chroma key', 'chromakey';
        'Application/RANSAC', 'ransac';         % broken
        'Application/Background estimation', 'bgest';
        'Application/Where''s Wally', 'wally';
        'Multiview/Stereo', 'stereo';
        % blobs
        % camera
        % convdemo
        % fly
        % harris
        % homdemo
        % imagegrab
        % kernel
        % lensanim
        % opticalflow
        % poseest
        % ransacline
        % seg
        % skel
        % track
        % track2
        % vservo_points
        % xx
        'VisualServo/Mosaicing', '';
        'VisualServo/Mosaicing', 'mosaic';
        'VisualServo/Mosaicing', 'mosaic';
        'Exit', '';
        };

    while true
        selection = menu('Machine Vision Toolbox demonstrations', demos{:,1});
        if strcmp(demos{selection,1}, 'Exit')
            % quit now
            delete( get(0, 'Children') );
            break;
        else
            % run the appropriate script
            script = demos{selection,2}
            runscript(script, opts{:})
        end
    end
end


function vw = meshUpdateAll(vw)
% Update all mesh displays associated with a mrVista view.
%
% vw = meshUpdateAll([vw=cur gray view]);
%
% ras, 08/2008.
if notDefined('vw'), vw = getSelectedGray; end

if ~isfield(vw, 'mesh') || isempty(viewGet(vw, 'mesh'))
	return
end

% remember the currently selected mesh, to restore it later
curMesh = viewGet(vw, 'mesh num');

for ii = 1:length(viewGet(vw, 'allmeshes'))
	vw = viewSet(vw, 'mesh num', ii);
	vw = meshColorOverlay(vw);
end

% restore the originally-selected mesh
vw = viewSet(vw, 'mesh num', curMesh);

return


classdef MimEditGrey < MimGuiPlugin
    % MimEditGrey. Gui Plugin for setting paint colour
    %
    %     You should not use this class within your own code. It is intended to
    %     be used by the gui of the TD MIM Toolkit.
    %
    %     MimEditGrey is a Gui Plugin for the MIM Toolkit.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties
        ButtonText = 'Grey'
        SelectedText = 'Grey'
        ToolTip = 'Edit with grey label'
        Category = 'Segmentation label'
        Visibility = 'Dataset'
        Mode = 'Edit'

        HidePluginInDisplay = false
        PTKVersion = '1'
        ButtonWidth = 5
        ButtonHeight = 1
        Icon = 'paint.png'
        IconColour = GemMarkerPoint.DefaultColours{7}
        Location = 37
    end

    methods (Static)
        function RunGuiPlugin(gui_app)
            gui_app.ImagePanel.PaintBrushColour = 7;
        end

        function enabled = IsEnabled(gui_app)
             enabled = gui_app.IsDatasetLoaded && gui_app.ImagePanel.OverlayImage.ImageExists && ...
                isequal(gui_app.ImagePanel.SelectedControl, 'Paint');
        end

        function is_selected = IsSelected(gui_app)
            is_selected = gui_app.ImagePanel.PaintBrushColour == 7;
        end
    end
end


% eeg_options() - eeglab option script
%
% Note: DO NOT EDIT, instead use pop_editoptions() or the menu
%       /File/Maximize memory in EEGLAB gui

% STUDY options (set these checkboxes if you intend to work with studies)
option_storedisk = 0 ; % If set, keep at most one dataset in memory. This allows processing hundreds of datasets within studies.
option_savetwofiles = 1 ; % If set, save not one but two files for each dataset (header and data). This allows faster data loading in studies.
% Memory options
option_single = 1 ; % If set, use single precision under Matlab 7.x. This saves RAM but can lead to rare numerical imprecisions.
option_memmapdata = 0 ; % If set, use memory mapped array under Matlab 7.x. This may slow down some computation.
% ICA options
option_computeica = 0 ; % If set, precompute ICA activations. This requires more RAM but allows faster plotting of component activations.
option_scaleicarms = 1 ; % If set, scale ICA component activities to RMS (Root Mean Square) in microvolt (recommended).
% Folder options
option_rememberfolder = 1 ; % If set, when browsing to open a new dataset assume the folder/directory of previous dataset.


function rss=get_rss_from_file(url)
csi_trace = read_bf_file(url);
csi_trace = get_csi_trace_sqeezed(csi_trace);
rss = get_rss_from_csitrace(csi_trace);
end


function d = rcnn_load_cached_pool5_features(cache_name, imdb_name, id)
% d = rcnn_load_cached_pool5_features(cache_name, imdb_name, id)
%   loads cached pool5 features from:
%   feat_cache/[cache_name]/[imdb_name]/[id].mat

% AUTORIGHTS
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

file = sprintf('./feat_cache/%s/%s/%s', cache_name, imdb_name, id);

if exist([file '.mat'], 'file')
  d = load(file);
else
  warning('could not load: %s', file);
  d = create_empty();
end

% standardize boxes to double (for overlap calculations, etc.)
d.boxes = double(d.boxes);

% ------------------------------------------------------------------------
function d = create_empty()
% ------------------------------------------------------------------------
d.gt = logical([]);
d.overlap = single([]);
d.boxes = single([]);
d.feat = single([]);
d.class = uint8([]);


function mkdirKPM(dname)
% function mkdirKPM(dname)
% If directory does not exist, make it
%
% mkdirKPM('foo\bar\baz') makes subdirectories bar and baz
% mkdirKPM('foo\bar\baz.txt') makes subdirectories bar

% convert foo\bar\baz to pathstr=foo\bar, name=baz
% convert foo\bar\baz.txt to pathstr=foo\bar, name=baz
[pathstr, name, ext, versn] = fileparts(dname);
if ~isempty(ext) % we stripped off something after final period
  % convert foo\bar to pathstr=foo, name=bar
  % convert foo\bar.bad to pathstr=foo, name=bar.bad
  [pathstr, name, ext, versn] = fileparts(pathstr);
  name = sprintf('%s%s', name, ext); % in case there is a period in the directory name
end

dname = fullfile(pathstr, name);
if ~exist(dname, 'dir')
  %fprintf('mkdirKPM: making %s, %s \n', pathstr, name);
  mkdir(pathstr, name)
else
  %fprintf('mkdirKPM: %s already exists\n', dname)
end


function varargout = create_main_inputfile(GID)
fid = fopen('main_inputfile.m','w+');  % open file

fprintf(fid, ...
 ['function varargout = main_inputfile(varargin)\n' ...
  '%% Task(menu).name   - name of task. Task(1).name is ''File'', Task(2).name is\n' ...
  '%%                     ''Model'', Task(8).name is ''Help''.\n' ...
  '%% Task(menu).string - For each menu item (or any sub-items), there are 4\n' ...
  '%%                     parameters that needed to be specified.\n' ...
  '%%                     (1) index -- There are up to 3 cascading levels of\n' ...
  '%%                     menu items. Each level can have up to 9 menu items.\n' ...
  '%%                     For example, "100" represents menu item 1 of level 1.\n' ...
  '%%                     "236" is item 2 selected from level 1 and item 3 from\n' ...
  '%%                     level 2 and item 6 from level 3.\n' ...
  '%%                     (2) label -- menu item label corresponding to index\n' ...
  '%%                     (3) type  -- menu item type; type ''doc1'' if the\n' ...
  '%%                     action is to open html or pdf file; ''run1'' to execute\n' ...
  '%%                     a matlab function; etc.\n' ...
  '%%                     (4) operands -- for type ''doc1'', this would be the\n' ...
  '%%                     html or pdf file; for type ''run1'', this would be the\n' ...
  '%%                     name of the function and its arguments.\n' ...
  '%%                     You can enter the menu items in any order\n' ...
  ]);
fprintf(fid, ...
    ['clear all\n' ...
     'if nargin > 0\n' ...
     '%% update gui4gui_inputfile with modified "Task" from the gui4gui input GUI\n' ...
     '    GID = varargin{1};\n' ...
     '    %% insert any additional modifications here\n' ...
     '    save gui4gui_inputfile GID;\n' ...
     'else\n' ...
     '%% the gui4gui package comes with this mfile pre-loaded with the setup\n' ...
     '%% for the MODE code. Some of these data are universal for all codes if\n' ...
     '%% you prepare PDF/HTML files and label them with the same names, such as\n' ...
     '%% to call the tutorial file Tutorial.ppt or name the abstract Abstract.pdf.\n' ...
     '%% You may also edit this file and change any contents that you wish.\n' ...
     '%% However, you should not remove any fields in Task. If you don''t need\n' ...
     '%% a specific menu item, just remove its content, like this\n' ...
     '%% Task(1).label = {};\n' ...
     '%%\n' ...
     '%% Define number of menus (File, Model, Articles, Tutorial, Examples, Run, Code, Help)\n' ...
     '%%\n']);
fprintf(fid,'Nmenus = %d;\n',GID.Nmenus);
fprintf(fid,'\n');
Nmenus = GID.Nmenus;
for menu=1:Nmenus
fprintf(fid, ...
    'Task(%d).name = ''%s'';\n', menu,GID.task(menu).name);
fprintf(fid, ...
    'Task(%d).string = { ...\n',menu);
n = length(GID.task(menu).string(:,1));
for k=1:n
  fprintf(fid,' %d ''%s''  ''%s''  ''%s'' ...\n',GID.task(menu).string{k,1:4});
end
fprintf(fid,'};\n\n');
end

fprintf(fid, ...
['for menu=1:Nmenus\n' ...
 '    task(menu).name = Task(menu).name;\n' ...
 '    for n=1:length(Task(menu).string(:))/4\n' ...
 '        task(menu).string(n,1) = Task(menu).string(1+(n-1)*4);\n' ...
 '        task(menu).string(n,2) = Task(menu).string(2+(n-1)*4);\n' ...
 '        task(menu).string(n,3) = Task(menu).string(3+(n-1)*4);\n' ...
 '        task(menu).string(n,4) = Task(menu).string(4+(n-1)*4);\n' ...
 '    end\n' ...
 'end\n']);

fprintf(fid, ...
['  GID.guiName = ''%s'';\n' ...
 '  GID.Nmenus = Nmenus;\n' ...
 '  GID.frontImage = ''%s'';\n' ...
 '  GID.bgcolor = ''%s'';\n' ...
 '  GID.fontsize = %d;\n' ...
 '  GID.fontweight = ''%s'';\n' ...
 '  GID.position = [%4.2f %4.2f %4.2f %4.2f];\n' ...
 '  GID.resize = ''%s'';\n' ...
 '  GID.task = task;\n'], ...
 GID.guiName, GID.frontImage, GID.bgcolor, GID.fontsize, ...
 GID.fontweight, GID.position, GID.resize);

fprintf(fid,'\n');
fprintf(fid, ...
['%% The buildMainGUI builder needs fields label, type and ops\n' ...
 '%% The addLabel function can extract them from GID''s string field\n' ...
 '  GID = addLabel(GID);\n']);

fprintf(fid,'\n');
fprintf(fid, ...
['%% returns the final GID to the caller.\n' ...
 '  varargout{1} = GID;\n' ...
 '%% Also save GID to the following file.\n' ...
 '  save main_inputfile GID;\n' ...
 'end   %% if\n']);


function mtrSetupGastrocParams(subjID)

% Setting up parameters files for a subject based on ROIs assumes
% 1. You are in the subject directory
% 2. A met_params.txt file is already in the conTrack directory

localSubjDir = ['/biac2/wandell2/data/conTrack/muscle/' subjID];
dlhSubjDir = ['/radlab_share/home/tony/images/' subjID];
lappySubjDir = ['c:/cygwin/home/sherbond/images/' subjID];
machineListL = {'deep-lumen1','deep-lumen2','deep-lumen4'};
% machineListR = {'deep-lumen5','deep-lumen6','deep-lumen8'};
mtrTwoRoiSamplerSISR(localSubjDir, 'tendon_plate.mat', 'end_voi.mat', 'met_params.txt', 'GAS_met_params.txt', 'paths_GAS.dat', 'gasRoisMask.nii.gz');
mtrTwoRoiSamplerSISR(localSubjDir, 'tendon_plate.mat', 'end_voi.mat', 'met_params.txt', 'GAS_met_params_lap.txt', 'paths_GAS.dat', 'gasRoisMask.nii.gz', 'temp.sh', lappySubjDir, machineListL);

delete(fullfile('conTrack','temp.sh'));


%
% FILE NAME:    applyJSON2RxnAssoc.m
%
% PURPOSE: Sort out and clean up the previous .mat files generated during
%          reaction association/curation of human-GEM:
%          1. identify redundant rxn-association .mat files and remove them;
%          2. convert the remained .mat files to JSON format as discussed
%          in #75, while retaining the content unchanged.
%

%% sort out and clean the reaction association files to HMR2

% There are two Matlab model structures (ihumanRxns2BiGG.mat and
% ihumanRxns2MNX.mat) that were generated from the HMR2 model during
% reaction-association curation. Since all the fields in ihumanRxns2BiGG
% are shared in ihumanRxns2MNX and with the same content, and the latter
% includes addtional information. The ihumanRxns2BiGG.mat file is moved to
% `deprecated` subfolder for reducing repetition.

% load the reaction association file and assign its info to a temp variable
load('ihumanRxns2MNX.mat');

r.rxns                = ihuman.rxns;                    % HMR id
r.rxnKEGGID           = ihuman.rxnKEGGID;               % KEGG
r.rxnEHMNID           = ihuman.rxnEHMNID;               % EHMN
r.rxnBiGGID           = ihuman.rxnBiGGID;               % BiGG
r.rxnHepatoNET1ID     = ihuman.rxnHepatoNET1ID;         % HepatoNET1
r.rxnREACTOMEID       = ihuman.rxnREACTOMEID;           % REACTOME
r.BiGG2BiGG           = ihuman.BiGG2BiGG;               % map to BiGG db id
r.HepatoNet12BiGG     = ihuman.HepatoNet12BiGG;         % HepatoNet1 map to BiGG id
r.EHMN2BiGG           = ihuman.EHMN2BiGG;               % EHMN map to BiGG id
r.HMR2BiGG            = ihuman.HMR2BiGG;                % combined BiGG ids from above
r.rxnBiGGDB2MNX       = ihuman.rxnBiGGDB2MNX;           % BiGG id to MNX id
r.rxnKEGG2MNX         = ihuman.rxnKEGG2MNX;             % KEGG id to MNX id
r.rxnREACTOMEStableID = ihuman.rxnREACTOMEStableID;     % REACTOME Stable ID
r.rxnReactome2MNX     = ihuman.rxnReactome2MNX;         % Reactome id 2 MNX id
r.rxnMNXID            = reformatElements(ihuman.rxnMNXID,'cell2str');  % MetaNetX, non-unique association
r.rxnCompIdx          = ihuman.rxnCompIdx;              % index of involved compartments

% encode to JSON format and pretty the layout before saving as plaintext file
jsonStr = jsonencode(r);
fid = fopen('ihumanRxns2MNX.JSON', 'w');
fwrite(fid, prettyJson(jsonStr));
fclose(fid);

% check if the content of JSON file is identical to that of .mat file
check = jsondecode(fileread('ihumanRxns2MNX.JSON'));
if isequal(r, check)
    fprintf('\nThe file ihumanRxns2MNX.JSON is confirmed with the same content to ihumanRxns2MNX.mat, which therefore can be removed!\n\n');
end

%% sort and clean up reaction association files to Recon3D

% There are two Matlab model structures (Recon3Rxns2MNX.mat and Recon3Rxns2HMR.mat)
% that were generated for Recon3D reaction-association curation. Since
% all the fields of Recon3Rxns2MNX.mat have already been included in
% Recon3Rxns2HMR.mat, which also includes some addtional fields. Hence the
% Recon3Rxns2MNX.mat is thus moved to `deprecated` subfolder for avoidance
% of repetition.

% load the reaction association file and assign its info to a temp variable
load('Recon3Rxns2HMR.mat');
clear r;   % clean and reuse the temp variable

r.rxns         = Recon3D.rxns;          % Recon3D id
r.rxnKEGGID    = Recon3D.rxnKEGGID;     % KEGG
r.rxnBiGGID    = Recon3D.rxnBiGGID;     % BiGG
r.rxnMNXID     = Recon3D.rxnMNXID;      % MetaNetX
r.rxnHMRID     = Recon3D.rxnHMRID;      % HMR id
r.BiGG2HMR     = Recon3D.BiGG2HMR;      % BiGG map to HMR id
r.rxnCompIdx   = Recon3D.rxnCompIdx;    % index of involved compartments
%r.comps       = Recon3D.comps;         % identical field is in Recon3DRAVEN
%r.compNames   = Recon3D.compNames;     % identical field is in Recon3DRAVEN
r.withMNXnoHMR = Recon3D.withMNXnoHMR;  % can be associated to MNX but not HMR

% Note that BiGG2HMR and rxnHMRID are different, the latter is used for the
% generation of rxnAssoc.mat

% encode to JSON format and pretty the layout before saving as plaintext file
jsonStr = jsonencode(r);
fid = fopen('Recon3Rxns2HMR.JSON', 'w');
fwrite(fid, prettyJson(jsonStr));
fclose(fid);

% check the content of JSON file, make sure they are identical to that of .mat file
check = jsondecode(fileread('Recon3Rxns2HMR.JSON'));
if isequal(r, check)
    fprintf('\nThe file Recon3Rxns2HMR.JSON is confirmed with the same content to Recon3Rxns2HMR.mat, which therefore can be removed!\n\n');
end


%kasi2kdf 'imports a file from the SpectraCube system of ASI '
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros asi2kdf.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% MultiChoice: t 'File Type', default: 2: 'Integer toggle selection'
%    Choices are:
%   1: 'Spectral raw-data file (.raw)'
%   2: 'Interferogram raw-data (.sdi) type 1'
%   3: 'Interferogram binary exprot (.sdm)'
%   4: 'Interferogram raw-data (.sdi) type 2'
% Integer: px 'PosX', default: 326: 'X-size position in headerfile'
% Integer: py 'PosY', default: 327: 'Y-size position in headerfile'
% Integer: pz 'PosChan', default: 325: 'Channel-size position in headerfile'
% Integer: hs 'Headersize', default: 334: 'Size of the header in Unsigned SHorts'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kasi2kdf(i, {'i','';'t',2;'px',326;'py',327;'pz',325;'hs',334;'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% asi2kdf - imports a file from the SpectraCube system of ASI
%
%  DESCRIPTION
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1996-2003, Rainer Heintzmann,  All rights reserved.
%

function varargout = kasi2kdf(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kasi2kdf(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'t', 2;'px', 326;'py', 327;'pz', 325;'hs', 334;'o', '__output'};
maxval={0,0,0,0,0,0,0};
minval={0,0,0,0,0,0,0};
istoggle=[0,0,1,1,1,1,0];
was_set=istoggle * 0;
paramtype={'InputFile','MultiChoice','Integer','Integer','Integer','Integer','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'asi2kdf"  -k'],Inputs,narglist);


% PARSE A GENERIC INPUT SET AGAINST A DEFAULT CONFIG STRUCTURE
function [config] = GetParameterOverrides(defaultConfig,inputParameters)
% This function is designed to compare a vector of {'input',parameter} pairs
% against a structure(or object) with labelled fields.

% INPUTS:
% defaultConfig     - The reference structure/class with available fields.
% inputParameters   - The cell array of string, parameter pairs or
%                     comparative structure.
% OUTPUT:
% config            - The structure/class with the fields overitten.

% Input sanity check #1
if nargin < 2 || numel(inputParameters) == 0
    config = defaultConfig;
    return
end

% Input sanity check #2 - Check nested cell arrays
if iscell(inputParameters)
    t = 1;
    while numel(inputParameters) == 1 && t < 10
        inputParameters = inputParameters{:};
        t = t + 1;
    end
    assert(t ~= 10,'Failed to unload parameters.');
end

% Input-dependant behaviour
switch true
    case iscell(inputParameters)
        assert(mod(numel(inputParameters),2) == 0,'Entries are not of list of parameter:value pairs');
        config = parseCellArray(defaultConfig,inputParameters);
        return
    case isstruct(inputParameters)
        config = parseStructure(defaultConfig,inputParameters);
        return
    otherwise
        error('Please provide a list of parameter:value pairs or a structure.');
end
end

% Parse the input parameters against a list of parameter:value cell array
function [config] = parseCellArray(config,inputParameters)

% Move through the parameter pairs (i.e. ,'radius',1,...)
for parameterIndex = 1:numel(inputParameters)
    % For each user-defined parameter
    givenParameter = inputParameters{parameterIndex};
    if ~ischar(givenParameter)
        continue
    end

    % IF THE OBJECT HAS A PROPERTY BY THAT NAME
    if isstruct(config) && isfield(config,givenParameter)
        config.(givenParameter) = inputParameters{parameterIndex + 1};  % Make a substitution
    end
    if ~isstruct(config) && isprop(config,givenParameter)
        config.(givenParameter) = inputParameters{parameterIndex + 1};   % Make a substitution
    end
end
end
% Parse the input parameters against a structure
function [config] = parseStructure(config,inputStructure)

% Move through the fields of the second structure and override associated
% fields.
fields = fieldnames(inputStructure);
for f = 1:numel(fields)
    % Config is a struct
    if isstruct(config) && isfield(config,fields{f})
        config.(fields{f}) = inputStructure.(fields{f});        % Make a substitution
        continue
    end
    % Config is a class
    if ~isstruct(config) && isprop(config,fields{f})
        config.(fields{f}) = inputStructure.(fields{f});        % Make a substitution
        continue
    end
end
end


function rot = rotation(sym)

rot = sym.rot;

end


classdef TestImageUtilities < CoreTest
    % TestImageUtilities. Tests for the PTKTextUtilities class.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    methods
        function obj = TestImageUtilities
            obj.TestCT;
        end
    end

    methods (Access = private)
        function TestCT(obj)
            datasets = {};
            datasets{end + 1} = obj.MakeDataset('OT', 12, 'OT0');
            datasets{end + 1} = obj.MakeDataset('CT', 12, 'CT1');
            datasets{end + 1} = obj.MakeDataset('CT', 14, 'CTlarge');
            datasets{end + 1} = obj.MakeDataset('CT', 1, 'CT2');
            datasets{end + 1} = obj.MakeDataset('MR', 13, 'MR1');
            datasets{end + 1} = obj.MakeDataset('OT', 25, 'OT1');
            obj.Assert(strcmp(MimImageUtilities.FindBestSeries(datasets), 'CTlarge'));
        end

        function TestMR(obj)
            datasets = {};
            datasets{end + 1} = obj.MakeDataset('OT', 12, 'OT0');
            datasets{end + 1} = obj.MakeDataset('CT', 12, 'CT1');
            datasets{end + 1} = obj.MakeDataset('CT', 14, 'CTlarge');
            datasets{end + 1} = obj.MakeDataset('CT', 1, 'CT2');
            datasets{end + 1} = obj.MakeDataset('MR', 13, 'MR1');
            datasets{end + 1} = obj.MakeDataset('MR', 100, 'MRlarge');
            datasets{end + 1} = obj.MakeDataset('OT', 250, 'OT1');
            obj.Assert(strcmp(MimImageUtilities.FindBestSeries(datasets), 'MRlarge'));
        end

        function TestOther(obj)
            datasets = {};
            datasets{end + 1} = obj.MakeDataset('AB', 12, 'CT1');
            datasets{end + 1} = obj.MakeDataset('CD', 14, 'CTlarge');
            datasets{end + 1} = obj.MakeDataset('EF', 1, 'CT2');
            datasets{end + 1} = obj.MakeDataset('GH', 1300, 'GHuid');
            datasets{end + 1} = obj.MakeDataset('IJ', 100, 'MRlarge');
            datasets{end + 1} = obj.MakeDataset('KL', 250, 'OT1');
            obj.Assert(strcmp(MimImageUtilities.FindBestSeries(datasets), 'GHuid'));
        end
    end

    methods (Access = private, Static)
        function fake_dataset = MakeDataset(modality, num_images, uid)
            fake_dataset = struct;
            fake_dataset.Modality = modality;
            fake_dataset.NumberOfImages = num_images;
            fake_dataset.SeriesUid = uid;
        end
    end
end