function this = subsasgn(this, subs, A)
% Subscript assignment for GIfTI objects
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: subsasgn.m 6513 2015-08-05 17:52:13Z guillaume $

switch subs(1).type
    case '.'
        if ~ismember(subs(1).subs, ...
                {'vertices' 'faces' 'normals' 'cdata','mat','indices','private'})
            error('Reference to non-existent field ''%s''.',subs(1).subs);
        end
        % TODO % handle cases when length(subs) > 1
        [i,n] = isintent(this,subs(1).subs);
        if isempty(i) && ~strcmp(subs(1).subs,'private')
            n = length(this.data) + 1;
            if n==1, this.data = {}; end
            % TODO % Initialise data field appropriately
            this.data{n}.metadata = struct([]);
            this.data{n}.space    = [];
            this.data{n}.attributes.Dim = size(A);
            % TODO % set DataType according to intent type
            this.data{n}.data = [];
            switch subs(1).subs
                case {'vertices','mat'}
                    in = 'NIFTI_INTENT_POINTSET';
                    dt = 'NIFTI_TYPE_FLOAT32';
                    this.data{n}.space.DataSpace = 'NIFTI_XFORM_UNKNOWN';
                    this.data{n}.space.TransformedSpace = 'NIFTI_XFORM_UNKNOWN';
                    this.data{n}.space.MatrixData = eye(4);
                case 'faces'
                    in = 'NIFTI_INTENT_TRIANGLE';
                    dt = 'NIFTI_TYPE_INT32';
                case 'indices'
                    in = 'NIFTI_INTENT_NODE_INDEX';
                    dt = 'NIFTI_TYPE_INT32';
                case 'normals'
                    in = 'NIFTI_INTENT_VECTOR';
                    dt = 'NIFTI_TYPE_FLOAT32';
                case 'cdata'
                    in = 'NIFTI_INTENT_NONE';
                    dt = 'NIFTI_TYPE_FLOAT32';
                otherwise
                    error('This should not happen.');
            end
            this.data{n}.attributes.Intent = in;
            this.data{n}.attributes.DataType = dt;
        end

        switch subs(1).subs
            %- .private
            %--------------------------------------------------------------
            case 'private'
                this = builtin('subsasgn',this,subs(2:end),A);

            % .mat
            %--------------------------------------------------------------
            case 'mat'
                if length(subs) > 1
                    this.data{n}.space(1).MatrixData = builtin('subsasgn',...
                        this.data{n}.space(1).MatrixData,subs(2:end),A);
                else
                    if ~isequal(size(A),[4 4])
                        error('Invalid Coordinate System Transform Matrix.');
                    end
                    this.data{n}.space(1).MatrixData = A;
                end

            %- .faces
            %--------------------------------------------------------------
            case 'faces'
                if length(subs) > 1
                    this.data{n}.data = int32(builtin('subsasgn',this.data{n}.data,subs(2:end),A-1));
                else
                    this.data{n}.data = int32(A - 1);
                    this.data{n}.attributes.Dim = size(A);
                end

            %- .indices
            %--------------------------------------------------------------
            case 'indices'
                if n ~= 1
                    this.data = this.data([n setdiff(1:numel(this.data),n)]);
                    n = 1;
                end
                if length(subs) > 1
                    this.data{n}.data = int32(builtin('subsasgn',this.data{n}.data,subs(2:end),A-1));
                else
                    A = A(:);
                    this.data{n}.data = int32(A - 1);
                    this.data{n}.attributes.Dim = size(A);
                end

            %- .vertices, .normals, .cdata
            %--------------------------------------------------------------
            otherwise
                if length(subs) > 1
                    if numel(n) == 1
                        this.data{n}.data = single(builtin('subsasgn',this.data{n}.data,subs(2:end),A));
                        this.data{n}.attributes.Dim = size(this.data{n}.data);
                    else
                        if numel(subs(2).subs) == 1
                            error('Linear indexing not supported: use multiple subscripts.');
                        end
                        idx = subs(2).subs{2};
                        if isequal(idx,':'), idx = 1:numel(this.data); end
                        for k=1:numel(idx)
                            s = subs(2);
                            s.subs{2} = 1;
                            if numel(A) == 1
                                this.data{idx(k)}.data = single(builtin('subsasgn',this.data{idx(k)}.data,s,A));
                            else
                                this.data{idx(k)}.data = single(builtin('subsasgn',this.data{idx(k)}.data,s,A(:,k)));
                            end
                            this.data{idx(k)}.attributes.Dim = size(this.data{idx(k)}.data);
                        end
                    end
                else
                    if numel(n) == 1
                        if isa(A,'file_array')
                            this.data{n}.data = A;
                            this.data{n}.attributes.Dim = A.dim;
                        else
                            this.data{n}.data = single(A);
                            this.data{n}.attributes.Dim = size(A);
                        end
                    else
                        error('Syntax not implemented.');
                    end
                end
        end

    case '()'
    case '{}'
    otherwise
        error('This should not happen.');
end


function axes_handle = PTKVisualiseIn3D(axes_handle, segmentation, smoothing_size, small_structures, reporting)
    % PTKVisualiseIn3D. Opens a new Matlab figure and visualises the
    % segmentation image in 3D.
    %
    %
    %     Inputs
    %     ------
    %
    %     axes_handle - specify an empty array [] to open a new figure, or the
    %         axes_handle of the existing axes for the visualisation
    %
    %     segmentation - a binary 3D PTKImage containing 1s for the voxels to
    %         visualise
    %
    %     smoothing_size - the amount of smoothing to perform. Higher
    %         smoothing makes the image look better but removes small
    %         structures such as airways and vessels
    %
    %     small_structures - set to true for improved visualisation of
    %         narrow structures such as airways and vessels
    %
    %     reporting - an object implementing CoreReportingInterface
    %         for reporting progress and warnings
    %
    %
    %
    %     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.
    %

    if nargin < 3
        smoothing_size = 4; % A good value for lobes
    end

    if nargin < 4
        small_structures = false;
    end

    if nargin < 5
        reporting = CoreReportingDefault;
    end

    limit_to_one_component_per_index = false;
    minimum_component_volume_mm3 = 0;
    surface_colormap = CoreSystemUtilities.BackwardsCompatibilityColormap();

    axes_handle = MimVisualiseIn3D(axes_handle, segmentation, smoothing_size, small_structures, limit_to_one_component_per_index, minimum_component_volume_mm3, surface_colormap, reporting);
end


function [map2] = changeNodesArea(map, metList, areaHeight, areaWidth)
% Change the area size of a list of metabolites (standardize the map)
%
% USAGE:
%
%    [map2] = changeNodesArea(map,metList,areaHeight,areaWidth)
%
% INPUTS:
%    map:          A parsed model structure generated by
%                  'transformXML2Map' function
%    metList:      list of metabolites which area wants to be changed
%
% OPTIONAL INPUTS:
%    areaHeight:       change heigt
%    areaWidth:        change areaWidth
%
% OUTPUTS:
%    map2:          New parsed file with the changes in the reactions
%
% .. Authors:
%       - J.modamio 18/07/2017. Belval, Luxembourg, 18/07/2017.
%       - N.Sompairac - Institut Curie, Paris, 11/10/2017. (Code checking)

    if nargin < 3
        areaHeight = 25.0;
        if nargin < 4
            areaWidth = 70.0;
        end
    end

    % Rename map
    map2 = map;

    % Find mets in the map
    id = map2.specID(ismember(map2.specName, metList));
    idx = find(ismember(map2.molID, id));

    % Change areaHeight
    map2.molHeight(idx, 1) = {areaHeight};

    % Change areaWidth
    map2.molWidth(idx, 1) = {areaWidth};

end


% EEG_EPOCH2CONTINUOUS - convert epoched dataset to continuous dataset
%                          with data epochs separated by boundary events.
% Usage:
%           >> EEGOUT = eeg_epoch2continuous(EEGIN);
%
% Inputs:
%   EEGIN  - a loaded epoched EEG dataset structure.
%
% Inputs:
%   EEGOUT - a continuous EEG dataset structure.
%
% Authors: Arnaud Delorme, SCCN, INC, UCSD, January, 2012

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, October 11, 2012, arno@sccn.ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function EEG = eeg_epoch2continuous(EEG)

if nargin < 1
    help eeg_epoch2continuous;
    return;
end

EEG.data = reshape(EEG.data, size(EEG.data,1), size(EEG.data,2)*size(EEG.data,3));

eeglab_options;
for index = 1:EEG.trials-1
    EEG.event(end+1).type = eeg_boundarytype(EEG);
    EEG.event(end  ).latency  = index*EEG.pnts-0.5;
    EEG.event(end  ).duration = NaN;
end

EEG.pnts   = size(EEG.data,2);
EEG.trials = 1;
if ~isempty(EEG.event) && isfield(EEG.event, 'epoch')
    EEG.event = rmfield(EEG.event, 'epoch');
end

EEG = eeg_checkset(EEG);


function spqr_install (metis_path, tbb)
%SPQR_INSTALL compile and install SuiteSparseQR
%
% Example:
%   spqr_install                        % compiles using ../../metis-4.0, no TBB
%   spqr_install ('/my/metis')          % using non-default path to METIS
%   spqr_install ('no metis')           % do not use METIS at all
%   spqr_install ('../../metis-4.0',1)  % with METIS, and TBB multithreading
%
% SuiteSparseQR relies on CHOLMOD, AMD, and COLAMD, and can optionally use
% CCOLAMD, CAMD, and METIS as well.  By default, CCOLAMD, CAMD,
% and METIS are used.  METIS is assumed to be in the ../../metis-4.0 directory.
%
% See http://www-users.cs.umn.edu/~karypis/metis for a copy of METIS 4.0.1.
%
% You can only use spqr_install while in the SuiteSparseQR/MATLAB directory.
%
% Multithreading based on Intel Threading Building Blocks (TBB) is optionally
% used. It is not enabled by default since it conflicts with multithreading in
% the BLAS.
%
% See also spqr, spqr_solve, spqr_qmult.

%   Copyright 2008, Timothy A. Davis
%   http://www.cise.ufl.edu/research/sparse

if (nargin < 1)
    metis_path = '../../metis-4.0' ;
end

if (nargin < 2)
    tbb = 0 ;
end

% compile SuiteSparseQR and add to the path
spqr_make (metis_path, tbb) ;
spqr_path = pwd ;
addpath (spqr_path)

fprintf ('\nThe following path has been added.  You may wish to add it\n') ;
fprintf ('permanently, using the MATLAB pathtool command.\n') ;
fprintf ('%s\n', spqr_path) ;

fprintf ('\nTo try your new mexFunctions, try this command:\n') ;
fprintf ('spqr_demo\n') ;


% EEGPLOT2EVENT - convert EEGPLOT rejections into events
%                   compatible with the eeg_eegrej function for rejecting
%                   continuous portions of datasets.
%
% Usage:
%   >> [events] = eegplot2event( eegplotrej, type, colorin, colorout );
%
% Inputs:
%   eegplotrej - EEGPLOT output (TMPREJ; see eegplot for more details)
%   type       - type of the event. Default -1.
%   colorin    - only extract rejection of specific colors (here a n x 3
%                array must be given). Default: extract all rejections.
%   colorout   - do not extract rejection of specified colors.
%
% Outputs:
%   events     - array of events compatible with the eeg_eegrej function
%                for rejecting continuous portions of datasets.
%
% Example:
% NEWEEG = eeg_eegrej(EEG,eegplot2event(TMPREJ, -1));
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: EEGPLOT, EEG_MULTIEEGPLOT, EEGPLOT2TRIAL, EEGLAB

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function events = eegplot2event( TMPREJ, type, color, colorout )

if nargin < 1
   help eegplot2event;
   return;
end;

if nargin < 2
   type = -1;
end;

% only take into account specific colors
% --------------------------------------
if exist('color') == 1
	for index = 1:size(color,1)
   		tmpcol1 = TMPREJ(:,3) + 255*TMPREJ(:,4) + 255*255*TMPREJ(:,5);
   		tmpcol2 = color(index,1)+255*color(index,2)+255*255*color(index,3);
   		I = find( tmpcol1 == tmpcol2);
   		if isempty(I)
      		fprintf('Warning: color [%d %d %d] not found\n', ...
      			color(index,1), color(index,2), color(index,3));
   		end
   		TMPREJ = TMPREJ(I,:);
   	end;
end

% remove other specific colors
% ----------------------------
if exist('colorout') == 1
	for index = 1:size(colorout,1)
   		tmpcol1 = TMPREJ(:,3) + 255*TMPREJ(:,4) + 255*255*TMPREJ(:,5);
   		tmpcol2 = colorout(index,1)+255*colorout(index,2)+255*255*colorout(index,3);
   		I = find( tmpcol1 ~= tmpcol2);
   		TMPREJ = TMPREJ(I,:);
   	end;
end

events = [];
if ~isempty(TMPREJ)
   events = TMPREJ(:,1:5);
   events = [ type*ones(size(events,1), 1) ones(size(events,1), 1) round(events(:,1:2)) events(:,3:5)];
end

return;


% EEG_REREJECT - reject the same data portion as the ones defined
%                  in a reference dataset. This function is useful when
%                  have filtered a dataset and want to reject again the
%                  same portions of data.
% Usage:
%   >> OUTEEG = eeg_rereject(EEG, cleanEEG)
%
% Inputs:
%   EEG       - input dataset
%   cleanEEG  - EEGLAB dataset with portion of data rejected (information
%               stored in boundary event types).
%
% Optional inputs:
%   'blank'    - ['on'|'off'] replace by 0 instead of removing the data
%                portions. Default is 'off'. Note that this does not
%                add any boundary events.
%   'rmdiscont' - ['on'|'off'] remove discontinuities (by shifting the
%                data in the different discontinuous portions). Note that
%                this discards the boundary events.
%
% Outputs:
%   OUTEEG     - output dataset
%
% Author: Arnaud Delorme, 2020
%
% Note: uses the RESAMPLE function from the signal processing toolbox
%       if present. Otherwise use griddata interpolation method (it should be
%       reprogrammed using spline interpolation for speed up).
%
% See also: RESAMPLE, EEGLAB

% Copyright (C) 2020 Arnaud Delorme
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [EEG, boundloc]= eeg_rereject(EEG, CLEANEDEEG, varargin)

boundLat = [];
if nargin < 2
    help eeg_rereject;
    return;
end

% check inputs
% ------------
g = finputcheck(varargin, { 'blank'      'string'  {'on','off' }             'off';
                            'rmdiscont'  'string'  {'on','off' }             'off' });

if isstr(g), error(g); end

boundEvents = eeg_findboundaries(CLEANEDEEG);
boundloc = [ CLEANEDEEG.event(boundEvents).latency ];
dur      = [ CLEANEDEEG.event(boundEvents).duration ];
cumdur   = cumsum(dur);
boundloc = boundloc + [0 cumdur(1:end-1) ];
boundloc = [ boundloc; boundloc+dur-1]';
if strcmpi(g.blank, 'off')
    EEG = eeg_eegrej(EEG, ceil(boundloc));
    boundEvents = eeg_findboundaries(EEG.event);
    boundLat    = [ EEG.event(boundEvents).latency ];
else
    boundloc = round(boundloc);
    for iBound = size(boundloc,1):-1:1
        EEG.data(:,boundloc(iBound,1):boundloc(iBound,2)) = 0;
    end
    boundEvents = [];
    boundlocTmp = boundloc;
    boundlocTmp(:,1) = boundlocTmp(:,1)-1; % to compensate round(lat+0.5) below
    boundLat = sort(boundlocTmp(:))';
end

% remake data continuous
if strcmpi(g.rmdiscont, 'on')
    for ind = length(boundLat):-1:1
        if boundLat(ind) > 1
            lat = min(round(boundLat(ind)+0.5), size(EEG.data,2));
            EEG.data(:,lat:end) = EEG.data(:,lat:end) - EEG.data(:,lat) + EEG.data(:,lat-1);
            EEG.data(:,lat) = []; % remove 1 sample
            if ~isempty(boundEvents)
                for ind2 = boundEvents(ind):length(EEG.event)
                    EEG.event(ind2).latency = EEG.event(ind2).latency-1; % shift events by 1 sample
                end
            end
        end
    end
    EEG.event(boundEvents) = [];
    EEG.pnts = size(EEG.data,2);
end
EEG = eeg_checkset(EEG);


function [metrics, modelEssential] = evalGeneEssentialityPred(model, expData, metabTasks, modelEssential)
% Compare GEM-based gene essentiality predictions with experimental data
%
% Inputs:
%
%   model       Genome-scale metabolic model structure.
%
%               NOTE: The model should include boundary metabolites! These
%               can be added using the addBoundaryMets function.
%
%   expData     A two-column cell array, where the first column contains
%               gene names or IDs (of the same type as those used in the
%               model), and the second column indicates whether the gene
%               was found as essential or non-essential.
%
%               The second column can be text (e.g., 'essential', 'non') or
%               numeric (0 = non-essential, 1 = essential). For example:
%
%               {'gene1'   'essential'  }       {'gene1'   [1]}
%               {'gene2'   'non'        }       {'gene2'   [0]}
%               {'gene3'   'conditional'}       {'gene3'   [1]}
%               {...       ...          }       {...       ...}
%
%               NOTE: If essentiality is provided as strings, only genes
%               starting with "non" will be treated as non-essential. This
%               means that genes annotated as "essential" or "conditional"
%               will both be treated as essential.
%
%               NOTE: ALL genes that were tested for essentiality should be
%               included in expData. If expData contains only essential
%               genes, then it will be assumed that all genes in the genome
%               (and thus all genes in the model) were tested.
%
%   metabTasks  Either the filename or structure containing the metabolic
%               tasks that will be tested when using the model to predict
%               gene essentiality. The task structure can be loaded using
%               the RAVEN "parseTaskList" function.
%
%               Genes will be predicted as essential if their deletion
%               impairs ANY of the metabolic tasks in metabTasks. If the
%               model can perform ALL metabolic tasks upon the deletion of
%               a gene, that gene will be predicted as non-essential.
%
%   modelEssential  (Optional) A list of model-predicted essential genes.
%                   If provided, the model gene essentiality prediction
%                   will be skipped and the provided list used instead.
%
% Outputs:
%
%   metrics     A result structure with the following fields:
%                   sensitivity
%                   specificity
%                   accuracy
%                   F1 statistic
%                   Matthew's Correlation Coefficient (MCC)
%                   p-value associated with a hypergeometric test of the
%                           true and false positives and negatives
%                           (2x2 contingency table).
%
%   modelEssential   List of model-predicted essential genes.
%

if nargin < 4
    modelEssential = [];
end

%% Pre-process expData

% extract information from expData and convert essentiality to 0, 1
ex.genes = expData(:,1);
if length(ex.genes) > length(unique(ex.genes))
    error('Gene names or IDs in expData are not unique. Duplicated entries must be removed.');
end
if isnumeric(expData{1,2})
    ex.essentiality = double(cell2mat(expData(:,2)));
else
    ex.essentiality = double(~startsWith(lower(expData(:,2)), 'non'));
end

% check that gene IDs/names in the model are the same type as in expData
if sum(ismember(ex.genes, model.genes)) < 3
    error('The gene name or ID type in expData seem to differ from those used in the model.');
end

% define essential and non-essential gene lists
ex.essential = ex.genes(ex.essentiality == 1);
if all(ex.essentiality == 1)
    fprintf('NOTE: All genes in expData are marked as essential; it will therefore be assumed that all genes in the genome were tested.\n\n');
    ex.nonessential = setdiff(model.genes, ex.essential);
    ex.genes = [ex.genes; ex.nonessential];
else
    ex.nonessential = ex.genes(ex.essentiality == 0);
end

%% Run gene essentiality predictions with the model

if isempty(modelEssential)

    if ischar(metabTasks)
        taskStruct = parseTaskList(metabTasks);
    else
        taskStruct = metabTasks;
    end

    % first confirm that the model can perform all the tasks
    taskReport = checkTasks(model,[],false,false,false,taskStruct);
    if ~all(taskReport.ok)
        fprintf('\nThe provided model could not perform the following tasks:\n');
        fprintf('\t> %s\n', taskReport.description{~taskReport.ok});
        fprintf('\n');
        error('Model failed task(s) before gene deletion!');
    end

    % get essential genes for each task in taskStruct
    [~,essentialGeneMat] = checkTasksGenes(model,[],false,false,true,taskStruct);

    % essential genes are counted as those that are essential for ANY task
    essentialGeneVect = any(essentialGeneMat > 0, 2);
    pred.essential = model.genes(essentialGeneVect);
    pred.nonessential = setdiff(model.genes, pred.essential);

else
    pred.essential = modelEssential;
    pred.nonessential = setdiff(model.genes, modelEssential);
end

%% Evaluate prediction performance

TP = sum(ismember(pred.essential, ex.essential));        % true positives
TN = sum(ismember(pred.nonessential, ex.nonessential));  % true negatives
FP = sum(ismember(pred.essential, ex.nonessential));     % false positives
FN = sum(ismember(pred.nonessential, ex.essential));     % false negatives

% calculate some metrics
sensitivity = TP./(TP + FN);
specificity = TN./(TN + FP);
accuracy = (TP + TN)./(TP + TN + FP + FN);
F1 = 2*TP./(2*TP + FP + FN);
MCC = ((TP.*TN) - (FP.*FN))./sqrt((TP+FP).*(TP+FN).*(TN+FP).*(TN+FN));
[~, p_hyper] = fishertest([TP, FP; FN, TN], 'tail', 'right');

% combine metrics into output structure
metrics.sensitivity = sensitivity;
metrics.specificity = specificity;
metrics.accuracy = accuracy;
metrics.F1 = F1;
metrics.MCC = MCC;
metrics.p_hyper = p_hyper;

% assign output
modelEssential = pred.essential;

end


classdef TestTickMeter
    %TestTickMeter

    methods (Static)
        function test_1
            tm = cv.TickMeter();
            tm.reset();
            tm.start();
            pause(0.1);
            tm.stop();
            validateattributes(tm.TimeTicks, {'int64'}, {'scalar'});
            validateattributes(tm.TimeMicro, {'double'}, {'scalar'});
            validateattributes(tm.TimeMilli, {'double'}, {'scalar'});
            validateattributes(tm.TimeSec, {'double'}, {'scalar'});
            validateattributes(tm.Counter, {'int64'}, {'scalar'});
            %assert(abs(tm.TimeSec - 0.1) < 0.02);
        end

        function test_2
            t1 = cv.TickMeter.getTickCount();
            pause(0.1);
            t2 = cv.TickMeter.getTickCount();
            f = cv.TickMeter.getTickFrequency();
            tsec = double(t2 - t1) / f;
            validateattributes(t1, {'int64'}, {'scalar'});
            validateattributes(t2, {'int64'}, {'scalar'});
            validateattributes(f, {'double'}, {'scalar'});
            %assert(abs(tsec - 0.1) < 0.02);
        end
    end

end


function S = spm_cfg_eeg_montage
% configuration file for reading montage files
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Stefan Kiebel
% $Id: spm_cfg_eeg_montage.m 6983 2017-01-06 17:25:22Z vladimir $

D = cfg_files;
D.tag = 'D';
D.name = 'File Name';
D.filter = 'mat';
D.num = [1 1];
D.help = {'Select the EEG mat file.'};

montagefile = cfg_files;
montagefile.tag = 'montagefile';
montagefile.name = 'Montage file name';
montagefile.filter = 'mat';
montagefile.num = [1 1];
montagefile.help = {'Select a montage file.'};

keepothers = cfg_menu;
keepothers.tag = 'keepothers';
keepothers.name = 'Keep other channels';
keepothers.labels = {'Yes', 'No'};
keepothers.values = {1, 0};
keepothers.val = {0};
keepothers.help = {'Specify whether you want to keep channels that are not contributing to the new channels'};

montage = cfg_branch;
montage.tag = 'montage';
montage.name = 'Load montage from file';
montage.val = {montagefile, keepothers};

montagename         = cfg_entry;
montagename.tag     = 'montagename';
montagename.name    = 'Montage name';
montagename.help    = {'Specify the name of existing montage'};
montagename.strtype = 's';
montagename.num     = [1 Inf];

montagenum         = cfg_entry;
montagenum.tag     = 'montagenum';
montagenum.name    = 'Montage index';
montagenum.help    = {'Specify the index of existing montage'};
montagenum.strtype = 'w';
montagenum.num     = [1 1];

montspec = cfg_choice;
montspec.tag = 'montspec';
montspec.name = 'Montage specification';
montspec.values = {montage, montagename, montagenum};
montspec.val = {montage};
montspec.help = {'Choose how to specify the montage'};

blocksize = cfg_entry;
blocksize.tag = 'blocksize';
blocksize.name = 'Block size';
blocksize.strtype = 'r';
blocksize.val = {655360};
blocksize.num = [1 1];
blocksize.help = {'size of blocks used internally to split large files default ~20Mb'};

prefix         = cfg_entry;
prefix.tag     = 'prefix';
prefix.name    = 'Filename Prefix';
prefix.help    = {'Specify the string to be prepended to the filenames of the montaged ',...
    'dataset (if generated). Default prefix is ''M''.'};
prefix.strtype = 's';
prefix.num     = [1 Inf];
prefix.val     = {'M'};

write = cfg_branch;
write.tag = 'write';
write.name = 'Write';
write.val = {montspec, blocksize, prefix};
write.help = {'Apply montage and write out to a new dataset.'};

online = cfg_branch;
online.tag = 'switch';
online.name = 'Switch';
online.val = {montspec};
online.help = {'Switch to new online montage without writing out a new file'};

add = cfg_branch;
add.tag = 'add';
add.name = 'Add';
add.val = {montage};
add.help = {'Add montage to the set of online montages without applying'};

clr = cfg_const;
clr.tag = 'clear';
clr.name = 'Clear';
clr.val  = {1};
clr.help = {'Clear all online montages and revert to the original state.'};

mode = cfg_choice;
mode.tag = 'mode';
mode.name = 'Mode';
mode.values = {write, online, add, clr};
mode.val = {write};
mode.help = {'Choose between writing a new dataset or online montage operation'};

S = cfg_exbranch;
S.tag = 'montage';
S.name = 'Montage';
S.val = {D, mode};
S.help = {'Apply a montage (linear transformation) to EEG/MEG data.'};
S.prog = @eeg_montage;
S.vout = @vout_eeg_montage;
S.modality = {'EEG'};

function out = eeg_montage(job)
% construct the S struct
S.D = job.D{1};
S.mode = char(fieldnames(job.mode));
switch S.mode
    case 'write'
        S.blocksize = job.mode.write.blocksize;
        S.prefix = job.mode.write.prefix;
        switch char(fieldnames(job.mode.write.montspec))
            case 'montagename'
                S.montage = job.mode.write.montspec.montagename;
            case 'montagenum'
                S.montage = job.mode.write.montspec.montagenum;
            case 'montage'
                S.montage = char(job.mode.write.montspec.montage.montagefile);
                S.keepothers = job.mode.write.montspec.montage.keepothers;
        end
    case 'switch'
        switch char(fieldnames(job.mode.switch.montspec))
            case 'montagename'
                S.montage = job.mode.switch.montspec.montagename;
            case 'montagenum'
                S.montage = job.mode.switch.montspec.montagenum;
            case 'montage'
                S.montage = char(job.mode.switch.montspec.montage.montagefile);
                S.keepothers = job.mode.switch.montspec.montage.keepothers;
        end
    case 'add'
        S.montage = char(job.mode.add.montage.montagefile);
        S.keepothers = job.mode.add.montage.keepothers;
end
out.D = spm_eeg_montage(S);
out.Dfname = {fullfile(out.D.path, out.D.fname)};

function dep = vout_eeg_montage(job)
% Output is always in field "D", no matter how job is structured
dep = cfg_dep;
dep.sname = 'Montaged data';
% reference field "D" from output
dep.src_output = substruct('.','D');
% this can be entered into any evaluated input
dep.tgt_spec   = cfg_findspec({{'strtype','e'}});

dep(2) = cfg_dep;
dep(2).sname = 'Montaged Datafile';
% reference field "Dfname" from output
dep(2).src_output = substruct('.','Dfname');
% this can be entered into any file selector
dep(2).tgt_spec   = cfg_findspec({{'filter','mat'}});


%% sub2indn
% Below is a demonstration of the features of the |sub2indn| function

%%
clear; close all; clc;

%% Syntax
% |ind = sub2indn(varargin);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program 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.
%
% This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.


function d=ddiff(d1,d2), d=max(d1,-d2);

%   Copyright (C) 2004-2006 Per-Olof Persson. See COPYRIGHT.TXT for details.


function e = end(X,k,n)
%END Last index of indexing expression for sparse tensor.
%
%   The expression X(end,:,:) will call END(X,1,3) to determine
%   the value of the first index.
%
%   See also SPTENSOR, SPTENSOR/SUBSREF, END.
%
%MATLAB Tensor Toolbox.
%Copyright 2015, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2015) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

if n > ndims(X)
  error('Subscript out of range.');
end
e = X.size(k);


% PRIMPORT import the old-format prtools datasets
%
%   OUT = PRIMPORT(A)
%
% INPUT
%    A     The Structure to be converted.
%
% OUTPUT
%    OUT   The imported dataset
%
% DESCRIPTION
% This routine converts old prtools datasets into the new prtools 4.x
% format. Structure A is tested for existence of all the fields forming
% particular dataset format. Prtools 3.x and 4.x formats are supported.
%
% SEE ALSO (PRTools Guide)
% DATASET

% $Id: primport.m,v 1.4 2007/08/24 13:49:59 davidt Exp $

function out = primport(a)

	% we try to convert only structures
	if isstruct(a)

		% prtools 3.x format
		if isfield(struct(a),'d') & isfield(struct(a),'l') & ...
			    isfield(struct(a),'p') & isfield(struct(a),'f') & ...
			    isfield(struct(a),'ll') & isfield(struct(a),'c') & ...
			    isfield(struct(a), 's')

			prwarning(2,'prtools 3.x dataset converted to 4.x');

			% lab list could be a cell-array
			if iscell(a.ll)
				lablist=a.ll{1};
				nlab=a.l;
			else
				[nlab,lablist] = renumlab(a.l);
			end

			out = prdataset(a.d,nlab,'featlab',a.f,'prior',a.p,'lablist',lablist);

			if a.c<0
				% objects are pixels
				xx=-a.c;
				yy=size(a.d,1)/xx;
				out.objsize=[xx yy];
			end
			if a.c>0
				% objects are pictures
				xx=a.c;
				yy=size(a.d,2)/xx;
				out.featsize=[xx yy];
			end

		% prtools 4 format
		elseif isfield(struct(a),'data') & isfield(struct(a),'lablist') & ...
			    isfield(struct(a),'nlab') & isfield(struct(a),'labtype') & ...
			    isfield(struct(a),'targets') & isfield(struct(a), 'featlab') & ...
			    isfield(struct(a),'prior') & ...
			    isfield(struct(a),'objsize') & isfield(struct(a),'featsize') & ...
			    isfield(struct(a),'ident') & isfield(struct(a),'version') & ...
			    isfield(struct(a),'name') & isfield(struct(a),'user')

			%DXD: The previous line was commented out
			%     Uncommenting made it work:
			% out = prdataset(a.data,a.nlab,'lablist',a.lablist);
			out = prdataset(a.data);
			if ~isempty(a.nlab), out.nlab=a.nlab; end
			if ~isempty(a.lablist), out.lablist=a.lablist; end
			if ~isempty(a.labtype), out.labtype=a.labtype; end
			if ~isempty(a.targets), out.targets=a.targets; end
			if ~isempty(a.featlab), out.featlab=a.featlab; end
			if ~isempty(a.prior), out.prior=a.prior; end
			if ~isempty(a.objsize), out.objsize=a.objsize; end
			if ~isempty(a.featsize), out.featsize=a.featsize; end
			if ~isempty(a.ident), out.ident=a.ident; end
			if ~isempty(a.version), out.version=a.version; end
			if ~isempty(a.name), out.name=a.name; end
			if ~isempty(a.user), out.user=a.user; end

			% later, the featdom field was included
			if isfield(struct(a),'featdom') & ~isempty(a.featdom)
				out.featdom = a.featdom;
			end

			% later, the cost field was included
			if isfield(struct(a),'cost') & ~isempty(a.cost)
				out.cost = a.cost;
			end

			prwarning(2,'prtools 4.x converted from structure');

		else
			out = [];
			prwarning(2,'unknown format! The structure cannot be converted into a dataset');
		end

	else % anything else then structure: just copy to the output
		out=a;
	end


function showScale(hAxis, i)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

global stateS
global planC

% check for comparemode if selected
compareMode = getappdata(hAxis,'compareMode');

pos = get(hAxis, 'position');
wid = pos(3); hgt = pos(4);

[scanSet, doseSet, viewType, coord] = getAxisInfo(uint8(i), 'scanSets', 'doseSets', 'view', 'coord');

scanText = ['S: ' sprintf('%d',scanSet)];
doseText = ['D: ' sprintf('%d',doseSet)];

if isempty(coord)
    set(stateS.handle.CERRAxisLabel1(i), 'string', '', 'visible', 'on', 'color', [0 0 0], 'hittest', 'off');
    set(stateS.handle.CERRAxisLabel2(i), 'string', '', 'visible', 'on', 'color', [0 0 0], 'hittest', 'off');
    return;
end

if ~isempty(scanSet)
    indexS = planC{end};
    [xV, yV, zV] = getScanXYZVals(planC{indexS.scan}(scanSet(1)));
else
    %warning('No Scan Selected')
    return
end

if stateS.currentAxis == i;
    color = [0.5 1 0.5];
else
    color = [0.9 0.9 0.5];
end
if stateS.contourAxis == i
    color = [1 0 0];
end
%try
    transM = getTransM('scan', scanSet(1), planC);
%catch
    %transM = [];
%end
if ~isempty(transM) || isequal(transM,eye(4))
    [nCoordX nCoordY nCoordZ] = applyTransM(inv(transM),coord,coord,coord);

else
    nCoordX = coord;
    nCoordY = coord;
    nCoordZ = coord;
end

switch viewType
    case 'transverse'
        viewTxt        = 'Tra: '; dim1 = 'z: '; dim2 = '\Deltax:'; dim3 = '\Deltay:';
        if isempty(zV)
            numSlices = []; zVal = [];
        else
            sliceNum    = findnearest(zV, nCoordZ);
            numSlices   = sprintf('%d',size(getScanArray(planC{indexS.scan}(scanSet(1))), 3));
            %xLim        = get(hAxis, 'xLim');
            %deltaX      = num2str(xLim(2) - xLim(1), '%0.4g');
            %yLim        = get(hAxis, 'yLim');
            %deltaY      = num2str(yLim(2) - yLim(1), '%0.4g');
            zVal        = sprintf('%.2f',coord);
            stateS.transverse.ZCoord = str2double(zVal);
%             %Show 5cm bar to display zoom-level
%             len = 5; %cm
%             dx = xLim(2)-xLim(1);
%             xStart = xLim(1) + dx * 0.05;
%             xEnd = xStart + len;
%             dy = yLim(2)-yLim(1);
%             yStart = yLim(1) + dy * 0.05;
%             yEnd = yStart + len;
%             %Delete previous handles
% %             hScale = findobj(hAxis,'tag','scale');
% %             delete(hScale)
% %             line([xStart xEnd], [yStart yStart], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %             line([xStart xStart], [yStart yEnd], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
%             xAll = linspace(xStart,xEnd,6);
%             yAll = linspace(yStart,yEnd,6);
% %             if wid/dx < 6 || hgt/dy < 6
% %                 line([xAll(6) xAll(6)], [yStart-dy*0.005 yStart+dy*0.005], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                 line([xStart-dx*0.005 xStart+dx*0.005], [yAll(6) yAll(6)], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                 text('parent', hAxis, 'string', '5', 'position', [xAll(6) yStart-dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                 text('parent', hAxis, 'string', '5', 'position', [xStart-dx*0.02 yAll(6) 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %             else
% %                 for iS = 2:length(xAll)
% %                     line([xAll(iS) xAll(iS)], [yStart-dy*0.005 yStart+dy*0.005], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                     line([xStart-dx*0.005 xStart+dx*0.005], [yAll(iS) yAll(iS)], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                     text('parent', hAxis, 'string', num2str(iS-1), 'position', [xAll(iS) yStart-dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                     text('parent', hAxis, 'string', num2str(iS-1), 'position', [xStart-dx*0.02 yAll(iS) 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                 end
% %             end
%             %text('parent', hAxis, 'string', 'cm', 'position', [xStart-dx*0.02 yStart-dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale','rotation',0);
        end

    case 'sagittal'
        viewTxt        = 'Sag: ';  dim1 = 'x: '; dim2 = '\Deltay:'; dim3 = '\Deltaz:';
        if isempty(xV)
            numSlices = []; zVal = [];
        else
            sliceNum    = findnearest(xV, nCoordX);
            numSlices   = sprintf('%d',size(getScanArray(planC{indexS.scan}(scanSet(1))), 2));
            %xLim        = get(hAxis, 'xLim');
            %deltaX      = num2str(xLim(2) - xLim(1), '%0.4g');
            %yLim        = get(hAxis, 'yLim');
            %deltaY      = num2str(yLim(2) - yLim(1), '%0.4g');
            zVal        = sprintf('%.2f',coord);
            stateS.sagittal.ZCoord = str2double(zVal);
%             %Show 5cm bar to display zoom-level
%             len = 5; %cm
%             dx = xLim(2)-xLim(1);
%             xStart = xLim(2) - dx * 0.05;
%             xEnd = xStart - len;
%             dy = yLim(2)-yLim(1);
%             yStart = yLim(2) - dy * 0.05;
%             yEnd = yStart - len;
%             %Delete previous handles
% %             hScale = findobj(hAxis,'tag','scale');
% %             delete(hScale)
% %             line([xStart xEnd], [yStart yStart], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %             line([xStart xStart], [yStart yEnd], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
%             xAll = linspace(xStart,xEnd,6);
%             yAll = linspace(yStart,yEnd,6);
% %             if wid/dx < 6 || hgt/dy < 6
% %                 line([xAll(6) xAll(6)], [yStart-dy*0.005 yStart+dy*0.005], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                 line([xStart-dx*0.005 xStart+dx*0.005], [yAll(6) yAll(6)], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                 text('parent', hAxis, 'string', '5', 'position', [xAll(6) yStart+dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                 text('parent', hAxis, 'string', '5', 'position', [xStart+dx*0.02 yAll(6) 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %             else
% %                 for iS = 2:length(xAll)
% %                     line([xAll(iS) xAll(iS)], [yStart-dy*0.005 yStart+dy*0.005], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                     line([xStart-dx*0.005 xStart+dx*0.005], [yAll(iS) yAll(iS)], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                     text('parent', hAxis, 'string', num2str(iS-1), 'position', [xAll(iS) yStart+dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                     text('parent', hAxis, 'string', num2str(iS-1), 'position', [xStart+dx*0.02 yAll(iS) 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                 end
% %             end
%             %text('parent', hAxis, 'string', 'cm', 'position', [xStart+dx*0.02 yStart+dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale','rotation',0);
        end

    case 'coronal'
        viewTxt        = 'Cor: ';  dim1 = 'y: '; dim2 = '\Deltax:'; dim3 = '\Deltaz:';
        if isempty(yV)
            numSlices = []; zVal = [];
        else
            sliceNum    = findnearest(yV, nCoordY);
            numSlices   = sprintf('%d',size(getScanArray(planC{indexS.scan}(scanSet(1))), 1));
            %xLim        = get(hAxis, 'xLim');
            %deltaX      = num2str(xLim(2) - xLim(1), '%0.4g');
            %yLim        = get(hAxis, 'yLim');
            %deltaY      = num2str(yLim(2) - yLim(1), '%0.4g');
            zVal        = sprintf('%.2f',coord);
            stateS.coronal.ZCoord = str2double(zVal);
%             %Show 5cm bar to display zoom-level
%             len = 5; %cm
%             dx = xLim(2)-xLim(1);
%             xStart = xLim(1) + dx * 0.05;
%             xEnd = xStart + len;
%             dy = yLim(2)-yLim(1);
%             yStart = yLim(2) - dy * 0.05;
%             yEnd = yStart - len;
%             %Delete previous handles
% %             hScale = findobj(hAxis,'tag','scale');
% %             delete(hScale)
% %             line([xStart xEnd], [yStart yStart], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %             line([xStart xStart], [yStart yEnd], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
%             xAll = linspace(xStart,xEnd,6);
%             yAll = linspace(yStart,yEnd,6);
% %             if wid/dx < 6 || hgt/dy < 6
% %                 line([xAll(6) xAll(6)], [yStart-dy*0.005 yStart+dy*0.005], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                 line([xStart-dx*0.005 xStart+dx*0.005], [yAll(6) yAll(6)], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                 text('parent', hAxis, 'string', '5', 'position', [xAll(6) yStart+dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                 text('parent', hAxis, 'string', '5', 'position', [xStart-dx*0.02 yAll(6) 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %             else
% %                 for iS = 2:length(xAll)
% %                     line([xAll(iS) xAll(iS)], [yStart-dy*0.005 yStart+dy*0.005], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                     line([xStart-dx*0.005 xStart+dx*0.005], [yAll(iS) yAll(iS)], [2 2], 'parent', hAxis, 'color', 'y', 'tag', 'scale', 'hittest', 'off');
% %                     text('parent', hAxis, 'string', num2str(iS-1), 'position', [xAll(iS) yStart+dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                     text('parent', hAxis, 'string', num2str(iS-1), 'position', [xStart-dx*0.02 yAll(iS) 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale');
% %                 end
% %             end
%             %text('parent', hAxis, 'string', 'cm', 'position', [xStart-dx*0.02 yStart+dy*0.02 0], 'color', 'y', 'units', 'data', 'visible', 'on','fontSize',8, 'tag', 'scale','rotation',0);
        end

    case 'legend'
        set(stateS.handle.CERRAxisLabel1(i), 'string', 'Legend', 'visible', 'on', 'color', color, 'hittest', 'off','position',[0.02 0.98 0]);
        return;
    otherwise
        return;
end

% APA commented for RIVIEW - begin

% set(stateS.handle.CERRAxisScale1(i),'xData',[xStart xEnd], 'yData', [yStart yStart],'visible','on')
% set(stateS.handle.CERRAxisScale2(i),'xData',[xStart xStart], 'yData', [yStart yEnd],'visible','on')

% set(stateS.handle.CERRAxisLabel3(i),'position',[xEnd yStart+dy*0.02 0],'visible','on');
% set(stateS.handle.CERRAxisLabel4(i),'position',[xStart-dx*0.02 yEnd 0],'visible','on');
% for j = 1:size(stateS.handle.CERRAxisTicks1,2)
%     set(stateS.handle.CERRAxisTicks1(i,j),'xData',[xAll(j) xAll(j)], 'yData', [yStart-dy*0.0025 yStart+dy*0.0025],'visible','on')
%     set(stateS.handle.CERRAxisTicks2(i,j),'xData',[xStart-dx*0.0025 xStart+dx*0.0025], 'yData', [yAll(j) yAll(j)],'visible','on')
% end

if wid < 100 || hgt < 100
    set(stateS.handle.CERRAxisLabel1(i), 'string', [viewTxt '        ' compareMode], 'visible', 'on', 'color', color, 'hittest', 'off','position',[0.02 0.98 0]);
    set(stateS.handle.CERRAxisLabel2(i),'string','');
else
    viewTxt = [viewTxt sprintf('%d',sliceNum) '/' numSlices '          ' compareMode];
    %         set(stateS.handle.CERRAxisLabel(i), 'string', {[viewTxt num2str(sliceNum) '/' numSlices], [dim1 zVal 'cm'], [dim2 deltaX 'cm'], [dim3 deltaY 'cm']}, 'visible', 'on', 'erasemode', 'none', 'color', color, 'hittest', 'off');
    set(stateS.handle.CERRAxisLabel1(i), 'string', {viewTxt, [dim1 zVal 'cm']}, 'visible', 'on', 'color', color, 'hittest', 'off','position',[0.02 0.98 0]);

    set(stateS.handle.CERRAxisLabel2(i), 'string', {scanText, doseText}, 'visible', 'on', 'color', color, 'hittest', 'off');
end

% kids = get(hAxis, 'children');
% index1 = find(kids == stateS.handle.CERRAxisLabel1(i));
% kids(index1) = [];
% index2 = find(kids == stateS.handle.CERRAxisLabel2(i));
% kids(index2) = [];
% index3 = ismember(kids, findobj(hAxis,'tag', 'scale'));
% kids(index3) = [];
% set(hAxis, 'children', [findobj(hAxis,'tag', 'scale');stateS.handle.CERRAxisLabel1(i);stateS.handle.CERRAxisLabel2(i);kids]);

% %%%%%% APA commented to test whether this is needed?
% kids = get(hAxis, 'children');
% index1 = kids == stateS.handle.CERRAxisLabel1(i);
% %kids(index1) = [];
% index2 = kids == stateS.handle.CERRAxisLabel2(i);
% %kids(index2) = [];
% %scaleKids = findobj(hAxis,'tag', 'scale');
% %index3 = ismember(kids, scaleKids);
% %kids(index3) = [];
% index3 = kids == stateS.handle.CERRAxisLabel3(i);
% index4 = kids == stateS.handle.CERRAxisLabel4(i);
% index5 = kids == stateS.handle.CERRAxisScale1(i);
% index6 = kids == stateS.handle.CERRAxisScale2(i);
% % index7 = ismember(kids, stateS.handle.CERRAxisTicks1(i,:));
% % index8 = ismember(kids, stateS.handle.CERRAxisTicks2(i,:));
% index7 = zeros(length(kids),1);
% index8 = index7;
% for j = 1:size(stateS.handle.CERRAxisTicks1,2)
%     index7 = index7 | kids == stateS.handle.CERRAxisTicks1(i,j);
%     index8 = index8 | kids == stateS.handle.CERRAxisTicks2(i,j);
% end
%
% reOrderedKids = kids;
% index = index1 | index2 | index3 | index4 | index5 | index6 | index7 | index8;
% reOrderedKids(index) = [stateS.handle.CERRAxisLabel1(i) stateS.handle.CERRAxisLabel2(i) stateS.handle.CERRAxisLabel3(i) stateS.handle.CERRAxisLabel4(i) stateS.handle.CERRAxisScale1(i) stateS.handle.CERRAxisScale2(i) stateS.handle.CERRAxisTicks1(i,:) stateS.handle.CERRAxisTicks2(i,:)];
% numFilled = sum(index);
% reOrderedKids(numFilled+1:end) = kids(~index);
%
% %%%%%% APA commented to test whether this is needed? ends

%set(hAxis, 'children', reOrderedKids);

% APA commented for RIVIEW - end


%% polyLineIntersect
% Below is a demonstration of the features of the |polyLineIntersect| function

%%
clear; close all; clc;

%% Syntax
% |[Vn]=polyLineIntersect(varargin);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program 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.
%
% This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.


function scanStruct = setScanXYZVals(scanStruct, xVals, yVals, zVals);
%"setScanXYZVals"
%   Sets the x, y, and z values of the cols, rows, and slices of the
%   passed scanStruct.
%
%   xVals must be EVENLY spaced and INCREASING.
%   yVals must be EVENLY spaced and DECREASING.
%   zVals must be simply INCREASING.
%
%   By JRA 1/26/05
%
%   scanStruct        : a planC{indexS.scan} struct.
%   xVals yVals zVals : new x,y,z values for scan.
%
% Usage:
%   function scanStruct = setScanXYZVals(scanStruct, xVals, yVals, zVals);
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

scanSize = size(getScanArray(scanStruct));
if length(xVals) ~= scanSize(2)
    error('Invalid number of xVals, must have the same number as columns in scanArray.');
end
if length(yVals) ~= scanSize(1)
    error('Invalid number of yVals, must have the same number as rows in scanArray.');
end
if length(zVals) ~= scanSize(3)
    error('Invalid number of zVals, must have the same number as slices in scanArray.');
end

sizeDim1 = scanSize(1);
sizeDim2 = scanSize(2);
sizeDim3 = scanSize(3);

grid2Units = xVals(2) - xVals(1);
grid1Units = -(yVals(2) - yVals(1));

for i=1:scanSize(3)
    scanStruct.scanInfo(i).grid1Units = grid1Units;
    scanStruct.scanInfo(i).grid2Units = grid2Units;
    scanStruct.scanInfo(i).sizeOfDimension1 = sizeDim1;
    scanStruct.scanInfo(i).sizeOfDimension2 = sizeDim2;
    scanStruct.scanInfo(i).zValue = zVals(i);
    scanStruct.scanInfo(i).xOffset = mean(xVals);
    scanStruct.scanInfo(i).yOffset = mean(yVals);
end

scanStruct.uniformScanInfo.grid1Units = grid1Units;
scanStruct.uniformScanInfo.grid2Units = grid2Units;
scanStruct.uniformScanInfo.sizeOfDimension1 = sizeDim1;
scanStruct.uniformScanInfo.sizeOfDimension2 = sizeDim2;
scanStruct.uniformScanInfo.zValue = zVals(i);
scanStruct.uniformScanInfo.xOffset = mean(xVals);
scanStruct.uniformScanInfo.yOffset = mean(yVals);
scanStruct.uniformScanInfo.firstZValue = scanStruct.scanInfo(1).zValue;


function data = boxesData( varargin )
% Get ground truth data for object proposal bounding box evaluation.
%
% Used to get dataset information for evaluation of bounding box object
% proposals using boxesEval.m. This requires separate download of the
% appropriate dataset first. Currently only set up for PASCAL VOC 2007 but
% it would be fairly simple to extend to other datasets.
%
% As a first step, it is necessary to download the PASCAL VOC 2007 dataset.
% Go to http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2007/ and get:
%  VOCdevkit_08-Jun-2007, VOCtrainval_06-Nov-2007, VOCtest_06-Nov-2007
% After downloading these files extract them to dataDir='boxes/VOCdevkit'.
% Once complete this function will process the data and return information
% in a convenient format for boxesEval.m.
%
% USAGE
%  data = boxesData( opts )
%
% INPUTS
%  opts       - parameters (struct or name/value pairs)
%   .resDir     - ['boxes/'] location for results and evaluation
%   .dataDir    - ['boxes/VOCdevkit/'] dir containing PASCAL VOC 2007
%   .split      - ['val'] data split for evaluation
%
% OUTPUTS
%  data       - dataset split information
%   .split      - data split for evaluation
%   .n          - number of images
%   .ids        - list of string ids
%   .imgs       - list of image filenames
%   .gt         - ground truth for each image
%
% EXAMPLE
%
% See also edgeBoxesDemo, edgeBoxes, boxesEval
%
% Structured Edge Detection Toolbox      Version 3.01
% Code written by Piotr Dollar and Larry Zitnick, 2014.
% Licensed under the MSR-LA Full Rights License [see license.txt]

% get default parameters (unimportant parameters are undocumented)
dfs={ 'resDir','boxes/', 'dataDir','boxes/VOCdevkit/', 'split','val' };
o=getPrmDflt(varargin,dfs,1);

% locations of PASCAL VOC dataset
if(~exist(o.dataDir,'dir')), error('dataset not found, see help'); end
imDir=[o.dataDir 'VOC2007/JPEGImages/'];
gtDir=[o.dataDir 'VOC2007/Annotations/'];
imList=[o.dataDir 'VOC2007/ImageSets/Main/' o.split '.txt'];
addpath(genpath([o.dataDir 'VOCcode']));

% check if data already exists, if yes load and return
dataNm=[o.resDir '/GroundTruth' '-' o.split '.mat'];
if(exist(dataNm,'file')), data=load(dataNm); data=data.data; return; end

% get list of image ids
if(~exist(imList,'file')), error('ids file not found'); end
f=fopen(imList); ids=textscan(f,'%s %*s'); ids=ids{1}; fclose(f);

% generate list of image and gt filenames then load gt
n=length(ids); imgs=cell(n,1); gt=cell(n,1);
for i=1:n, imgs{i}=[imDir ids{i} '.jpg']; end
for i=1:n, gt{i}=[gtDir ids{i} '.xml']; end
if(~exist(imgs{1},'file')), error('images not found'); end
if(~exist(gt{1},'file')), error('annotations not found'); end
parfor i=1:n, [~,gt{i}]=bbGt('bbLoad',gt{i},'format',1); end

% create output structure and cache to disk
data=struct('split',o.split,'n',n,'ids',{ids},'imgs',{imgs},'gt',{gt});
if(~exist(o.resDir,'dir')), mkdir(resDir); end; save(dataNm,'data');

end


function rtk=uddcb_ppp(rtk)

VAR_DCB=30^2;
idx=rtk.id+1;

if rtk.x(idx)==0
    rtk=initx(rtk,1e-6,VAR_DCB,idx);
end

return


% ------------------------------------------------------------------------
%  Copyright (C)
%  Universitat Politecnica de Catalunya BarcelonaTech (UPC) - Spain
%  University of California Berkeley (UCB) - USA
%
%  Jordi Pont-Tuset <jordi.pont@upc.edu>
%  Pablo Arbelaez <arbelaez@berkeley.edu>
%  June 2014
% ------------------------------------------------------------------------
% This file is part of the MCG package presented in:
%    Arbelaez P, Pont-Tuset J, Barron J, Marques F, Malik J,
%    "Multiscale Combinatorial Grouping,"
%    Computer Vision and Pattern Recognition (CVPR) 2014.
% Please consider citing the paper if you use this code.
% ------------------------------------------------------------------------
%
% Create random divisions of the training set for cross-validation
%
% ------------------------------------------------------------------------

% Create random divisions of the training set
id = '3';
percentage_train = 0.5;
full_set = 'train2012';

% Get full ids
im_ids = database_ids('pascal2012',full_set);

ids_a = sort(randperm(length(im_ids),floor(percentage_train*length(im_ids))));
ids_b = setdiff(1:length(im_ids),ids_a);
im_ids_a = im_ids(ids_a);
im_ids_b = im_ids(ids_b);

% Write to file
file_a = fullfile(root_dir,'datasets', 'pascal2012','gt_sets',[full_set '_' id 'a.txt']);
file_b = fullfile(root_dir,'datasets', 'pascal2012','gt_sets',[full_set '_' id 'b.txt']);

dlmwrite(file_a,im_ids_a,'')
dlmwrite(file_b,im_ids_b,'')


function varargout = text2( varargin )
% Wrapper for text.m that ensures displayed text fits in figure.
%
% When text is called, Matlab displays the text, but does nothing to ensure
% that all of the text fits in the figure.  This function, after calling
% text, shrinks the axes until the text is fully visible.  Note that since
% font doesn't resize as the figure does, just because the text fully fits
% after text2 is called, no guaranties are made after the figure is
% resized.  Hence it is a good idea to resize the figure appropriately
% before calling text2.
%
% Same input/output options as Matlab's text.m command.
%
% USAGE
%  varargout = text2( varargin )
%
% INPUTS
%  varargin   - input to Matlab's text
%
% OUTPUTS
%  varargout  - output to Matlab's text
%
% EXAMPLE
%  figure(1); clf; text( -1 , 2, 'hello world' )  % will not appear
%  figure(2); clf; text2( -1 , 2, 'hello world' ) % will appear
%
% See also TEXT, IMLABEL
%
% Piotr's Image&Video Toolbox      Version 2.0
% Copyright 2012 Piotr Dollar.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see external/bsd.txt]

%%% call text normally
hs = text( varargin{:} );
if(nargout>=1); varargout={hs}; end;

%%% now make sure text fits
%%% update the OuterPosition (not regular Position) so good resize behavior
nhs = length(hs);
for i=1:nhs;  set(hs(i),'Units','Normalized');  end;
oldunits = get(gca,'Units'); set(gca,'Units','Normalized');
opos = get(gca,'OuterPosition'); %x y w h
updated = 1; updatedpos=1;
while( updated ); updated=0;
  for p=1:4
    if( updatedpos ); updatedpos=0;
      % get overall pos of text in normalized AXIS coordinates
      pos = [inf inf -inf -inf]; % [l b r t]
      for i=1:nhs
        extent = get(hs(i),'Extent'); % slow [l b w h]
        pos(1:2) = min( pos(1:2), extent(1:2) );
        pos(3:4) = max( pos(3:4), extent(1:2) + extent(3:4) );
      end;
      pos = pos * 1.05;
      pos(3:4) = pos(3:4) - pos(1:2);  % [l b w h]

      % convert pos to normalized FIGURE coordinates
      % must move origin, and also account for scaling
      axisPos = get(gca,'Position');
      pos(1) = axisPos(1) + pos(1) * axisPos(3);
      pos(2) = axisPos(2) + pos(2) * axisPos(4);
      pos(3) = pos(3) * axisPos(3);
      pos(4) = pos(4) * axisPos(4);
    end

    % if necessary, move OuterPosition of axes accordingly
    if( p<=2 && pos(p)<0 )
      step = min(.1,max(.001,-pos(p)/50));
      opos(p) = opos(p)+step;
      opos(p+2) = opos(p+2)-step;
      set(gca,'OuterPosition',opos);
      updated=1; updatedpos=1;
    elseif( p>2 && (pos(p-2)+pos(p))>1 )
      step = min(.1,max(.001,pos(p)/50));
      opos(p)=opos(p)-step;
      set(gca,'OuterPosition',opos);
      updated=1; updatedpos=1;
    end
  end
end
set(gca,'Units',oldunits);

%   if necessary, move OuterPosition of axes accordingly
%   if(p<=2 && pos(p)<0 )
%       step = max(.01,abs(pos(p))/1.5);
%       opos, step, pos, p
%       opos(p)=opos(p)+step;
%       opos(p+2)=opos(p+2)-step;
%       updated=1; updatedpos=1;
%       set(gca,'OuterPosition',opos);
%   elseif( p>2 && pos(p)>1 )
%       step = max(.01,(pos(p)-1)/1.5);
%       opos(p)=opos(p)-step;
%       updated=1; updatedpos=1;
%       set(gca,'OuterPosition',opos);
%   end


function [marginal, pot] = marginal_family(engine, query)
% MARGINAL_NODES Compute the marginal on the family of the specified query node (belprop)
% [marginal, pot] = marginal_family(engine, query)

pot = engine.marginal_domains{query};
marginal = pot_to_marginal(pot);


% SUPERGUI - a comprehensive gui automatic builder. This function help
%              to create GUI very fast without bothering about the
%              positions of the elements. After creating a geometry,
%              elements just place themselves into the predefined
%              locations. It is especially useful for figure where you
%              intend to put text button and descriptions.
%
% Usage:
%   >> [handles, height, allhandles ] = ...
%             supergui( 'key1', 'val1', 'key2', 'val2', ... );
%
% Inputs:
%   'fig'       - figure handler, if not given, create a new figure.
%   'geom'      - cell array of cell array of integer vector. Each cell
%               array defines the coordinate of a given input in the following
%               manner: { nb_row nb_col [x_topcorner y_topcorner]
%               [x_bottomcorner y_bottomcorner] };
%   'geomhoriz' - integer vector or cell array of numerical vectors describing the
%               geometry of the elements in the figure.
%               - if integer vector, vector length is the number of rows and vector
%               values are the number of 'uilist' elements in each row.
%               For example, [2 3 2] means that the
%               figures will have 3 rows, with 2 elements in the first
%               and last row and 3 elements in the second row.
%               - if cell array, each vector describes the relative widths
%               of items in each row. For example, { [2 8] [1 2 3] } which means
%               that figures will have 2 rows, the first one with 2
%               elements of relative width 2 and 8 (20% and 80%). The
%               second row will have 3 elements of relative size 1, 2
%               and 3 (1/6 2/6 and 3/6).
%   'geomvert' - describting geometry for the rows. For instance
%               [1 2 1] means that the second row will be twice the height
%               of the other ones. If [], all the lines have the same height.
%   'uilist'   - list of uicontrol lists describing elements properties
%               { { ui1 }, { ui2 }... }, { 'uiX' } being GUI matlab
%               uicontrol arguments such as { 'style', 'radiobutton',
%               'String', 'hello' }. See Matlab function UICONTROL for details.
%   'borders'  - [left right top bottom] GUI internal borders in normalized
%               units (0 to 1). Default values are
%   'title'    - optional figure title
%   'userdata' - optional userdata input for the figure
%   'inseth'   - horizontal space between elements. Default is 2%
%               of window size.
%   'insetv'   - vertical space between elements. Default is 2%
%               of window height.
%   'spacing'  - [horiz vert] spacing in normalized units. Default
%   'spacingtype' - ['absolute'|'proportional'] absolute means that the
%               spacing values are fixed. Proportional means that they
%               depend on the number of element in a line.
%   'minwidth' - [integer] minimal width in pixels. Default is none.
%   'screenpos' - [x y] position of the right top corner of the graphic
%               interface. 'center' may also be used to center the GUI on
%               the screen.
%   'adjustbuttonwidth' - ['on'|'off'] adjust button width in the GUI.
%               Default is 'off'.
%
% Hint:
%    use 'print -mfile filemane' to save a matlab file of the figure.
%
% Output:
%    handles  - all the handles of the elements (in the same order as the
%                uilist input).
%    height    - advised height for the figure (so the text look nice).
%    allhandles - all the handles in object format
%
% Example:
%    figure;
%    supergui( 'geomhoriz', { 1 1 }, 'uilist', { ...
%        { 'style', 'radiobutton', 'string', 'radio' }, ...
%        { 'style', 'pushbutton' , 'string', 'push' } } );
%
% Author: Arnaud Delorme, CNL / Salk Institute, La Jolla, 2001-
%
% See also: EEGLAB

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [handlers, outheight, allhandlers, alltags] = supergui( varargin);

% handlers cell format
% allhandlers linear format
handlers = {};
outheight = 0;

if nargin < 2
	help supergui;
	return;
end

% get version and
% set additional parameters
% -------------------------
v = version;
indDot  = find(v == '.');
versnum = str2num(v(1:indDot(2)-1));
if versnum >= 7.14
     addParamFont = { 'fontsize' 12 };
else addParamFont = { };
end

warning off MATLAB:hg:uicontrol:ParameterValuesMustBeValid

% decoding input and backward compatibility
% -----------------------------------------
if ischar(varargin{1})
    options = varargin;
else
    options = { 'fig'      varargin{1} 'geomhoriz' varargin{2} ...
                'geomvert' varargin{3} 'uilist'    varargin(4:end) };
end
g = finputcheck(options, { 'geomhoriz' 'cell'   []      {};
                           'fig'       ''       []      0;
                           'geom'      'cell'   []      {};
                           'uilist'    'cell'   []      {};
                           'title'     'string' []      '';
                           'userdata'  ''       []      [];
                           'adjustbuttonwidth' 'string' { 'on' 'off' } 'off';
                           'geomvert'  'real'   []      [];
                           'screenpos' { 'real' 'string' } [] [];
                           'horizontalalignment'  'string'   { 'left','right','center' } 'left';
                           'minwidth'  'real'   []      10;
                           'borders'   'real'   []      [0.05 0.04 0.07 0.06];
                           'spacing'   'real'   []      [0.02 0.01];
                           'inseth'    'real'   []      0.02; % x border absolute (5% of width)
                           'insetv'    'real'   []      0.02 }, 'supergui');
if ischar(g), error(g); end
if ~isempty(g.geomhoriz)
    maxcount = sum(cellfun('length', g.geomhoriz));
    if maxcount ~= length(g.uilist)
        warning('Wrong size for ''geomhoriz'' input');
    end
    if ~isempty(g.geomvert)
        if length(g.geomvert) ~= length(g.geomhoriz)
            warning('Wrong size for ''geomvert'' input');
        end
    end
    g.insetv = g.insetv/length(g.geomhoriz);
end
if ~isempty(g.geom)
    if length(g.geom) ~= length(g.uilist)
        warning('Wrong size for ''geom'' input');
    end
    maxcount = length(g.geom);
end

% create new figure
% -----------------
if g.fig == 0
	g.fig = figure('visible','off');
end

% converting the geometry formats
% -------------------------------
if ~isempty(g.geomhoriz) && ~iscell( g.geomhoriz )
	oldgeom = g.geomhoriz;
	g.geomhoriz = {};
	for row = 1:length(oldgeom)
		g.geomhoriz = { g.geomhoriz{:} ones(1, oldgeom(row)) };
	end
end
if isempty(g.geomvert)
	g.geomvert = ones(1, length(g.geomhoriz));
end

% converting to the new format
% ----------------------------
if isempty(g.geom)
    count = 1;
    incy  = 0;
    sumvert  = sum(g.geomvert);
    maxhoriz = 1;
    for row = 1:length(g.geomhoriz)
        incx = 0;
        maxhoriz = max(maxhoriz, length(g.geomhoriz{row}));
        ratio = length(g.geomhoriz{row})/sum(g.geomhoriz{row});
        for column = 1:length(g.geomhoriz{row})
            g.geom{count} = { length(g.geomhoriz{row}) sumvert [incx incy] [g.geomhoriz{row}(column)*ratio g.geomvert(row)] };
            incx = incx+g.geomhoriz{row}(column)*ratio;
            count = count+1;
        end
        incy = incy+g.geomvert(row);
    end
    g.borders(1:2) = g.borders(1:2)/maxhoriz*5;
    g.borders(3:4) = g.borders(3:4)/sumvert*10;
    g.spacing(1)   = g.spacing(1)/maxhoriz*5;
    g.spacing(2)   = g.spacing(2)/sumvert*10;
end

% disp new geometry
% -----------------
if 0
    fprintf('{ ...\n');
    for index = 1:length(g.geom)
        fprintf('{ %g %g [%g %g] [%g %g] } ...\n', g.geom{index}{1}, g.geom{index}{2}, ...
            g.geom{index}{3}(1), g.geom{index}{3}(2), g.geom{index}{4}(1), g.geom{index}{3}(2));
    end
    fprintf('};\n');
end

% get axis coordinates
% --------------------
try
    set(g.fig, 'menubar', 'none', 'numbertitle', 'off');
catch
end

pos = [0 0 1 1]; % plot relative to current axes
q = [pos(1) pos(2) 0 0];
s = [pos(3) pos(4) pos(3) pos(4)]; % allow to use normalized position [0 100] for x and y
axis('off');

% creating guis
% -------------
row    = 1; % count the elements
column = 1; % count the elements
factmultx = 0;
factmulty = 0; %zeros(length(g.geomhoriz));
transformTextUIList = [];
alltags = [];
for counter = 1:maxcount

	% init
	clear rowhandle;
    gm = g.geom{counter};
    [posx posy width height] = getcoord(gm{1}, gm{2}, gm{3}, gm{4}, g.borders, g.spacing);
%     str1 = sprintf('%d, %d, [%1.2f,%1.2f], [%1.2f,%1.2f]', gm{1}, gm{2}, gm{3}(1), gm{3}(2), gm{4}(1), gm{4}(2));
%     str2 = sprintf('%.4f, ', [posx posy width height]);
%     fprintf('%s -> %s -> %s\n', str1, str2, g.uilist{ counter }{4});

    try
        currentelem = g.uilist{ counter };
    catch
        fprintf('Warning: not all boxes were filled\n');
        return;
    end;
    if ~isempty(currentelem)
        % decode metadata
        % ---------------
        if strcmpi(currentelem{1}, 'link2lines'),
            currentelem(1) = [];
            hf1 = 3.6/2-0.3;
            hf2 = 0.7/2-0.3;
            allhandlers{counter} = uicontrol(g.fig, 'unit', 'normalized', 'position', ...
                                          [posx-width/2 posy+hf1*height width/2 0.005].*s+q, 'style', 'pushbutton', 'string', '');
            allhandlers{counter} = uicontrol(g.fig, 'unit', 'normalized', 'position', ...
                                          [posx-width/2 posy+hf2*height width/2 0.005].*s+q, 'style', 'pushbutton', 'string', '');
            allhandlers{counter} = uicontrol(g.fig, 'unit', 'normalized', 'position', ...
                                          [posx posy+hf2*height 0.005 (hf1-hf2+0.1)*height].*s+q, 'style', 'pushbutton', 'string', '');
            allhandlers{counter} = uicontrol(g.fig, 'unit', 'normalized', 'position', ...
                                          [posx posy+(hf1+hf2)/2*height width/2 0.005].*s+q, 'style', 'pushbutton', 'string', '');
            allhandlers{counter} = nan;
        else

            if strcmpi(currentelem{1}, 'width')
                 curwidth = currentelem{2};
                 currentelem(1:2) = [];
            else curwidth = 0;
            end
            if strcmpi(currentelem{1}, 'align')
                 align = currentelem{2};
                 currentelem(1:2) = [];
            else align = 'right';
            end
            transformText = false;
            if strcmpi(currentelem{2}, 'text2')
                transformTextUIList = [ transformTextUIList counter ];
                currentelem{2} = 'text';
            end
            if strcmpi(currentelem{1}, 'stickto')
                 stickto = currentelem{2};
                 currentelem(1:2) = [];
            else stickto = 'none';
            end
            if strcmpi(currentelem{1}, 'vertshift'), currentelem(1) = []; addvert = -height/2;
            else                                                          addvert = 0;
            end
            if strcmpi(currentelem{1}, 'vertexpand'), heightfactor = currentelem{2}; addvert = -(heightfactor-1)*height; currentelem(1:2) = [];
            else                                      heightfactor = 1;
            end

            % position adjustment depending on GUI type
            if ischar(currentelem{2}) && strcmpi(currentelem{2}, 'popupmenu')
                posy = posy-height/5;
            end
            if ischar(currentelem{2}) && strcmpi(currentelem{2}, 'text')
                posy = posy+height/5;
            end

            if strcmpi(currentelem{1}, 'function')
                % property grid argument
                panel = uipanel('Title','','FontSize',12,'BackgroundColor','white','Position',[posx posy+addvert width height*heightfactor].*s+q);
                allhandlers{counter} = arg_guipanel(panel, currentelem{:});
            elseif strcmpi(currentelem{1}, 'panel')
                % property grid argument
                uipanel(currentelem{2:end},'FontSize',12,'Position',[posx posy+addvert width height*heightfactor].*s+q);
                allhandlers{counter} = nan;
            elseif strcmpi(currentelem{1}, 'uitable')
                uitable(g.fig, currentelem{2:end}, 'unit', 'normalized', 'Position',[posx posy+addvert width height*heightfactor].*s+q);
                allhandlers{counter} = nan;
            else
                if ~isempty(strmatch('fontsize', currentelem(1:2:end)))
                    allhandlers{counter} = uicontrol(g.fig, 'unit', 'normalized', 'position', ...
                        [posx posy+addvert width height*heightfactor].*s+q, currentelem{:});
                else
                    allhandlers{counter} = uicontrol(g.fig, 'unit', 'normalized', 'position', ...
                        [posx posy+addvert width height*heightfactor].*s+q, currentelem{:}, addParamFont{:});
                end

                % this simply compute a factor so that all uicontrol will be visible
                % ------------------------------------------------------------------
                style = get( allhandlers{counter}, 'style');
                set( allhandlers{counter}, 'units', 'pixels');
                curpos = get(allhandlers{counter}, 'position');
                curext = get(allhandlers{counter}, 'extent');
                if curwidth ~= 0
                    curwidth = curwidth/((factmultx-1)/1.85+1);
                    if strcmpi(align, 'right')
                        curpos(1) = curpos(1)+curpos(3)-curwidth;
                    elseif strcmpi(align, 'center')
                        curpos(1) = curpos(1)+curpos(3)/2-curwidth/2;
                    end
                    set(allhandlers{counter}, 'position', [ curpos(1) curpos(2) curwidth curpos(4) ]);
                    if strcmpi(stickto, 'on')
                        set( allhandlers{counter-1}, 'units', 'pixels');
                        curpos2 = get(allhandlers{counter-1}, 'position');
                        set(allhandlers{counter-1}, 'position', [ curpos(1)-curpos2(3)-10 curpos2(2) curpos2(3) curpos2(4) ]);
                        set( allhandlers{counter-1}, 'units', 'normalized');
                    end
                    curext(3) = curwidth;
                end
                set( allhandlers{counter}, 'units', 'normalized');
            end

            if ~strcmp(style, 'edit') && (~strcmp(style, 'pushbutton') || strcmpi(g.adjustbuttonwidth, 'on'))
                if strcmpi( currentelem{3}, 'string') && (~iscell(currentelem{4}) || ...
                        (~isempty(currentelem{4}) && isempty(findstr('html', currentelem{4}{1}))))
                    %tmp = curext(3)/curpos(3);
                    %if tmp > 3*factmultx && factmultx > 0, adsfasd; end
                    if exist('OCTAVE_VERSION','builtin') ~= 0
                      curtxt = get(allhandlers{counter}, 'string');
                      if ischar(curtxt)
                        nLines = length(find(curtxt == 10))+1;
                        curext(3) = curext(3)/nLines;
                      end
                    end

                    if curext(3)/curpos(3) < 3
                        factmultx = max(factmultx, curext(3)/curpos(3));
                    end
                    tmptxt = get(allhandlers{counter}, 'string');
%                   % text to get which UI modify horizontal size
%                    if iscell(tmptxt) fprintf('%s -> %f\n', 'cell', curext(3)/curpos(3));
%                    else              fprintf('%s -> %f\n', tmptxt, curext(3)/curpos(3));
%                    end
                    if strcmp(style, 'pushbutton'), factmultx = factmultx*1.1; end
                end
            end
            if  ~strcmp(style, 'listbox') &&  ~strcmp(style, 'popupmenu')
                factmulty = max(factmulty, curext(4)/curpos(4));
            end

            % Uniformize button text aspect (first letter must be uppercase)
            % -----------------------------
            if strcmp(style, 'pushbutton') && ishandle(allhandlers{counter})
                tmptext = get(allhandlers{counter}, 'string');
                if length(tmptext) > 1
                    if upper(tmptext(1)) ~= tmptext(1) || lower(tmptext(2)) ~= tmptext(2) && ~strcmpi(tmptext, 'STATS')
                        tmptext = lower(tmptext);
                        try, tmptext(1) = upper(tmptext(1)); catch, end
                    end
                end
                set(allhandlers{counter}, 'string', tmptext);
            end

            try
                currentelemstruct = struct(currentelem{:});
                alltags.(currentelemstruct.tag) = allhandlers{counter};
            catch, end
        end
    else
        allhandlers{counter} = nan;
    end
end

% adjustments
% -----------
factmultx = factmultx*1.1;% because some text was still hidden
if factmultx < 0.1
	factmultx = 0.1;
end

% for MAC (magnify figures that have edit fields)
% -------
warning off;
try,
    comp = computer;
	if length(comp) > 2 && strcmpi(comp(1:3), 'MAC')
        factmulty = factmulty*1.5;
	elseif ~isunix % windows
        factmulty = factmulty*1.08;
    end
catch, end
if exist('OCTAVE_VERSION', 'builtin') == 0
    factmulty = factmulty*0.9; % global shinking
else
    factmulty = factmulty*1.5;
end
warning on;

% scale and replace the figure in the screen
% -----------------------------------------
pos = get(g.fig, 'position');
if factmulty > 1
	pos(2) = max(0,pos(2)+pos(4)-pos(4)*factmulty);
end
pos(1) = max(0,pos(1)+pos(3)*(1-factmultx)/2);
pos(3) = max(pos(3)*factmultx, g.minwidth);
pos(4) = pos(4)*factmulty;
set(g.fig, 'position', pos);

% vertical alignment to bottom for text (isnumeric by ishanlde was changed here)
% ---------------------------------------
for index = 1:length(allhandlers)
	if ishandle(allhandlers{index})
		if strcmp(get(allhandlers{index}, 'style'), 'text')
            set(allhandlers{index}, 'unit', 'pixel');
			curpos = get(allhandlers{index}, 'position');
			curext = get(allhandlers{index}, 'extent');
			set(allhandlers{index}, 'position', [curpos(1) curpos(2)-4 curpos(3) curext(4)]);
            set(allhandlers{index}, 'unit', 'normalized');
		end
	end
end

% setting defaults colors
%------------------------
try, icadefs;
catch,
	GUIBACKCOLOR        =  [.8 .8 .8];
	GUIPOPBUTTONCOLOR   = [.8 .8 .8];
	GUITEXTCOLOR        = [0 0 0];
end

numobjects = cellfun(@ishandle, allhandlers); % (isnumeric by ishanlde was changed here)
allhandlersnum = [ allhandlers{numobjects} ];
hh = findobj(allhandlersnum,'flat', 'parent', g.fig, 'style', 'text');
%set(hh, 'BackgroundColor', get(g.fig, 'color'), 'horizontalalignment', 'left');
set(hh, 'Backgroundcolor', GUIBACKCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
try
set(g.fig, 'color',GUIBACKCOLOR );
catch
end
set(hh, 'horizontalalignment', g.horizontalalignment);

hh = findobj(allhandlersnum,'flat', 'style', 'edit');
set(hh, 'BackgroundColor', [1 1 1]); %, 'horizontalalignment', 'right');

hh =findobj(allhandlersnum,'flat', 'parent', g.fig, 'style', 'pushbutton');
comp = computer;
if length(comp) < 3 || ~strcmpi(comp(1:3), 'MAC') % this puts the wrong background on macs
    set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
    set(hh, 'foregroundcolor', GUITEXTCOLOR);
end
hh =findobj(allhandlersnum,'flat', 'parent', g.fig, 'style', 'popupmenu');
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlersnum,'flat', 'parent', g.fig, 'style', 'checkbox');
set(hh, 'backgroundcolor', GUIBACKCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlersnum,'flat', 'parent', g.fig, 'style', 'listbox');
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlersnum,'flat', 'parent', g.fig, 'style', 'radio');
set(hh, 'foregroundcolor', GUITEXTCOLOR);
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(g.fig, 'visible', 'on');

% screen position
% ---------------
if ~isempty(g.screenpos)
    pos = get(g.fig, 'position');
    if isnumeric(g.screenpos)
        set(g.fig, 'position', [ g.screenpos pos(3) pos(4)]);
    else
        screenSize = get(0, 'screensize');
        pos(1) = (screenSize(3)-pos(3))/2;
        pos(2) = (screenSize(4)-pos(4))/2+pos(4);
        set(g.fig, 'position', pos);
    end
end;

% set userdata and title
% ----------------------
if ~isempty(g.userdata), set(g.fig, 'userdata', g.userdata); end
if ~isempty(g.title   ), set(g.fig, 'name',     g.title   ); end

% transform selected text UI
% --------------------------
a = axes('position', [0 0 1 1]);
for iList = transformTextUIList
    set(allhandlers{iList}, 'unit', 'normalized');
    sTmp = get(allhandlers{iList},'string');
    pTmp = get(allhandlers{iList},'position');
    eTmp = get(allhandlers{iList},'extent');
    tTmp = get(allhandlers{iList},'tag');
    % Remove the UICONTROL
    delete(allhandlers{iList});
    % Replace it with a TEXT object
    allhandlers{iList} = text(pTmp(1),pTmp(2),sTmp, 'interpreter','latex', 'tag', tTmp);
end
set(a, 'visible', 'off');

return;

function [posx posy width height] = getcoord(geom1, geom2, coord1, sz, borders, spacing);

    coord2 = coord1+sz;
    borders(1:2) = borders(1:2)-spacing(1);
    borders(3:4) = borders(3:4)-spacing(2);

    % absolute positions
    posx   = coord1(1)/geom1;
    posy   = coord1(2)/geom2;
    posx2  = coord2(1)/geom1;
    posy2  = coord2(2)/geom2;
    width  = posx2-posx;
    height = posy2-posy;

    % add spacing
    posx   = posx+spacing(1)/2;
    width  = max(posx2-posx-spacing(1), 0.001);
    height = max(posy2-posy-spacing(2), 0.001);
    posy   = max(0, 1-posy2)+spacing(2)/2;

    % add border
    posx   = posx*(1-borders(1)-borders(2))+borders(1);
    posy   = posy*(1-borders(3)-borders(4))+borders(4);
    width  = width*( 1-borders(1)-borders(2));
    height = height*(1-borders(3)-borders(4));

function [posx posy width height] = getcoordold(geom1, geom2, coord1, sz);

    coord2 = coord1+sz;
    horiz_space  = 0.05/geom1;
    vert_space   = 0.05/geom2;
    horiz_border = min(0.1, 1/geom1)-horiz_space;
    vert_border  = min(0.2, 1.5/geom2)-vert_space;

    % absolute positions
    posx   = coord1(1)/geom1;
    posy   = coord1(2)/geom2;
    posx2  = coord2(1)/geom1;
    posy2  = coord2(2)/geom2;
    width  = posx2-posx;
    height = posy2-posy;

    % add spacing
    posx   = posx+horiz_space/2;
    width  = max(posx2-posx-horiz_space, 0.001);
    height = max(posy2-posy- vert_space, 0.001);
    posy   = max(0, 1-posy2)+vert_space/2;

    % add border
    posx   = posx*(1-horiz_border)+horiz_border/2;
    posy   = posy*(1- vert_border)+vert_border/2;
    width  = width*(1-horiz_border);
    height = height*(1-vert_border);

    %     posx   = coord1(1)/geom1+horiz_border*1/geom1/2;
%     posy   = 1-(coord1(2)/geom2+vert_border*1/geom2/2)-1/geom2;
%
%     posx2  = coord2(1)/geom1+horiz_border*1/geom1/2;
%     posy2  = 1-(coord2(2)/geom2+vert_border*1/geom2/2)-1/geom2;
%
%     width  = posx2-posx;
%     height = posy-posy2;

    %h = axes('unit', 'normalized', 'position', [ posx posy width height ]);
    %h = axes('unit', 'normalized', 'position', [ coordx/geom1 1-coordy/geom2-1/geom2 1/geom1 1/geom2 ]);


function [p] = elec_write_emse(p)

% elec_write_emse - Write an EMSE probe file (*.elp)
%
% Usage: [p] = elec_write_emse(p)
%
% This script outputs x,y,z values to an EMSE
% probe (*.elp) file.
%
% EMSE *.elp files are in meters.  Also, when using
% EMSE *.elp files in the eeg_toolbox, it is necessary
% to swap X and Y.
%
% See also: emse_read_elp, elec_open
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:55 $

% Licence:  GNU GPL, no express or implied warranties
% History:  10/2002, Darren.Weber_at_radiology.ucsf.edu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[path,name,ext] = fileparts(strcat(p.elec.path,filesep,p.elec.file));
ext = '.elp';
file = fullfile(path,[name ext]);

p.elec.file = [name ext];

[fid,msg] = fopen(file,'w','ieee-le');
if ~isempty(msg), error(msg); end

tic

fprintf('\nELEC_WRITE_EMSE...\n');
fprintf('...writing .elp data to:\n\t%s\n',file);

write_elp(fid,p);

t = toc; fprintf('...done (%6.2f sec).\n\n',t);

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [elp] = write_elp(fid,p)

    Nelec = size(p.elec.data.x,1);

    % Probe files contain position information for electrode locations
    % and/or gradiometer locations. The file consists of a prolog, a
    % header, and a list of one or more sensor fields.

    % Any line beginning with '//' is a comment line, which is ignored

    % Write the prolog
    fprintf(fid,'%d %d\n%d\n',3,2,1);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Write the header
    % The header consists of one optional entry and 2 entries in
    % mandatory sequence and one optional entry:
    % Name [optional] > %N %s replace %s with name string (8 or fewer characters)
    % Type Code       > %x    replace %x with 1 (all electric), 2 (all magnetic) or 4 (mixed).
    % #Channels       > %d    number of points per channel per epoch [???? DLW]

    fprintf(fid,'//TypeCode nsensors\n');
    fprintf(fid,'%d %d\n',1,Nelec + 1);     % Nelectrodes plus REF

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Fiducial points may be included optionally. They are required
    % for MRI registration. If they are included, they must be in
    % the obligatory order : nasion, left preauricular point,
    % right preauricular point. Table A-2 defines the format for
    % representing fiduciary points.

    fprintf(fid,'//Fiducials (Nasion, Left Preauricular, Right Preauricular)\n');
    fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','%F',...
        p.elec.data.nasion(1),...
        p.elec.data.nasion(2),...
        p.elec.data.nasion(3));
    fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','%F',...
        p.elec.data.lpa(1),...
        p.elec.data.lpa(2),...
        p.elec.data.lpa(3));
    fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','%F',...
        p.elec.data.rpa(1),...
        p.elec.data.rpa(2),...
        p.elec.data.rpa(3));

    % Each electrode is represented by an electric sensor,
    % and consists of 5 fields, of which 1 (the name) is
    % optional.
    % Name              Format      Description
    % Type Code         %S          %x replace %x with 400 (electrode) or 1c00 if reference channel
    % Name [optional]   %N          %s replace %s with name string (8 or fewer characters)
    % Position          %g %g %g    electrode location with respect to head frame (Cartesian, meters)
    % Orientation       %g %g %g    not used, replace with 0 0 1
    %
    % Sensor state (which appears in the 'type code' field) may
    % be obtained by logically OR-ing suitable combinations from
    % the table below. Note that not all combinations are physically valid.
    %
    % type/state        type code
    % magnetic          200
    % electric          400
    % off               800
    % reference         1000        actually '1c00' [DLW]
    % optical           4000
    % trigger           8000
    % other             10000
    % named point       20000
    %
    % Other types (such as named points, trigger, and optical) should
    % be represented in the same pattern as electrodes, with the type
    % code set to identify the type. Even those types (e.g. trigger)
    % which do not have a true location, should have a nominal
    % location, (e.g. 0 0 0).

    % Note below that eeg_toolbox x,y,z are equivalent to
    % emse y,-x,z

    typecode = 400;

    for n = 1:Nelec,
        fprintf(fid,'\n//ecSensor typecode/state---------------------\n');
        fprintf(fid,'%s\t%d\n','%S',typecode);
        fprintf(fid,'//ecSensor name:\n');
        fprintf(fid,'%s\t%s\n','%N',char(p.elec.data.label(n)));
        fprintf(fid,'//sphere origin\n');
        fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','%O',...
            p.elec.data.centroid(2),...
            p.elec.data.centroid(1) * -1,...
            p.elec.data.centroid(3));
        fprintf(fid,'//ecSensor location (origin)\n');
        fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','  ',...
            p.elec.data.y(n),...
            p.elec.data.x(n) * -1,...
            p.elec.data.z(n));
    end

    % Output the REF
    typecode = '1c00'; % This is not consistent with the
                       % table above, but it works!
    fprintf(fid,'\n//ecSensor typecode/state---------------------\n');
    fprintf(fid,'%s\t%s\n','%S',typecode);
    fprintf(fid,'//ecSensor name:\n');
    fprintf(fid,'%s\t%s\n','%N','Ref');
    fprintf(fid,'//sphere origin\n');
    fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','%O',...
        p.elec.data.centroid(2),...
        p.elec.data.centroid(1) * -1,...
        p.elec.data.centroid(3));
    fprintf(fid,'//ecSensor location (origin)\n');
    fprintf(fid,'%s\t%12.8f\t%12.8f\t%12.8f\n','  ',...
        p.elec.data.ref(2),...
        p.elec.data.ref(1) * -1,...
        p.elec.data.ref(3));

    fclose(fid);

return


function projmat_art = comb_projmat(proj_mat1,proj_mat2)%,angles1,angles2)
projmat_art = [proj_mat1,fliplr(proj_mat2)];
end