% POP_SPECPARAMS - Set plotting and statistics parameters for computing
%                    STUDY component spectra.
% Usage:
%       >> STUDY = pop_specparams(STUDY, 'key', 'val');
%
% Inputs:
%   STUDY        - EEGLAB STUDY set
%
% Plot options:
%   'topofreq'   - [real] Plot Spectrum scalp maps at one specific freq. (Hz).
%                  A frequency range [min max] may also be defined (the
%                  spectrum is then averaged over the interval) {default: []}
%   'freqrange'  - [min max] spectral frequency range (in Hz) to plot.
%                  {default: whole frequency range} .
%   'ylim'       - [mindB maxdB] spectral plotting limits in dB
%                  {default: from data}
%   'plotgroups' - ['together'|'apart'] 'together' -> plot subject groups
%                  on the same figure in different colors, else ('apart') on
%                  different figures {default: 'apart'}
%   'plotconditions' - ['together'|'apart'] 'together' -> plot conditions
%                  on the same figure in different colors, else ('apart')
%                  on different figures. Note: keywords 'plotgroups' and
%                  'plotconditions' cannot both be set to 'together'.
%                  {default: 'apart'}
%   'subtractsubjectmean' - ['on'|'off'] subtract individual subject mean
%                  from each spectrum before plotting and computing
%                  statistics. Default is 'off'.
%   'averagechan' - ['rms'|'on'|'off'] average data channels when several are
%                  selected ('on') or compute root mean square ('rms').
%
% See also: STD_SPECPLOT
%
% Authors: Arnaud Delorme, CERCO, CNRS, 2006-

% Copyright (C) Arnaud Delorme, CERCO
%
% 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 [ STUDY, com ] = pop_specparams(STUDY, varargin);

STUDY = default_params(STUDY);
TMPSTUDY = STUDY;
com = '';
if isempty(varargin)

    enablecond  = 'off';
    enablegroup = 'off';
    if length(STUDY.design(STUDY.currentdesign).variable) > 0 && length(STUDY.design(STUDY.currentdesign).variable(1).value)>1, enablecond  = 'on'; end
    if length(STUDY.design(STUDY.currentdesign).variable) > 1 && length(STUDY.design(STUDY.currentdesign).variable(2).value)>1, enablegroup = 'on'; end;
    plotconditions     = fastif(strcmpi(STUDY.etc.specparams.plotconditions, 'together'), 1, 0);
    plotgroups         = fastif(strcmpi(STUDY.etc.specparams.plotgroups,'together'), 1, 0);
    submean            = fastif(strcmpi(STUDY.etc.specparams.subtractsubjectmean,'on'), 1, 0);
    tmpFreqRange = STUDY.etc.specparams.freqrange;
    if strcmpi(STUDY.etc.specparams.averagechan,'off')
        if isempty(STUDY.etc.specparams.topofreq) || any(isnan(STUDY.etc.specparams.topofreq))
            multipleChansVal   = 1; % scalp array
        else
            multipleChansVal   = 2; % scalp topo
            tmpFreqRange = STUDY.etc.specparams.topofreq;
        end
    else
        if strcmpi(STUDY.etc.specparams.averagechan,'on')
            multipleChansVal   = 3; % average channels
        else
            multipleChansVal   = 4; % root mean square
        end
    end

    cb_radio = [ 'set(findobj(gcbf, ''userdata'', ''radio''), ''value'', 0);' ...
                 'set(gcbo, ''value'', 1);' ...
                 'set(findobj(gcbf, ''tag'', ''topofreq''), ''string'', '''');' ];
    cb_edit  = [ 'set(findobj(gcbf, ''userdata'', ''radio''), ''value'', 0);' ...
                 'set(findobj(gcbf, ''tag'', ''scalptopotext''), ''value'', 1);' ];
    cb_multiplechan    = [ 'if get(gcbo, ''value'') == 2 ' ...
                         '    if isempty(get(findobj(gcbf, ''tag'', ''freqrange''), ''string'')),' ...
                         '       set(gcbo, ''value'', 1);' ...
                         '       warndlg2([ ''Select frequency range first for plotting topography,'' 10 ''then select that setting again.'' ]);' ...
                         '    end;' ...
                         'else,' ...
                         '    if ~isempty(get(findobj(gcbf, ''tag'', ''freqrange''), ''string'')) && length(unique(str2num(get(findobj(gcbf, ''tag'', ''freqrange''), ''string'')))) ==1,' ...
                         '       set(findobj(gcbf, ''tag'', ''freqrange''), ''string'', '''');' ...
                         '    end;' ...
                         'end;' ];

    uilist = { ...
           {'style' 'text'       'string' 'Spectrum plotting options' 'fontweight' 'bold' 'fontsize', 12} ...
        {} {'style' 'text'       'string' 'Frequency [low_Hz high_Hz]' } ...
           {'style' 'edit'       'string' num2str(tmpFreqRange) 'tag' 'freqrange' } ...
        {} {'style' 'text'       'string' 'Plot limits [low high]'} ...
           {'style' 'edit'       'string' num2str(STUDY.etc.specparams.ylim) 'tag' 'ylim' } ...
        {} {'style' 'checkbox'   'string' 'Subtract individual subject mean spectrum' 'value' submean 'tag' 'submean' } ...
        {} ...
           {'style' 'text'       'string' 'Spectrum plotting format' 'fontweight' 'bold' 'fontsize', 12} ...
        {} {'style' 'checkbox'   'string' 'Plot first variable on the same panel' 'value' plotconditions 'enable' enablecond  'tag' 'plotconditions' } ...
        {} {'style' 'checkbox'   'string' 'Plot second variable on the same panel' 'value' plotgroups 'enable' enablegroup 'tag' 'plotgroups' } ...
        {} ...
           {'style' 'text'       'string' 'Multiple channels selection' 'fontweight' 'bold' 'tag', 'spec' 'fontsize', 12} ...
        {} {'style' 'popupmenu'  'string' { 'Plot channels individually' 'Plot averaged topography over frequency range' 'Average power of selected channels' 'Compute RMS power of selected channels' } 'value' multipleChansVal 'tag' 'multiplechan' 'callback' cb_multiplechan } };
    cbline = [0.07 1.1];
    otherline = [ 0.07 0.6 .3];
    chanline  = [ 0.07 0.8];
    geometry = { 1 otherline otherline cbline 1 1 cbline cbline 1 1 chanline };
    geomvert = [1.2 1 1 1 0.5 1.2 1 1 0.5 1.2 1 ];

    % component plotting
    % ------------------
    if isnan(STUDY.etc.specparams.topofreq)
        geometry(end-2:end) = [];
        geomvert(end-2:end) = [];
        uilist(end-3:end) = [];
    end

    [out_param userdat tmp res] = inputgui( 'geometry' , geometry, 'uilist', uilist, 'geomvert', geomvert, ...
                                            'title', 'Spectrum plotting options -- pop_specparams()');
    if isempty(res), return; end
    if ~isfield(res, 'multiplechan'), res.multiplechan = 0; end

    % decode inputs
    % -------------
    %if res.plotgroups && res.plotconditions, warndlg2('Both conditions and group cannot be plotted on the same panel'); return; end
    if res.submean   , res.submean    = 'on'; else res.submean    = 'off'; end
    if res.plotgroups, res.plotgroups = 'together'; else res.plotgroups = 'apart'; end
    if res.plotconditions , res.plotconditions  = 'together'; else res.plotconditions  = 'apart'; end
    res.freqrange = str2num( res.freqrange );
    res.ylim      = str2num( res.ylim );

    % build command call
    % ------------------
    options = {};
    if ~strcmpi( res.plotgroups, STUDY.etc.specparams.plotgroups), options = { options{:} 'plotgroups' res.plotgroups }; end
    if ~strcmpi( res.plotconditions , STUDY.etc.specparams.plotconditions ), options = { options{:} 'plotconditions'  res.plotconditions  }; end
    if ~strcmpi( res.submean   , STUDY.etc.specparams.subtractsubjectmean ), options = { options{:} 'subtractsubjectmean'  res.submean  }; end
    if ~isequal(res.ylim, STUDY.etc.specparams.ylim),               options = { options{:} 'ylim' res.ylim      }; end
    if ~isequal(res.freqrange, STUDY.etc.specparams.freqrange) && res.multiplechan ~= 2,     options = { options{:} 'freqrange' res.freqrange }; end

    % multiple channel option
    % -----------------------
    if res.multiplechan == 1
        if ~isequal('off', STUDY.etc.specparams.averagechan), options = { options{:} 'averagechan' 'off' }; end
        if ~isempty(       STUDY.etc.specparams.topofreq),    options = { options{:} 'topofreq' [] }; end
    elseif res.multiplechan == 2
        if ~isequal('off', STUDY.etc.specparams.averagechan), options = { options{:} 'averagechan' 'off' }; end
        if ~isequal(res.freqrange, STUDY.etc.specparams.topofreq) options = { options{:} 'topofreq' res.freqrange }; end
        if ~isequal([], STUDY.etc.specparams.freqrange) options = { options{:} 'freqrange' [] }; end
        if isempty(res.freqrange)
            disp('Warning: you must select a frequency range to plot scalp topographies, plotting individual channels instead');
        end
    elseif res.multiplechan > 2
        if ~isempty(       STUDY.etc.specparams.topofreq),    options = { options{:} 'topofreq' [] }; end
        if res.multiplechan == 3
            if ~isequal('on', STUDY.etc.specparams.averagechan), options = { options{:} 'averagechan' 'on' }; end
        else
            if ~isequal('rms', STUDY.etc.specparams.averagechan), options = { options{:} 'averagechan' 'rms' }; end
        end
    end

    % execute option
    % --------------
    if ~isempty(options)
        STUDY = pop_specparams(STUDY, options{:});
        com = sprintf('STUDY = pop_specparams(STUDY, %s);', vararg2str( options ));
    end
else

    if strcmpi(varargin{1}, 'default')
        STUDY = default_params(STUDY);
    else
        for index = 1:2:length(varargin)
            if ~isempty(strmatch(varargin{index}, fieldnames(STUDY.etc.specparams), 'exact'))
                STUDY.etc.specparams = setfield(STUDY.etc.specparams, varargin{index}, varargin{index+1});
            end
        end
    end
end

% scan clusters and channels to remove specdata info if freqrange has changed
% ----------------------------------------------------------
if ~isequal(STUDY.etc.specparams.freqrange, TMPSTUDY.etc.specparams.freqrange) || ...
    ~isequal(STUDY.etc.specparams.subtractsubjectmean, TMPSTUDY.etc.specparams.subtractsubjectmean)
    rmfields = { 'specdata' 'specfreqs' };
    for iField = 1:length(rmfields)
        if isfield(STUDY.cluster, rmfields{iField})
            STUDY.cluster = rmfield(STUDY.cluster, rmfields{iField});
        end
        if isfield(STUDY.changrp, rmfields{iField})
            STUDY.changrp = rmfield(STUDY.changrp, rmfields{iField});
        end
    end
end

function STUDY = default_params(STUDY)
    if ~isfield(STUDY.etc, 'specparams'), STUDY.etc.specparams = []; end
    if ~isfield(STUDY.etc.specparams, 'topofreq'),             STUDY.etc.specparams.topofreq = []; end
    if ~isfield(STUDY.etc.specparams, 'freqrange'),            STUDY.etc.specparams.freqrange = []; end
    if ~isfield(STUDY.etc.specparams, 'ylim'     ),            STUDY.etc.specparams.ylim      = []; end
    if ~isfield(STUDY.etc.specparams, 'subtractsubjectmean' ), STUDY.etc.specparams.subtractsubjectmean  = 'off'; end
    if ~isfield(STUDY.etc.specparams, 'plotgroups'),           STUDY.etc.specparams.plotgroups = 'apart'; end
    if ~isfield(STUDY.etc.specparams, 'plotconditions'),       STUDY.etc.specparams.plotconditions  = 'apart'; end
    if ~isfield(STUDY.etc.specparams, 'averagechan') ,         STUDY.etc.specparams.averagechan  = 'off'; end
    if ~isfield(STUDY.etc.specparams, 'detachplots') ,         STUDY.etc.specparams.detachplots  = 'on'; end % deprecated


function [ Pos ] = getEEFCartesianPosition( t )
%% This function is used to get the endeffector cartizian position of the KUKA iiwa 7 R 800.

%% Syntax:
% [ Pos ] = getEEFCartesianPosition( t )

%% About
% This function is used to get the endeffector Cartesian position of the KUKA iiwa 7 R 800.
% The position is of the media flange of the robot, and it is measured
% relative to the robot base frame.

%% Arreguments:
% t: is the TCP/IP connection
% Pos: is 1x3 cell array. Representing the  X,Y and Z positions of the
% endeffector. The returned values are in (millimeters)

% Copyright, Mohammad SAFEEA, 3rd of May 2017

theCommand='Eef_pos';
fprintf(t, theCommand);
message=fgets(t);
%disp(message)
[P1,N]=getDoubleFromString(message);

for i=1:3
    Pos{i}=P1{i};
end

end

function [jPos,j]=getDoubleFromString(message)
n=max(max(size(message)));
j=0;
numString=[];
for i=1:n
    if message(i)=='_'
        j=j+1;
        jPos{j}=str2num(numString);
        numString=[];
    else
        numString=[numString,message(i)];
    end
end
end


function test_validity_of_datasource(ds)

% A helper function that tests whether a given data source returns any of the same data
%  in the training and test data.  Obviously if some of the same data is in the training
%  and test sets then there are major problems with the datasource!
%
% The input of this function should be a datasource that has been initialized with
%  real data.  This function replaces the real data with unique numbers and tests
%  whether any of the same numbers are in the training and test sets.  The function
%  prints a message that says whether the datasource has problems or seems ok.

%==========================================================================

%     This code is part of the Neural Decoding Toolbox.
%     Copyright (C) 2011 by Ethan Meyers (emeyers@mit.edu)
%
%     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/>.

%==========================================================================

% replace the original data with unique numbers for data point

the_original_data = ds.the_data;

start_ind = 1;

for iSite = 1:length(the_original_data)

    end_ind = start_ind - 1 + prod(size(the_original_data{iSite}));

    the_new_data{iSite} = reshape(start_ind:end_ind, [size(the_original_data{iSite}, 1) size(the_original_data{iSite}, 2)]);

    start_ind = end_ind + 1;

end

clear the_original_data

ds.the_data = the_new_data;

% get the training and test data with the new data that has unique labels at each time point, and
%   make sure that no unique label is in both the training and test sets

[XTr_all_time_cv YTr_all_cv XTe_all_time_cv YTe_all_cv] = get_data(ds);

num_probs_with_ds = 0;

for iTime = 1:size(XTr_all_time_cv, 2)
    for iCV = 1:ds.num_cv_splits

        if length(intersect(XTr_all_time_cv{iTime}{iCV}(:), XTe_all_time_cv{iTime}{iCV}(:)))
            num_probs_with_ds = num_probs_with_ds + 1;
        end

    end
end

if num_probs_with_ds > 1
    'This datasource has problems - some of the same data is in the training and test sets!'
else
    'This datasource seems ok'
end


function [scoresAll, labelsAll, nGTall] = assignGTMulticutMulti_WAF(annolistWAF_det,annolistWAF_gt,pidxsAll,parts,thresh_gt)

if (nargin < 5)
    thresh_gt = 0.5;
end

% scoresAll = cell(length(pidxsAll),1);
% labelsAll = cell(length(pidxsAll),1);
% nGTall = zeros(length(pidxsAll),length(annolist));
%
% for i = 1:length(pidxsAll)
%     scoresAll{i} = cell(length(annolist),1);
%     labelsAll{i} = cell(length(annolist),1);
% end

assert(length(annolistWAF_det) == length(annolistWAF_gt));
bVis = false;

for imgidx = 1:length(annolistWAF_gt)

    fprintf('.');

%     dist = inf(length(keypointsAll(imgidx).det),length(annolist(imgidx).annorect),length(pidxsAll));
%     score = nan(length(keypointsAll(imgidx).det),length(annolist(imgidx).annorect),length(pidxsAll));
%     hasDet = false(length(keypointsAll(imgidx).det),length(annolist(imgidx).annorect),length(pidxsAll));
%     hasGT = false(length(keypointsAll(imgidx).det),length(annolist(imgidx).annorect),length(pidxsAll));

    for j = 1:length(annolistWAF_det(imgidx).stickmen) % clusters

        for ridx = 1:length(annolistWAF_gt(imgidx).stickmen) % gt people

            rect = annolist(imgidx).annorect(ridx);
            refDist = util_get_head_size(rect);
            points_gt = rect.annopoints.point;

            for i = 1:length(pidxsAll)
                pidx = pidxsAll(i);
                % part is a joint
                assert(parts(pidx+1).pos(1) == parts(pidx+1).pos(2));
                jidx = parts(pidx+1).pos(1);

                det = keypointsAll(imgidx).det{j}{jidx+1};
                if (~isempty(det))
                    point_det = det(1:2);
                    score(j,ridx,i) = det(3);
                    hasDet(j,ridx,i) = true;
                end
                pp = util_get_annopoint_by_id(points_gt, jidx);
                if (~isempty(pp))
                    hasGT(j,ridx,i) = true;
                end
                if (hasDet(j,ridx,i) && hasGT(j,ridx,i))
                    dist(j,ridx,i) = norm([pp.x pp.y] - point_det)/refDist;
                end
            end
        end
    end

    match = dist <= thresh_gt;
    pck = sum(match,3)./sum(hasGT,3);
    [val,idx] = max(pck,[],2);
    for j = 1:length(idx)
        pck(j,setdiff(1:size(pck,2),idx(j))) = 0;
    end
    [val,clusToGT] = max(pck,[],1);
    clusToGT(val == 0) = 0;

    for j = 1:length(keypointsAll(imgidx).det)
        if (ismember(j,clusToGT)) % match to GT
            ridx = find(clusToGT == j);

            if (bVis)
                rect = annolist(imgidx).annorect(ridx);
                points_gt = rect.annopoints.point;
                gt = cell(16,1);
                for i = 1:length(pidxsAll)
                    pidx = pidxsAll(i);
                    % part is a joint
                    assert(parts(pidx+1).pos(1) == parts(pidx+1).pos(2));
                    jidx = parts(pidx+1).pos(1);
                    pp = util_get_annopoint_by_id(points_gt, jidx);
                    if (~isempty(pp))
                        gt{jidx+1} = [pp.x pp.y -1];
                    end
                end

                img = imread(annolist(imgidx).image.name);
                figure(100); clf; subplot(1,2,1); imagesc(img); axis equal; hold on;
                vis_multicut2(keypointsAll(imgidx).det{j},pidxsAll,parts);
                subplot(1,2,2); imagesc(img); axis equal; hold on;
                vis_multicut2(gt,pidxsAll,parts);
            end

            s = squeeze(score(j,ridx,:));
            m = squeeze(match(j,ridx,:));
            hd = squeeze(hasDet(j,ridx,:));

            idxs = find(hd);
            for i = 1:length(idxs)
                scoresAll{idxs(i)}{imgidx} = [scoresAll{idxs(i)}{imgidx};s(idxs(i))];
                labelsAll{idxs(i)}{imgidx} = [labelsAll{idxs(i)}{imgidx};m(idxs(i))];
            end

        else % no matching to GT
            s = squeeze(score(j,1,:));
            m = false(size(match,3),1);
            hd = squeeze(hasDet(j,ridx,:));
            idxs = find(hd);
            for i = 1:length(idxs)
                scoresAll{idxs(i)}{imgidx} = [scoresAll{idxs(i)}{imgidx};s(idxs(i))];
                labelsAll{idxs(i)}{imgidx} = [labelsAll{idxs(i)}{imgidx};m(idxs(i))];
            end
        end
    end

    for ridx = 1:length(annolist(imgidx).annorect)
        hg = squeeze(hasGT(1,ridx,:));
%         idxs = find(hg);
%         for i = 1:length(idxs)
%             nGTall(idxs(i),imgidx) = nGTall(idxs(i),imgidx) + hg(idxs(i));
%         end
        nGTall(:,imgidx) = nGTall(:,imgidx) + hg;
    end

    if (~mod(imgidx, 100))
        fprintf(' %d/%d\n',imgidx,length(keypointsAll));
    end
end
fprintf(' done\n');
end


% Template script for FieldMap toolbox
% _____________________________________________________________________
%
% This script gives an example of how to run the FieldMap toolbox
% FieldMap.m without using the GUI. It can be expanded using standard
% matlab code to for example create multiple field maps or use a single
% fieldmap to unwarp multiple images.
%
% As it stands the script uses routines from the FieldMap toolbox to
% create a single field map which is matched to an EPI and then used
% to unwarp it. A structural image is loaded and matched to the unwarped
% EPI.
%
% For details about the FieldMap toolbox, see FieldMap.man. For a
% description of the components of the structure IP, see FieldMap.m.
% For an introduction to the theoretcial and practical principles behind
% the toolbox, see principles.man.
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Jesper Andersson and Chloe Hutton
% $Id: FieldMap_ngui.m 1358 2008-04-10 11:20:26Z guillaume $

%----------------------------------------------------------------------
% Set up default parameters and structures
%----------------------------------------------------------------------

spm('defaults','FMRI');
IP = FieldMap('Initialise'); % Gets default params from pm_defaults

%----------------------------------------------------------------------
% Load measured field map data - phase and magnitude or real and imaginary
%----------------------------------------------------------------------

if IP.uflags.iformat=='PM'
   for index=1:4
      IP.P{index} = FieldMap('LoadFilePM',index);
   end
else
   for index=1:4
      IP.P{index} = FieldMap('LoadFile',index);
   end
end

%----------------------------------------------------------------------
% Or you may want to load a precalculated Hz phase map instead...
%----------------------------------------------------------------------

% [IP.fm, IP.pP] = FieldMap('LoadFieldMap');

%----------------------------------------------------------------------
% Create field map (in Hz) - this routine calls the unwrapping
%----------------------------------------------------------------------

IP.fm = FieldMap('CreateFieldMap',IP);

%----------------------------------------------------------------------
% Write out field map
% Outputs -> fpm_NAME-OF-FIRST-INPUT-IMAGE.img
%----------------------------------------------------------------------

FieldMap('Write',IP.P{1},IP.fm.fpm,'fpm_',64,'Smoothed phase map');

%----------------------------------------------------------------------
% Convert Hz to voxels and write voxel displacement map
% Outputs -> vdm_NAME-OF-FIRST-INPUT-IMAGE.img
%----------------------------------------------------------------------

[IP.vdm, IP.vdmP]=FieldMap('FM2VDM',IP);

%----------------------------------------------------------------------
% Select an EPI to unwarp
%----------------------------------------------------------------------

IP.epiP = FieldMap('LoadEPI');

%----------------------------------------------------------------------
% Match voxel displacement map to image
% Outputs -> mag_NAME-OF-FIRST-INPUT-IMAGE.img
%----------------------------------------------------------------------

IP.vdmP = FieldMap('MatchVDM',IP);

%----------------------------------------------------------------------
% Unwarp EPI
%----------------------------------------------------------------------

IP.uepiP = FieldMap('UnwarpEPI',IP);

%----------------------------------------------------------------------
% Write unwarped EPI
% Outputs -> uNAME-OF-EPI.img
%----------------------------------------------------------------------

IP.uepiP = FieldMap('Write',IP.epiP,IP.uepiP.dat,'u',IP.epiP.dim(4),'Unwarped image');

%----------------------------------------------------------------------
% Load a structural image
%----------------------------------------------------------------------

IP.nwarp=FieldMap('LoadStructural');

%----------------------------------------------------------------------
% Coregister structural with the unwarped image
%----------------------------------------------------------------------

FieldMap('MatchStructural',IP);

%______________________________________________________________________


% pop_chanevent() - import event latencies from the rising and/or falling 'edge'
%                   latencies of a specified event-marker channel in EEG.data
% Usage:
%   >> OUTEEG = pop_chanevent( INEEG ); % select parameters via a pop-up window
%   >> OUTEEG = pop_chanevent( INEEG, chanindices, 'key', 'val' ... ); % no pop-up
%
% Graphic interface:
%   "Event channel(s)" - [edit box] indices of event channel(s) to import.
%                  Command line equivalent: chanindices.
%   "Preprocessing transform" - [edit box] apply this preprocessing
%                  formula or function to the selected data channel(s) X,
%                  transforming X into the command output before edge
%                  extraction. Command line equivalent 'oper'.
%   "Transition to extract" - [list box] extract events when the event
%                  channel values go up ('leading'), down ('trailing')
%                  or both ('both'). Command line equivalent: 'edge'.
%   "Transition length" - [edit box] Increase this number to avoid having
%                  events very close to each other due to a not perfectly
%                  straight edge. Command line equivalent: 'edgelen'.
%   "Assign duration to events?" - [checkbox] . Assign duration to each
%                  extracted event.  This option can only be used when
%                  extracting events on leading edges. Event will last
%                  until next trailing edge (down) event. Command line
%                  equivalent: 'duration'.
%   "Delete event channel(s)" - [checkbox] check to delete the event channel
%                  after events have been extracted from it.
%                  Command line equivalent: 'delchan'.
%   "Delete old events if any" - [checkbox] check this checkbox to
%                  remove any prior events in the dataset. Otherwise
%                  imported events are appended to old events. Command
%                  line equivalent: 'delevent'.
%   "Only one event type" - [checkbox] check this checkbox to assign
%                  all transitions in the event channel to one event
%                  type. Else, one type is assigned for each non-zero
%                  channel value. Command line equivalent: 'nbtype'.
% Inputs:
%   INEEG          - input dataset structure
%   chanindices    - index|(indices) of the event channel(s)
%
% Optional inputs:
%   'edge'         - ['leading'|'trailing'|'both'] extract events when values
%                    in the event channel go up ('leading'), down ('trailing')
%                    or both ('both'). {Default is 'both'}.
%   'edgelen'      - [integer] maximum edge length (for some data edge do not
%                    take whole value and it takes a few sample points for
%                    signal to rise. Default is 1 (perfect edges).
%   'oper'         - [string] prior to extracting edges, preprocess data
%                    channel(s) using the string command argument.
%                    In this command, the data channel(s) are designated by
%                    (capital) X. For example, 'X>3' will test the value of X
%                    at each time point (returning 1 if the data channel value
%                    is larger than 3, and 0 otherwise). You may also use
%                    any function (Ex: 'myfunction(X)').
%   'duration'     - ['on'|'off'] extract event duration. This option can only be
%                    used when extracting events on leading edges. Event will last
%                    until next trailing-edge (down) event { 'off' }.
%   'delchan'      - ['on'|'off'] delete channel from data { 'on' }.
%   'delevent'     - ['on'|'off'] delete old events if any { 'on' }.
%   'nbtype'       - [1|NaN] setting this to 1 will force the program to
%                    consider all events to have the same type. {Default is NaN}.
%                    If set (1), all transitions are considered the same event type
%			         If unset (NaN), each (transformed) event channel value following a
%                    transition determines an event type (Ex: Detecting leading-edge
%                    transitions of 0 0 1 0 2 0 ...  produces event types 1 and 2).
%   'typename'     - [string] event type name. Only relevant if 'nbtype' is 1
%                    or if there is only one event type in the event channel.
%                    {Default is 'chanX', X being the index of
%                    the selected event channel}.
% Outputs:
%   OUTEEG         - EEGLAB output data structure
%
% Author: Arnaud Delorme, CNL / Salk Institute, 29 July 2002
%
% See also: eeglab()

% Copyright (C) 2002 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% 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 2 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, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [EEG, command] = pop_chanevent(EEG, chan, varargin);
command = '';

if nargin < 1
    help pop_chanevent;
    return;
end;

if nargin < 2
	geometry = { [1.5 1 1] [1] [1.5 1 1] [1.5 1 1] [1.5 1 1] [1.5 0.2 0.36 0.84] ...
                 [1] [1.5 0.21 1] [1.5 0.21 1] [1.5 0.21 1] };

    % callback from listbox to disable duration checkbox (if leading event is not selected)
    % --------------------------------------------------
    cb_list = [ 'if get(gcbo, ''value'') == 1,' ...
                '  set(findobj(gcbf, ''tag'', ''dur''), ''enable'', ''on'');' ...
                'else,' ...
                '  set(findobj(gcbf, ''tag'', ''dur''), ''enable'', ''off'', ''value'', 0);' ...
                'end;' ];

	strgui = { { 'style' 'text' 'string' 'Event channel(s)' 'tooltipstring' 'indexes of event channels' } ...
			   { 'style' 'edit' 'string' '' } { } ...
               {} ...
			   { 'style' 'text' 'string' 'Preprocessing transform (data=''X'')' 'tooltipstring'  ...
                 [ 'For example, ''X>3'' will test the value of X' 10 ...
                  'at each time point (returning 1 if the data channel value' 10 ...
                  'is larger than 3, and 0 otherwise).' ] } ...
			   { 'style' 'edit' 'string' '' } { 'style' 'text' 'string' 'Optional. Ex: X>3' } ...
			   { 'style' 'text' 'string' 'Transitions to extract? (up|down)' 'tooltipstring' ...
				 [ 'Extract events whenever values in the (transformed) event channel(s) shift up' 10 ...
				   '(''leading''), down (''trailing'') or either (''both'').' 10 ...
				   'AFTER SCROLLING CLICK TO SELECT' ] } ...
			   { 'style' 'listbox' 'string' 'up (leading)|both|down (trailing)' 'value' 1 'callback' cb_list } ...
               { 'style' 'text' 'string' '(click to select)'} ...
			   { 'style' 'text' 'string' 'Transition length (1=perfect edges)' 'tooltipstring'  ...
                 [ 'Increase this number to avoid having events very close to each other due.' 10 ...
                   'to a not perfectly straight edge' ] } ...
			   { 'style' 'edit' 'string' '0' } { } ...
			   { 'style' 'text' 'string' 'Assign duration to each events?' 'tag' 'dur' 'tooltipstring' ...
				 [ 'You may assign an event duration to each event if you select to detect' 10 ...
				   'event on the leading edge above. Event will last as long as the signal is non-0.' ] } ...
			   { 'style' 'checkbox' 'string' '' 'value' 0 'tag' 'dur'} { } ...
               { 'style' 'text' 'string' '(set=yes)' } ...
               {} ...
               { 'style' 'text' 'string' 'Delete event channel(s)? ' } ...
			   { 'style' 'checkbox' 'value' 1 } { 'style' 'text' 'string' '        (set = yes)'} ...
			   { 'style' 'text' 'string' 'Delete old events if any? ' } ...
			   { 'style' 'checkbox' 'value' 1 } { } ...
			   { 'style' 'text' 'string' 'All events of same type? ' 'tooltipstring' ...
			    ['If set, all transitions are considered the same event type,' 10 ...
				 'If unset, each (transformed) event channel value following a transition' 10 ...
                 'determines an event type (Ex: Detecting leading-edge transitions of' 10 ...
                 '0 0 1 0 2 0 ...  produces event types 1 and 2).' ] } ...
			   { 'style' 'checkbox' 'value' 0 } { } };
	result       = inputgui( geometry, strgui, 'pophelp(''pop_chanevent'');', 'Extract event from channel(s) - pop_chanevent()');

	if length(result) == 0 return; end;
	chan   = eval( [ '[' result{1} ']' ] );
    options = {};
	if ~isempty(result{2}), options = { options{:} 'oper' result{2} }; end;
	switch result{3},
		case 1, options = { options{:} 'edge' 'leading' };
		case 2, options = { options{:} 'edge' 'both' };
		case 3, options = { options{:} 'edge' 'trailing' };
	end;
    options = { options{:} 'edgelen' eval( [ '[' result{4} ']' ] ) };
    if result{5},  options = { options{:} 'duration' 'on' }; end;
	if ~result{6}, options = { options{:} 'delchan'  'off'}; end;
	if ~result{7}, options = { options{:} 'delevent' 'off'}; end;
	if result{8},  options = { options{:} 'nbtype'  1}; end;
else
    options = varargin;
end;
listcheck = { 'edge'      'string'     { 'both' 'leading' 'trailing'}     'both';
              'edgelen'   'integer'    [1 Inf]                            1;
              'delchan'   'string'     { 'on' 'off' }                     'on';
              'oper'      'string'     []                                 '';
              'delevent'  'string'     { 'on' 'off' }                     'on';
              'duration'  'string'     { 'on' 'off' }                     'off';
              'typename'  'string'     []                                 [ 'chan' int2str(chan) ];
              'nbtype'    'integer'    [1 NaN]                             NaN };
g = finputcheck( options, listcheck, 'pop_chanedit');
if isstr(g), error(g); end;

% check inut consistency
% ----------------------
if strcmpi(g.duration, 'on') & ~strcmpi(g.edge, 'leading')
    error('Must detect leading edge to extract event duration');
end;

% process events
% --------------
fprintf('pop_chanevent: importing events from data channel %d ...\n', chan);
counte = 1; % event counter
events(10000).latency = 0;
if isnan(g.nbtype)
    if length(unique(EEG.data(chan, :))) == 2, g.nbtype = 1; end;
end;

for ci = chan
    X = EEG.data(ci, :);

    % apply preprocessing
    % -------------------
    if ~isempty(g.oper)
        try, eval( [ 'X = ' g.oper ';' ]);
        catch, error('pop_chanevent: error executing preprocessing string');
        end;
    end;

    % extract edges
    % -------------
    tmpdiff =  diff(abs([ X X(end) ]));
    switch g.edge
     case 'both'    , tmpevent1 = find( tmpdiff > 0)-1; tmpevent2 = find( tmpdiff < 0);
     case 'trailing', tmpevent2 = find( tmpdiff < 0);
     case 'leading' , tmpevent1 = find( tmpdiff > 0)-1; tmpdur = find( tmpdiff < 0);
    end;

    % fuse close events if necessary
    % ------------------------------
    if exist('tmpevent1')
        tmpclose = find( tmpevent1(2:end)-tmpevent1(1:end-1) < g.edgelen)+1;
        tmpevent1(tmpclose) = [];
        tmpevent    = tmpevent1+1;
        tmpeventval = tmpevent1+2;
    end;
    if exist('tmpevent2')
        tmpclose = find( tmpevent2(2:end)-tmpevent2(1:end-1) < g.edgelen); % not +1
        tmpevent2(tmpclose) = [];
        tmpevent    = tmpevent2+1;
        tmpeventval = tmpevent2;
    end;
    if exist('tmpevent1') & exist('tmpevent2')
        tmpevent    = sort([ tmpevent1+1 tmpevent2+1]);
        tmpeventval = sort([ tmpevent1+2 tmpevent2]);
    end;

    % adjust edges for duration  if necessary
    % ---------------------------------------
    if strcmpi(g.duration, 'on')
        tmpclose = find( tmpdur(2:end)-tmpdur(1:end-1) < g.edgelen); % not +1 (take out the first)
        tmpdur(tmpclose) = [];
        if tmpdur(1) < tmpevent(1), tmpdur(1) = []; end;
        if length(tmpevent) > length(tmpdur), tmpdur(end+1) = EEG.pnts; end;
        if length(tmpevent) ~= length(tmpdur)
            error([ 'Error while attempting to extract event durations' 10 ...
                    'Maybe edges are not perfectly defined, try increasing edge length' ]);
        end;
    end;

    if isempty(tmpevent),
        fprintf('No event found for channel %d\n', ci);
    else
        for tmpi = 1:length(tmpevent)
            if ~isnan(g.nbtype)
                events(counte).type    = g.typename;
            else
                events(counte).type    = X(tmpeventval(tmpi));
            end;
            events(counte).latency = tmpevent(tmpi);
            if strcmpi(g.duration, 'on')
                events(counte).duration = tmpdur(tmpi) - tmpevent(tmpi);
            end;
            counte = counte+1;
        end;
    end;
    events = events(1:counte-1);
end;

% resort events
% --------------
if strcmp(g.delevent, 'on')
	EEG.event = events;
    if EEG.trials > 1
        for index = 1:length(events)
            EEG.event(index).epoch = 1+floor((EEG.event(index).latency-1) / EEG.pnts);
        end;
    end;
else
	for index = 1:length(events)
		EEG.event(end+1).type  = events(index).type;
		EEG.event(end).latency = events(index).latency;
        if EEG.trials > 1 | isfield(EEG.event, 'epoch');
            EEG.event(end).epoch = 1+floor((EEG.event(end).latency-1) / EEG.pnts);
        end;
	end;
    if EEG.trials > 1
        EEG = pop_editeventvals( EEG, 'sort', {  'epoch' 0 'latency', [0] } );
    else
        EEG = pop_editeventvals( EEG, 'sort', { 'latency', [0] } );
    end;
end;
if isfield(EEG.event, 'urevent'), EEG.event = rmfield(EEG.event, 'urevent'); end;
EEG = eeg_checkset(EEG, 'eventconsistency');
EEG = eeg_checkset(EEG, 'makeur');

% delete channels
% ---------------
if strcmp(g.delchan, 'on')
	EEG = pop_select(EEG, 'nochannel', chan);
end;

if nargin < 2
    command = sprintf('%s = pop_chanevent(%s, %s);', inputname(1), inputname(1), ...
                      vararg2str({ chan options{:} }));
end;
return;


function MeshStruct = read_gmsh(fileName)

T=txtfile2cell(fileName);

start_physicals =  find(contains(T,'$PhysicalNames'));
start_entities = find(contains(T,'$Entities'));
start_nodes = find(contains(T,'$Nodes'));
start_elements = find(contains(T,'$Elements'));

entity_info = str2num(T{start_entities+1});
node_info = str2num(T{start_nodes+1});
element_info = str2num(T{start_elements+1});

num_nodes = node_info(2);
num_node_blocks = node_info(1);
num_elements = element_info(2);
num_element_blocks = element_info(1);
num_entities = sum(entity_info);

%%%read physicals
num_physicals = str2num(T{start_physicals+1});
Physicals = T(start_physicals+2:start_physicals+1+num_physicals);
for i = 1:size(Physicals, 1)
    Physicals{i} = strsplit(Physicals{i},' ');
    Physicals{i}{1} = str2num(Physicals{i}{1});
    Physicals{i}{2} = str2num(Physicals{i}{2});
end

%%%read and sort entities
Entities = cell(4,1);
Points = {};Curves = {};Surfaces = {};Volumes = {};
line = start_entities+2;
for i = 1:entity_info(1)
    Temp = str2num(T{line});
    Points{i,1} = Temp;
    line = line+1;
end
for i = 1:entity_info(2)
    Temp = str2num(T{line});
    Curves{i,1} = Temp;
    line = line+1;
end
for i = 1:entity_info(3)
    Temp =  str2num(T{line});
    Surfaces{i,1} = Temp;
    line = line+1;
end
for i = 1:entity_info(4)
    Temp = str2num(T{line});
    Volumes{i,1} = Temp;
    line = line+1;
end
Entities{1} = Points;
Entities{2} = Curves;
Entities{3} = Surfaces;
Entities{4} = Volumes;

%%%read and sort nodes
node_block_info = zeros(num_node_blocks,4);
node_block_numbers = cell(num_node_blocks,1);
node_block_coords = cell(num_node_blocks,1);
line = start_nodes+2;
for i = 1:num_node_blocks

    node_block_info_i = str2num(T{line});
    node_block_size= node_block_info_i(1,4);

    node_block_info(i,:) = node_block_info_i;
    node_block_numbers_temp = T(line+1:line+node_block_size);
    node_block_coords_temp = T(line+node_block_size +1:line+node_block_size+node_block_size);
    line = line+2*node_block_size+1;

    for j = 1:node_block_size
        node_block_numbers{i}(j,:) = str2num(node_block_numbers_temp{j});
        node_block_coords{i}(j,:) = str2num(node_block_coords_temp{j});
    end

end

%%%Read and sort elements
element_block_info = zeros(num_element_blocks,4);
element_block_numbers = cell(num_element_blocks,1);
line = start_elements+2;
for i = 1:num_element_blocks

    element_block_info_i = str2num(T{line});element_block_size= element_block_info_i(1,4);
    element_block_info(i,:) = element_block_info_i;
    element_block_numbers_temp = T(line+1:line+element_block_size);

    for j = 1:element_block_size
        element_block_numbers{i}(j,:) = str2num(element_block_numbers_temp{j});
    end

    line = line+element_block_size+1;
end

node_ids = [];
nodes = [];
for i = 1:num_node_blocks

    nodes = [nodes;node_block_coords{i}];
    node_ids = [node_ids;node_block_numbers{i}];

end

nodes = double(nodes);
Mesh.Physicals = Physicals;
Mesh.entity_info = entity_info;
Mesh.node_info = node_info;
Mesh.element_info = element_info;
Mesh.nodes = nodes;
Mesh.Node_Blocks = node_block_numbers;
Mesh.Node_ids = node_ids;
Mesh.node_block_info = node_block_info;
Mesh.Entities = Entities;
Mesh.Elements = element_block_numbers;
Mesh.element_block_info = element_block_info;

%%
vol_ct = 0;
surf_ct = 0;
curve_ct= 0;

[~,part_name,~] = fileparts(fileName);

 node_ids = Mesh.Node_ids; %The node id's
 nodes = Mesh.nodes; %The nodel coordinates

 %%

for j = 1:size(Mesh.Physicals,1)

    physical = Mesh.Physicals{j};
    phys_name = physical{3}(2:end-1);
    dim = physical{1};
    tag = physical{2};

    switch dim
        case 3

            vol_ct = vol_ct+1;
            entities = Mesh.Entities{4,1};
            element_ids = [];
            element_mat = [];

            for k = 1:size(entities, 1)
                num_phys = entities{k}(8);
                phys_tags = entities{k}(9:9+num_phys-1);
                if sum(find(phys_tags==tag))
                   entity_tag = entities{k}(1);
                   elements_3 = (Mesh.element_block_info(:,1) == dim).*Mesh.element_block_info;
                   entity_ind = find(elements_3(:,2)==entity_tag);
                   element_ids = [element_ids;Mesh.Elements{entity_ind}(:,1)];
                   element_mat = [element_mat;Mesh.Elements{entity_ind}(:,2:end)];
                end

            end

            %febio_spec.Mesh.Elements{vol_ct}.ATTR.type='tet4'; %Element type
            volumes_names{vol_ct,1} = phys_name; %Name of this part
            elements_IDs_blocks{vol_ct} = element_ids; %Element id's
            elements_blocks{vol_ct} = element_mat; %The element matrix

        case 2

            surf_ct = surf_ct+1;
            entities = Mesh.Entities{3,1};
            element_mat = [];
            element_start = 0;

            for k = 1:size(entities, 1)
                num_phys = entities{k}(8);
                phys_tags = entities{k}(9:9+num_phys-1);
                if sum(find(phys_tags==tag))
                   entity_tag = entities{k}(1);
                   elements_2 = (Mesh.element_block_info(:,1) == dim).*(Mesh.element_block_info(:,2) == entity_tag);
                   entity_ind = find(elements_2);
                   element_mat = [element_mat;Mesh.Elements{entity_ind}(:,2:end)];
                   element_start = element_start+1;
                   element_start = element_start+size(element_mat,1);
                end

            end

            element_ids = [1:size(element_mat,1)]';
            facesBoundary_Names{surf_ct,1} = phys_name; %Name of this surface
            facesBoundary_IDs_Block{surf_ct} = element_ids; %Element id's
            facesBoundary_Block{surf_ct} =element_mat; %The element matrix

            case 1

            curve_ct = curve_ct+1;
            entities = Mesh.Entities{2,1};
            element_mat = [];
            element_start = 0;

            for k = 1:size(entities, 1)
                num_phys = entities{k}(8);
                phys_tags = entities{k}(9:9+num_phys-1);
                if sum(find(phys_tags==tag))
                   entity_tag = entities{k}(1);
                   elements_1 = (Mesh.element_block_info(:,1) == dim).*(Mesh.element_block_info(:,2) == entity_tag);
                   entity_ind = find(elements_1);
                   element_mat = [element_mat;Mesh.Elements{entity_ind}(:,2:end)];
                   element_start = element_start+1;
                   element_start = element_start+size(element_mat,1);
                end

            end

             element_ids_block{curve_ct} = element_mat(:,1);
             curve_names{curve_ct} = phys_name; %Name of this curve
             curve_elements_block{curve_ct} = element_ids; %Element id's

   end
end

%%
facesBoundary = [];
boundaryMarker = [];
elements = [];
elementsMaterialID = [];

%%
for i = 1:vol_ct

    elementMaterialID_block = ones(length(elements_IDs_blocks{i}),1).*i;
    elements = [elements;elements_blocks{i}];
    elementsMaterialID = [elementsMaterialID;elementMaterialID_block];

end

for i = 1:surf_ct

    boundaryMarker_block = ones(length(facesBoundary_IDs_Block{i}),1).*i;
    facesBoundary = [facesBoundary;facesBoundary_Block{i}];
    boundaryMarker = [boundaryMarker;boundaryMarker_block];

end

% for i = 1:curve_ct
%
% end

MeshStruct.node_IDs = node_ids;
MeshStruct.nodes = nodes;
MeshStruct.facesBoundary = facesBoundary;
MeshStruct.boundaryMarker = boundaryMarker;
MeshStruct.elements = elements;
MeshStruct.elementMaterialID = elementsMaterialID;
MeshStruct.loadNameStruct.MeshName = part_name;
MeshStruct.loadNameStruct.VolumeNames = volumes_names;
MeshStruct.loadNameStruct.SurfaceNames = facesBoundary_Names;

%                 nodes: [415×3 double]
%         facesBoundary: [320×3 double]
%        boundaryMarker: [320×1 double]
%                 faces: [8144×3 double]
%              elements: [2036×4 double]
%     elementMaterialID: [2036×1 double]
%        faceMaterialID: [8144×1 double]
%        loadNameStruct: [1×1 struct]

%%
% _*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/>.


classdef PluginConstraint < AbstractConstraint
    %PluginConstraint Summary of this class goes here
    %   Detailed explanation goes here

    properties
        normFact = 1;
        plugin LvdPlugin
        event LaunchVehicleEvent
        eventNode(1,1) ConstraintStateComparisonNodeEnum = ConstraintStateComparisonNodeEnum.FinalState;

        lb(1,1) double = 0;
        ub(1,1) double = 0;

        evalType(1,1) ConstraintEvalTypeEnum = ConstraintEvalTypeEnum.FixedBounds;
        stateCompType(1,1) ConstraintStateComparisonTypeEnum = ConstraintStateComparisonTypeEnum.Equals;
        stateCompEvent LaunchVehicleEvent
        stateCompNode(1,1) ConstraintStateComparisonNodeEnum = ConstraintStateComparisonNodeEnum.FinalState;
    end

    methods
        function obj = PluginConstraint(plugin, event, lb, ub)
            obj.plugin = plugin;
            obj.event = event;
            obj.lb = lb;
            obj.ub = ub;

             obj.id = rand();
        end

        function [lb, ub] = getBounds(obj)
            lb = obj.lb;
            ub = obj.ub;
        end

        function [c, ceq, value, lwrBnd, uprBnd, type, eventNum, valueStateComp] = evalConstraint(obj, stateLog, celBodyData)
            type = obj.getConstraintType();

            switch obj.eventNode
                case ConstraintStateComparisonNodeEnum.FinalState
                    stateLogEntry = stateLog.getLastStateLogForEvent(obj.event);

                case ConstraintStateComparisonNodeEnum.InitialState
                    stateLogEntry = stateLog.getFirstStateLogForEvent(obj.event);

                otherwise
                    error('Unknown event node.');
            end

            if(not(isempty(obj.frame)))
                frame = obj.frame;
            else
                frame = stateLogEntry.centralBody.getBodyCenteredInertialFrame();
            end

            lvdData = stateLogEntry.lvdData;
            pluginSet = lvdData.plugins;
            value = obj.plugin.executePlugin(stateLogEntry.lvdData, stateLog, obj.event, LvdPluginExecLocEnum.Constraint, [],[],[], pluginSet.userData, stateLogEntry, frame);

            if(obj.evalType == ConstraintEvalTypeEnum.StateComparison)
                switch obj.stateCompNode
                    case ConstraintStateComparisonNodeEnum.FinalState
                        stateLogEntryStateComp = stateLog.getLastStateLogForEvent(obj.stateCompEvent);

                    case ConstraintStateComparisonNodeEnum.InitialState
                        stateLogEntryStateComp = stateLog.getFirstStateLogForEvent(obj.stateCompEvent);

                    otherwise
                        error('Unknown event node.');
                end

                valueStateComp = obj.plugin.executePlugin(lvdData, stateLog, obj.event, LvdPluginExecLocEnum.Constraint, [],[],[], pluginSet.userData, stateLogEntryStateComp, frame);
            else
                valueStateComp = NaN;
            end

            [c, ceq] = obj.computeCAndCeqValues(value, valueStateComp);

            lwrBnd = obj.lb;
            uprBnd = obj.ub;

            eventNum = obj.event.getEventNum();
        end

        function sF = getScaleFactor(obj)
            sF = obj.normFact;
        end

        function setScaleFactor(obj, sF)
            obj.normFact = sF;
        end

        function tf = usesStage(obj, stage)
            tf = false;
        end

        function tf = usesEngine(obj, engine)
            tf = false;
        end

        function tf = usesTank(obj, tank)
            tf = false;
        end

        function tf = usesEngineToTankConn(obj, engineToTank)
            tf = false;
        end

        function tf = usesEvent(obj, event)
            tf = obj.event == event;
            if(obj.evalType == ConstraintEvalTypeEnum.StateComparison)
                tf = tf || obj.stateCompEvent == event;
            end
        end

        function tf = usesStopwatch(obj, stopwatch)
            tf = false;
        end

        function tf = usesExtremum(obj, extremum)
            tf = false;
        end

        function tf = usesGroundObj(obj, grdObj)
            tf = false;
        end

        function tf = usesPlugin(obj, plugin)
            tf = obj.plugin == plugin;
        end

        function tf = canUseSparseOutput(obj)
            tf = true;
        end

        function event = getConstraintEvent(obj)
            event = obj.event;
        end

        function type = getConstraintType(obj)
            type = 'Plugin Value';
        end

        function [unit, lbLim, ubLim, usesLbUb, usesCelBody, usesRefSc] = getConstraintStaticDetails(obj)
            unit = ''; %TODO: Need to come up with a way to populate this I think?
            lbLim = -Inf;
            ubLim = Inf;
            usesLbUb = true;
            usesCelBody = false;
            usesRefSc = false;
        end

        function addConstraintTf = openEditConstraintUI(obj, lvdData)
            if(lvdData.plugins.getNumPlugins() >= 1)
%                 addConstraintTf = lvd_EditPluginConstraintGUI(obj, lvdData);

                output = AppDesignerGUIOutput({false});
                lvd_EditPluginConstraintGUI_App(obj, lvdData, output);
                addConstraintTf = output.output{1};
            else
                errordlg('There are currently no plugins in this scenario.  Create at least one new plugin first.');

                addConstraintTf = false;
            end
        end

        function plugin = selectConstraintObj(obj, lvdData)
            [listBoxStr, plugins] = lvdData.plugins.getListboxStr();

            plugin = [];
            if(isempty(plugins))
                warndlg('Cannot create plugin value object: no plugins have been created.  Create a plugin first.','Plugin Value Constraint','modal');
            else
                [Selection,ok] = listdlg('PromptString',{'Select a plugin:'},...
                                'SelectionMode','single',...
                                'Name','Plugins',...
                                'ListString',listBoxStr);

                if(ok == 0)
                    plugin = [];
                else
                    plugin = plugins(Selection);
                end
            end
        end

        function useObjFcn = setupForUseAsObjectiveFcn(obj,lvdData)
            pluginSel = obj.selectConstraintObj(lvdData);

            if(not(isempty(pluginSel)))
                obj.plugin = pluginSel;
                useObjFcn = true;
            else
                useObjFcn = false;
            end
        end
    end

    methods(Static)
        function constraint = getDefaultConstraint(~, ~)
            constraint = PluginConstraint(LvdPlugin.empty(1,0), LaunchVehicleEvent.empty(1,0), 0, 0);
        end
    end
end


function QRS = run_qrsdet_by_seg(ecg,HRVparams)
% this function is used to run the QRS detector for each window window (non overlapping)
% this is needed because in the case of big artefacts at the begining of
% the record (i.e. where the P&T threshold is computed) it can make the detection fail.
%
% inputs
%   ecg:        ecg signal
%   fs:         sampling frequency
%   window:     size of the window onto which to perform QRS detection (in seconds)
%   thres:      threshold to be used
%   ecgType:    'FECG' or 'MECG'
%
% output
%   QRS:        QRS location in nb samples (ms)
%
%
% FECG-ESN toolbox, version 1.0
% Released under the GNU General Public License
%
% Copyright (C) 2014  Joachim Behar
% Oxford university, Intelligent Patient Monitoring Group
% joachim.behar@eng.ox.ac.uk
%
% Last updated : 28-01-2014
%
% 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 2 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.
%
%
% 12-07-2017 Modified by Giulia Da Poian to be used with VOSIM HRV Toolbox
%            use HRVparsms struct

% == managing inputs
if nargin<2; error('run_qrsdet_by_seg: wrong number of input arguments \n'); end;

fs = HRVparams.Fs;
window = HRVparams.PeakDetect.windows;
thres = HRVparams.PeakDetect.THRES;
ecgType = HRVparams.PeakDetect.ecgType;

% == general
segsizeSamp = window*fs; % convert window into nb of samples
NbSeg = floor(length(ecg)/segsizeSamp); % nb of segments
QRS = [];
start = 1;
stop  = segsizeSamp;
signForce = 0; % if we want to force the sign of the peak we are looking for

% == core function
try
    for ch=1:NbSeg
        % for each segment perform QRS detection
        QRStemp = 0;

        % take +/-1sec around selected subsegment exept for the borders. This
        % is in case there is a QRS in between segments -> allows to locate
        % them well.
        if ch==1
            % first subsegment
            dTplus  = fs;
            dTminus = 0;
        elseif ch==NbSeg
            % last subsegment
            dTplus  = 0;
            dTminus = fs;
        else
            % any other subsegment
            dTplus  = fs;
            dTminus = fs;
        end

        % lowering the threshold in case not enough beats are
        % detected. Also changed the refractory period to be different between
        % mother and foetus. sign of peaks is determined by the sign on the
        % first window and then is forced for the following windows.
        if strcmp(ecgType,'FECG')
            thresTrans = thres;
            while length(QRStemp)<20 && thresTrans>0.1
                [QRStemp,signForce] = jqrs(ecg(start-dTminus:stop+dTplus),HRVparams);
                thresTrans = thresTrans-0.1;
            end
        else
            [QRStemp,signForce] = jqrs(ecg(start-dTminus:stop+dTplus),HRVparams);
        end

        NewQRS = (start-1)-dTminus+QRStemp;
        NewQRS(NewQRS>stop) = [];
        NewQRS(NewQRS<start) = [];

        if ~isempty(QRS) && ~isempty(NewQRS) && NewQRS(1)-QRS(end)<0.25*fs
            % this is needed to avoid double detection at the transition point
            % between two windows
            NewQRS(1) = [];
        end
        QRS = [QRS NewQRS];

        start = start+segsizeSamp;
        stop = stop+segsizeSamp;
    end

catch ME
    for enb=1:length(ME.stack); disp(ME.stack(enb)); end;
    QRS = [1000 2000];
    rethrow(ME);
end

end


function [mri] = align_neuromag2acpc(mri, method, template)

% ALIGN_NEUROMAG2ACPC performs an approximate alignment of the anatomical
% volume from NEUROMAG towards ACPC coordinates. Only the homogenous transformation
% matrix is modified and the coordsys-field is updated.
%
% Use as
%   mri = align_neuromag2acpc(mri)
%   mri = align_neuromag2acpc(mri, method)
%   mri = align_neuromag2acpc(mri, method, template)
%
% The first input argument is a FieldTrip MRI-structure, and the second optional
% argument specifies how the registration is to be done:
%   method = 0: only an approximate coregistration
%   method = 1: an approximate coregistration, followed by spm_affreg
%   method = 2: an approximate coregistration, followed by spm_normalise (default)
%
% When method = 1 or 2, an optional template filename can be specified, which denotes
% the filename of the target volume. This is required when running in deployed
% mode.
%
% See also ALIGN_CTF2ACPC, ALIGN_FSAVERAGE2MNI

if nargin<2
  method = 2;
end

%--------------------------------------------------------------------------
% do a first round of approximate coregistration using the predefined voxel
% locations of the fiducials and landmarks in the template T1 image from
% SPM

acpcvox2acpchead = [
  2     0     0   -92
  0     2     0  -128
  0     0     2   -74
  0     0     0     1
  ];

% these are the voxel indices of some points in the SPM canonical T1
acpcvox_Ac           = [46 64  37  1]';     % the anterior commissure
acpcvox_Ori          = [46 48  10  1]';     % approximately between the ears in T1.mnc
acpcvox_Nas          = [46 106 13  1]';     % approximately the nasion in T1.mnc
acpcvox_Lpa_canal    = [ 5 48  10  1]';     % Left ear canal
acpcvox_Rpa_canal    = [87 48  10  1]';     % Right ear canal

acpchead_Ac           = acpcvox2acpchead * acpcvox_Ac  ;
acpchead_Ori          = acpcvox2acpchead * acpcvox_Ori ;
acpchead_Nas          = acpcvox2acpchead * acpcvox_Nas ;
acpchead_Lpa_canal    = acpcvox2acpchead * acpcvox_Lpa_canal ;
acpchead_Rpa_canal    = acpcvox2acpchead * acpcvox_Rpa_canal ;

neuromagvox2neuromaghead  = mri.transform;
acpchead2neuromaghead     = ft_headcoordinates(acpchead_Nas(1:3), acpchead_Lpa_canal(1:3), acpchead_Rpa_canal(1:3), 'neuromag');

%neuromagvox2acpchead =  inv(acpchead2neuromaghead) * neuromagvox2neuromaghead;
neuromagvox2acpchead  =  acpchead2neuromaghead \ neuromagvox2neuromaghead;

% change the transformation matrix, such that it returns approximate SPM head coordinates
mri.transform     = neuromagvox2acpchead;
mri.vox2headOrig  = neuromagvox2neuromaghead;
mri.vox2head      = neuromagvox2acpchead;
mri.head2headOrig = acpchead2neuromaghead;
mri.coordsys      = 'acpc';

if method>0
  % this requires SPM to be on the path. However, this is not the proper place to
  % choose between SPM versions. The user can either use cfg.spmversion in a high-level
  % function, or has to add the path to the desired SPM version by hand.
  ft_hastoolbox('spm', -1);
end

%--------------------------------------------------------------------------
% Do a second round of affine registration (rigid body) to get improved
% alignment with ACPC coordinate system. this is needed because there may be
% different conventions defining LPA and RPA. The affine registration may
% fail however, e.g. if the initial alignment is not close enough. In that
% case SPM will throw an error

if method==1
  % use spm_affreg

  switch lower(spm('ver'))
    case 'spm2'
      if isdeployed
        if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using method==1'); end
      else
        template = fullfile(spm('Dir'),'templates','T1.mnc');
      end

    case 'spm8'
      if isdeployed
        if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using method==1'); end
      else
        template = fullfile(spm('Dir'),'templates','T1.nii');
      end

    case 'spm12'
      if isdeployed
        if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using method==1'); end
      else
        template = fullfile(spm('Dir'),'toolbox','OldNorm','T1.nii');
        if ~exist('spm_affreg', 'file')
          addpath(fullfile(spm('Dir'),'toolbox','OldNorm'));
        end
      end
      fprintf('using ''OldNorm'' affine registration\n');

    otherwise
      ft_error('unsupported SPM version');
  end
  mri2 = ft_read_mri(template);

  tname1 = [tempname, '.img'];
  tname2 = [tempname, '.img'];
  V1 = ft_write_mri(tname1, mri.anatomy,  'transform', mri.transform,  'spmversion', spm('ver'), 'dataformat', 'nifti_spm');
  V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm');

  % the below, using just spm_affreg does not work robustly enough in some cases
  flags.regtype = 'rigid';
  [M, scale]    = spm_affreg(V1,V2,flags);

  % some juggling around with the transformation matrices
  neuromagvox2acpchead2  = M \ V1.mat;
  acpchead2neuromaghead2 = neuromagvox2neuromaghead / neuromagvox2acpchead2;

  % update the transformation matrix
  mri.transform     = neuromagvox2acpchead2;

  % this one is unchanged
  mri.vox2headOrig  = neuromagvox2neuromaghead;

  % these are new
  mri.vox2head      = neuromagvox2acpchead2;
  mri.head2headOrig = acpchead2neuromaghead2;

  % delete the temporary files
  delete(tname1); delete(strrep(tname1, 'img', 'hdr'));
  delete(tname2); delete(strrep(tname2, 'img', 'hdr'));

elseif method==2
  % use spm_normalise

  switch lower(spm('ver'))
    case 'spm2'
      if isdeployed
        if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using method==2'); end
      else
        template = fullfile(spm('Dir'),'templates','T1.mnc');
      end

    case 'spm8'
      if isdeployed
        if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using method==2'); end
      else
        template = fullfile(spm('Dir'),'templates','T1.nii');
      end

    case 'spm12'
      % this uses the 'OldNorm' functionality, so the path needs to be
      % added, can only be done if non-deployed.
      if isdeployed
        if nargin<3, ft_error('you need to specify a template filename when in deployed mode and using method==2'); end
      else
        template = fullfile(spm('Dir'),'toolbox','OldNorm','T1.nii');
        if ~exist('spm_normalise', 'file')
          addpath(fullfile(spm('Dir'),'toolbox','OldNorm'));
        end
      end
      fprintf('using ''OldNorm'' normalisation\n');

    otherwise
      ft_error('unsupported SPM version');
  end
  mri2 = ft_read_mri(template);

  tname1 = [tempname, '.img'];
  tname2 = [tempname, '.img'];
  V1 = ft_write_mri(tname1, mri.anatomy,  'transform', mri.transform,  'spmversion', spm('ver'), 'dataformat', 'nifti_spm');
  V2 = ft_write_mri(tname2, mri2.anatomy, 'transform', mri2.transform, 'spmversion', spm('ver'), 'dataformat', 'nifti_spm');

  flags.nits       = 0; %set number of non-linear iterations to zero
  flags.regtype    = 'rigid';
  params           = spm_normalise(V2,V1,[],[],[],flags);
  acpchead2neuromaghead2 = acpchead2neuromaghead*V1.mat*params.Affine/V2.mat;
  neuromagvox2acpchead2  = acpchead2neuromaghead2\neuromagvox2neuromaghead;

  % update the transformation matrix
  mri.transform     = neuromagvox2acpchead2;

  % this one is unchanged
  mri.vox2headOrig  = neuromagvox2neuromaghead;

  % these are new
  mri.vox2head      = neuromagvox2acpchead2;
  mri.head2headOrig = acpchead2neuromaghead2;

  % delete the temporary files
  delete(tname1); delete(strrep(tname1, 'img', 'hdr'));
  delete(tname2); delete(strrep(tname2, 'img', 'hdr'));
end


% KALMAN_FILTER - Under construction..

function [X, CovX] = kalman_filter_old(measurement, ...
                                   transition_matrix, ...
                                   process_noise, ...
                                   measurement_model_matrix, ...
                                   measurement_noise, ...
                                   x, ...
                                   C)

warning('This function is deprecated')

error('Not ready yet..')
return

N = 0;
D = 1000;

X = zeros(D,N);
if nargout >= 2
  CovX = zeros(D,D,10);
end

for n=1:N
  % Get the parameters
  A = transition_matrix(n);
  Q = process_noise(n);
  y = measurement(n);
  H = measurement_model_matrix(n);
  R = measurement_noise(n);

  % Prediction step
  x = A*x;
  C = A*C*A' + Q;

  % Update step
  if length(y) < D
    v = y - H*x;
    S = H*C*H' + R;
    K = C*H'/S;
    x = m + K*v;
    C = C - K*S*K';
  else
    K = C*H';
    L = chol(C +
  end

  % Store the distribution
  X(:,n) = x;
  if nargout >= 2
    CovX(:,:,n) = C;
  end
end


function nPhysioRegressors = tapas_physio_count_physio_regressors(physio)
% Returns number of physiological regressors created, given model
% specification;
% NOTE: only reproducible numbers (data-independent) are
% returned, i.e. session-specific movement spikes and %-variance explained
% PCA-components are not included
%
% IN
%   physio  physio-structure, See also tapas_physio_new
%
% OUT
% nPhysioRegressors     number of physiological regressors, e.g. motion,
%                       retroicor, noise_rois
%                       but: ignores
%
% EXAMPLE
%   tapas_physio_report_contrasts
%
%   See also

% Author: Lars Kasper
% Created: 2014-10-16
% Copyright (C) 2014 TNU, Institute for Biomedical Engineering, University of Zurich and ETH Zurich.
%
% This file is part of the TAPAS PhysIO Toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

model = physio.model;

nPhysioRegressors = 0;

if model.hrv.include
    nPhysioRegressors = nPhysioRegressors + numel(model.hrv.delays);
end

if model.rvt.include
    nPhysioRegressors = nPhysioRegressors + numel(model.rvt.delays);
end

if model.retroicor.include
    order = model.retroicor.order;
    nPhysioRegressors = nPhysioRegressors + ...
        2*order.c + ...
        2*order.r + ...
        4* order.cr;
end

if model.noise_rois.include
    % TODO: what if number of components implicit?...shall we save this?
    nPhysioRegressors = nPhysioRegressors + ...
        numel(model.noise_rois.roi_files)*ceil(model.noise_rois.n_components+1); % + 1 for mean
end

if model.movement.include
    % TODO: what about variable regressors, that should not be
    % concatenated, e.g. movement outlier censoring
    nPhysioRegressors = nPhysioRegressors + model.movement.order;
end

end


function [success,qj,okay,kk]=checksignres_inc_other_shocks(qj,fj,Scell,okay,IRFt,n)

if IRFt==4
kk=1;
elseif IRFt==6
kk=2; % first IV shock is okay
end

check=0;
while check==0
        Sjcheck=Scell{1,kk};
        if isempty(Sjcheck) && okay(kk,1)==0 %if we get a not yet filled unrestricted column
            okay(kk,1)=1; %switch okay vector to 1
            success=1;
            check=1;
            qj=qj;
        elseif ~isempty(Sjcheck) && all(Sjcheck*fj>=0) && okay(kk,1)==0
            okay(kk,1)=1; %switch okay vector to 1
            success=1;
            check=1;
            qj=qj;
        elseif ~isempty(Sjcheck) && all(Sjcheck*(-fj)>=0) && okay(kk,1)==0
            okay(kk,1)=1; %switch okay vector to 1
            success=1;
            check=1;
            qj=-qj;
         else
            check=0;
            kk=kk+1;
       end
         if kk>n %if kk > n stop the loop as it failed
            success=0;
            check=1;
         end
end


% op_concatSubspecs.m
% Jamie Near, McGill University 2014.
%
% USAGE:
% out=op_concatSubspecs(in1,in2);
%
% DESCRIPTION:
% Concatenate two scans along the subspecs dimension.  Two scans with 50
% averages each will now look like a single scan with 100 averages.
%
% INPUTS:
% in1    = first input in matlab structure format.
% in2    = second input in matlab structure format.
%
% OUTPUTS:
% out    = Output following concatenation along the subspecs dimension.

function out=op_concatSubspecs(in1,in2);

if in1.dims.subSpecs ~= in2.dims.subSpecs || in1.dims.t ~= in2.dims.t || in1.dims.coils ~= in2.dims.coils || in1.dims.averages ~=in2.dims.averages
    error('subSpecs dimensions must be the same for both inputs');
end

%if subspecs dimension is zero, make a new dimension for them
if in1.dims.subSpecs==0
    newSubspecsDim=max([in1.dims.t in1.dims.coils in1.dims.averages in1.dims.subSpecs in1.dims.extras])+1;
else
    newSubspecsDim=in1.dims.subSpecs;
end

fids=cat(newSubspecsDim,in1.fids,in2.fids);
specs=cat(newSubspecsDim,in1.specs,in2.specs);
sz=size(fids);

%FILLING IN DATA STRUCTURE
out=in1;
out.fids=fids;
out.specs=specs;
out.sz=sz;
out.dims=in1.dims;
out.dims.subSpecs=newSubspecsDim;

out.rawSubspecs=in1.rawSubspecs+in2.rawSubspecs;
out.subspecs=in1.subspecs+in2.subspecs;

%FILLING IN THE FLAGS
out.flags=in1.flags;
out.flags.writtentostruct=1;
out.flags.subtracted=0;


function [b, mpe] = backT_mpe(engine, f, ev2, t)

bnet = bnet_from_engine(engine);
ss = bnet.nnodes_per_slice;

if t==1
  % ev2 is just the evidence on slice 1
  [mpe, b.clpot] = find_max_config(engine.jtree_engine1, f.clpot, f.seppot, ev2);
else
  [mpe, b.clpot] = find_max_config(engine.jtree_engine, f.clpot, f.seppot, ev2);
  mpe = mpe((1:ss)+ss); % extract values for slice 2
end
for c=1:length(b.clpot)
  [b.clpot{c}, ll(c)] = normalize_pot(b.clpot{c});
end
b.t = t;


classdef MergeRobertson < handle
    %MERGEROBERTSON  Merge exposure sequence to a single image
    %
    % The resulting HDR image is calculated as weighted average of the
    % exposures considering exposure values and camera response.
    %
    % For more information see [RB99].
    %
    % ## References
    % [RB99]:
    % > Mark A Robertson, Sean Borman, and Robert L Stevenson.
    % > "Dynamic range improvement through multiple exposures".
    % > In Image Processing, 1999. ICIP 99. Proceedings. 1999 International
    % > Conference on, volume 3, pages 159-163. IEEE, 1999.
    %
    % See also: cv.MergeDebevec, cv.MergeMertens, makehdr
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    %% MergeRobertson
    methods
        function this = MergeRobertson()
            %MERGEROBERTSON  Creates MergeRobertson object
            %
            %     obj = cv.MergeRobertson()
            %
            % See also: cv.MergeRobertson.process
            %
            this.id = MergeRobertson_(0, 'new');
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     obj.delete()
            %
            % See also: cv.MergeRobertson
            %
            if isempty(this.id), return; end
            MergeRobertson_(this.id, 'delete');
        end
    end

    %% MergeExposures
    methods
        function dst = process(this, src, etimes, varargin)
            %PROCESS  Merges images
            %
            %     dst = obj.process(src, etimes)
            %     dst = obj.process(src, etimes, response)
            %
            % ## Input
            % * __src__ vector of input images, all of the same size and
            %   `uint8` type.
            % * __etimes__ vector of exposure time values for each image.
            % * __response__ 256x1xCN `single` matrix with inverse camera
            %   response function (CRF) for each pixel value, it should have
            %   the same number of channels as images `src{i}`.
            %
            % ## Output
            % * __dst__ result image, same size as `src{i}` and `single` type.
            %
            % The function has a short version, that doesn't take the extra
            % `response` argument.
            %
            % See also: cv.MergeRobertson.MergeRobertson
            %
            dst = MergeRobertson_(this.id, 'process', src, etimes, varargin{:});
        end
    end

    %% Algorithm
    methods (Hidden)
        function clear(this)
            %CLEAR  Clears the algorithm state
            %
            %     obj.clear()
            %
            % See also: cv.MergeRobertson.empty, cv.MergeRobertson.load
            %
            MergeRobertson_(this.id, 'clear');
        end

        function b = empty(this)
            %EMPTY  Returns true if the algorithm is empty
            %
            %     b = obj.empty()
            %
            % ## Output
            % * __b__ Returns true if the object is empty (e.g in the
            %   very beginning or after unsuccessful read).
            %
            % See also: cv.MergeRobertson.clear, cv.MergeRobertson.load
            %
            b = MergeRobertson_(this.id, 'empty');
        end

        function name = getDefaultName(this)
            %GETDEFAULTNAME  Returns the algorithm string identifier
            %
            %     name = obj.getDefaultName()
            %
            % ## Output
            % * __name__ This string is used as top level XML/YML node tag
            %   when the object is saved to a file or string.
            %
            % See also: cv.MergeRobertson.save, cv.MergeRobertson.load
            %
            name = MergeRobertson_(this.id, 'getDefaultName');
        end

        function save(this, filename)
            %SAVE  Saves the algorithm parameters to a file
            %
            %     obj.save(filename)
            %
            % ## Input
            % * __filename__ Name of the file to save to.
            %
            % This method stores the algorithm parameters in the specified
            % XML or YAML file.
            %
            % See also: cv.MergeRobertson.load
            %
            MergeRobertson_(this.id, 'save', filename);
        end

        function load(this, fname_or_str, varargin)
            %LOAD  Loads algorithm from a file or a string
            %
            %     obj.load(fname)
            %     obj.load(str, 'FromString',true)
            %     obj.load(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __fname__ Name of the file to read.
            % * __str__ String containing the serialized model you want to
            %   load.
            %
            % ## Options
            % * __ObjName__ The optional name of the node to read (if empty,
            %   the first top-level node will be used). default empty
            % * __FromString__ Logical flag to indicate whether the input is a
            %   filename or a string containing the serialized model.
            %   default false
            %
            % This method reads algorithm parameters from the specified XML or
            % YAML file (either from disk or serialized string). The previous
            % algorithm state is discarded.
            %
            % See also: cv.MergeRobertson.save
            %
            MergeRobertson_(this.id, 'load', fname_or_str, varargin{:});
        end
    end

end


function ExampleAnalog()
% function OutputAnalogVector = ExampleAnalog()

% Prompt for the correct DLL
disp(' ');  % Blank line
DLLName = input('DLL Name: ', 's');

% Load the appropriate DLL
[nsresult] = ns_SetLibrary(DLLName);
if (nsresult ~= 0)
    disp('DLL was not found!');
    return
end

% Find out the data file from user
disp(' ');  % Blank line
filename = input('Data file: ', 's');

% Load data file and display some info about the file
% Open data file
[nsresult, hfile] = ns_OpenFile(filename);
if (nsresult ~= 0)
    disp('Data file did not open!');
    return
end
clear filename;

% Get file information
[nsresult, FileInfo] = ns_GetFileInfo(hfile);
% Gives you EntityCount, TimeStampResolution and TimeSpan
if (nsresult ~= 0)
    disp('Data file information did not load!');
    return
end

% Define some variables needed for firing rates
stepsize = 0.02; % seconds
stepsize1 = 0.1; % seconds
if FileInfo.TimeSpan > 150  % Limit the timespan shown in the graphs to 150 seconds
    totaltime = 150;
else
    totaltime = FileInfo.TimeSpan; % seconds
end
time = 0 : stepsize : totaltime;   % Initialize time axis for gaussian plot

% Build catalogue of entities
[nsresult, EntityInfo] = ns_GetEntityInfo(hfile, [1 : 1 : FileInfo.EntityCount]);

NeuralList = find([EntityInfo.EntityType] == 4);    % List of EntityIDs needed to retrieve the information and data
SegmentList = find([EntityInfo.EntityType] == 3);
AnalogList = find([EntityInfo.EntityType] == 2);
EventList = find([EntityInfo.EntityType] == 1);

% How many of a particular entity do we have
cNeural = length(NeuralList);
cSegment = length(SegmentList);
cAnalog = length(AnalogList);
cEvent = length(EventList);

clear FileInfo;

if (cNeural == 0)
    disp('No neural events available!');
end

if (cSegment == 0)
    disp('No segment entities available!');
end

if (cAnalog == 0)
    disp('No analog entities available!');
end

if (cEvent == 0)
    disp('No event entities available!');
end

% prompt to get the number of points
max_count = input('How many data points (x-axis) do you want max? ');

% Have user pick a channels or channels for further analysis
% Show the user how many channels are available
disp(' ');
disp(['There are ' num2str(cAnalog) ' analog channels.']);
disp(' ');

yes = input('Show first all analog channels? y/n ', 's');
if (yes == 'y')
    for i = 1 : 1 : length(AnalogList)
        chan = AnalogList(i);
        count = min(max_count, EntityInfo(chan).ItemCount);
        % Get the fist data points of the waveform and show it
        [nsresult, ContinuousCount, wave] = ns_GetAnalogData(hfile, AnalogList(i), 1, count);
        figure;
        plot(wave);
    end
    return;
end

disp(['First analog entity: ' num2str(AnalogList(1)) ]);
channel = input('Which data channels would you like to display? (e.g. 1 or [1 2 3])');
if (EntityInfo(channel).EntityType == 2)  % Have to check that the selected channel actually exists
else
    disp('Channel is not of type analog');
    return
end
clear cNeural cSegment;

% Throw away entity infos we don't need to save memory
EntityInfo = rmfield(EntityInfo, 'EntityType');

%
% Load the waveform data and do the analysis
%

count = min(max_count, EntityInfo(channel).ItemCount);

% Get the fist data points of the waveform and show it
[nsresult, ContinuousCount, wave] = ns_GetAnalogData(hfile, channel, 1, count);
plot(wave);
return;


function maxComplexity = getComplexity(filename)
%GETCOMPLEXITY  Calculate the maximum complexity in an M-file.
%   maxComplexity = getcomplexity(filename)
%
%   "Complexity" refers to the McCabe complexity as returned by "mlint -cyc"
%   When there are multiple functions in a file, the maximum value is
%   returned.

% The MATLAB Contest Team
% Copyright 2010-2011 The MathWorks, Inc.

msg = mlint('-cyc','-string',filename);
tk = regexp(msg,'McCabe complexity of [^\s]+ is (\d+)','tokens');
complexity = zeros(size(tk));
for j = 1:length(tk)
    complexity(j) = eval(tk{j}{1});
end
maxComplexity = max(complexity);


%  Verify NIFTI header extension to make sure that each extension section
%  must be an integer multiple of 16 byte long that includes the first 8
%  bytes of esize and ecode. If the length of extension section is not the
%  above mentioned case, edata should be padded with all 0.
%
%  Usage: [ext, esize_total] = verify_nii_ext(ext)
%
%  ext - Structure of NIFTI header extension, which includes num_ext,
%       and all the extended header sections in the header extension.
%       Each extended header section will have its esize, ecode, and
%       edata, where edata can be plain text, xml, or any raw data
%       that was saved in the extended header section.
%
%  esize_total - Sum of all esize variable in all header sections.
%
%  NIFTI data format can be found on: http://nifti.nimh.nih.gov
%
%  - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
%
function [ext, esize_total] = verify_nii_ext(ext)

   if ~isfield(ext, 'section')
      error('Incorrect NIFTI header extension structure.');
   elseif ~isfield(ext, 'num_ext')
      ext.num_ext = length(ext.section);
   elseif ~isfield(ext, 'extension')
      ext.extension = [1 0 0 0];
   end

   esize_total = 0;

   for i=1:ext.num_ext
      if ~isfield(ext.section(i), 'ecode') | ~isfield(ext.section(i), 'edata')
         error('Incorrect NIFTI header extension structure.');
      end

      ext.section(i).esize = ceil((length(ext.section(i).edata)+8)/16)*16;
      ext.section(i).edata = ...
	[ext.section(i).edata ...
	 zeros(1,ext.section(i).esize-length(ext.section(i).edata)-8)];
      esize_total = esize_total + ext.section(i).esize;
   end

   return                                       % verify_nii_ext


function [geo,angles]=readBrukerGeometry(folder_or_file,dataset_number)

% Developed by A. Biguri

if nargin==1
    dataset_number=-1;
end

if endsWith(folder_or_file,'.log')
    % is the log file itself
    fid=fopen(folder_or_file);
else
    % is the folder where it lives
    file = dir([folder_or_file,'/*.log']); %
    if isempty(file)
        error(['No .log file found in folder: ', folder_or_file]);
    end

    filename=file(1).name;
    fid=fopen([folder_or_file,'/',filename]);
    xtekctText = textscan(fid, '%s %s', 'Delimiter', '=', 'HeaderLines', 1, 'CommentStyle', '[');
    fclose(fid);

    if ~isempty(xtekctText{2}(strcmpi('Number of connected scans', xtekctText{1})))
        if dataset_number==-1
            error('This folder contains many datasets, please select which one to load with BrukerDataLoader(...,`dataset_number`, dataset_number)');
        end
        matching=[];
        for ii=1:length(file)
           if strcmpi(file(ii).name(end-5:end-4),num2str(dataset_number,'%02d'))
               matching=[matching ii];
           end
        end
        if length(matching)>1
            error('More than 1 file for the same dataset found, confused what to do, so I error')
        elseif isempty(matching)
            error('Dataset not found, check the number')
        end
        id=matching;
    else
        id=1;
    end
    filename=file(id).name;
    fid=fopen([folder_or_file,'/',filename]);
end
% check if it was oppened right
if(fid==-1)
    error('Wrong file path');
end
xtekctText = textscan(fid, '%s %s', 'Delimiter', '=', 'HeaderLines', 1, 'CommentStyle', '[');
fclose(fid);

%% Detector information
% Number of pixel in the detector
geo.nDetector=[str2double(xtekctText{2}(strcmpi('Number of Columns', xtekctText{1})));
    str2double(xtekctText{2}(strcmpi('Number of Rows', xtekctText{1})))];
% Size of pixels in the detector
geo.dDetector=[str2double(xtekctText{2}(strcmpi('Camera Pixel Size (um)', xtekctText{1})))/1000;
    str2double(xtekctText{2}(strcmpi('Camera Pixel Size (um)', xtekctText{1})))/1000];

camera_binning=cell2mat(xtekctText{2}(strcmpi('Camera binning', xtekctText{1})));
camera_binning=[str2double(camera_binning(1)), str2double(camera_binning(3))];
if ~isempty(camera_binning)
    geo.dDetector=geo.dDetector.*camera_binning';
end

xyratio= str2double(xtekctText{2}(strcmpi('CameraXYRatio', xtekctText{1})));
if ~isempty(xyratio)
    % try again
    xyratio= str2double(xtekctText{2}(strcmpi('Camera X/Y Ratio', xtekctText{1})));
    if ~isempty(xyratio)
        geo.dDetector(2)=geo.dDetector(2)/xyratio;
    end
end
% Total size of the detector
geo.sDetector=geo.nDetector.*geo.dDetector;

%% Offset of the detector:
geo.offDetector=[0;-(geo.nDetector(2)/2-str2double(xtekctText{2}(strcmpi('Optical Axis (line)', xtekctText{1}))))].*geo.dDetector;

%% Image information
% Number of pixel in the detector

% Size of each pixel
geo.dVoxel=[str2double(xtekctText{2}(strcmpi('Image Pixel Size (um)', xtekctText{1})))/1000;
    str2double(xtekctText{2}(strcmpi('Image Pixel Size (um)', xtekctText{1})))/1000;
    str2double(xtekctText{2}(strcmpi('Image Pixel Size (um)', xtekctText{1})))/1000 ];
% Size of the image in mm
geo.nVoxel=[geo.nDetector(1);geo.nDetector(1);geo.nDetector(2)];
geo.sVoxel=geo.nVoxel.*geo.dVoxel;

geo.offOrigin=[0;0;0];
%% Global geometry
geo.DSO=str2double(xtekctText{2}(strcmpi('Object to Source (mm)', xtekctText{1})));
geo.DSD=str2double(xtekctText{2}(strcmpi('Camera to Source (mm)', xtekctText{1})));

%% Detector offset
if endsWith(folder_or_file,'.log')
    folder=folder_or_file(1:end-4);
else
    folder=folder_or_file;
end
file = dir([folder,'/*.csv']); %
if ~isempty(file)
    off=csvread([file(1).folder, '/', file(1).name],5,1).'.*(geo.dDetector./camera_binning');
    geo.offDetector=geo.offDetector+off(:,1:end);
end
%% whitelevel

geo.whitelevel=2^str2double(xtekctText{2}(strcmpi('Depth (bits)', xtekctText{1})));

%%
%% angles

angle_step=str2double(xtekctText{2}(strcmpi('Rotation Step (deg)', xtekctText{1})));
initial_angle=0;
n_angles=str2double(xtekctText{2}(strcmpi('Number of Files', xtekctText{1})))-1;
angles=initial_angle:angle_step*pi/180:(initial_angle+(n_angles-1)*angle_step)*pi/180;
assert(size(angles,2)==n_angles,'Assertion failed: Inconsistent data detected. Number of projections and angle information do not match\n');


%  doinvers
% This file calculates orintation of the stress tensor
% based on Gephard's algorithm.
% stress tensor orientation. The actual calculation is done
% using a call to a fortran program.
%
% Stefan Wiemer 03/96

global mi mif1 mif2  hndl3 a newcat2 mi2
global tmp cumu2
report_this_filefun(mfilename('fullpath'));
think

tmp = [newt2(:,10:14)];
save /home/stefan/ZMAP/invers/data.inp tmp -ascii
infi = ['/home/stefan/ZMAP//invers/data.inp'];
outfi = ['/home/stefan/ZMAP/tmpout.dat'];

cd /home/stefan/ZMAP/invers
com1 =input('Which computer?','s');
tic
comm = ['! rsh ' com1 ' /home/stefan/ZMAP/invers/invshell1 ',...
    num2str(length(tmp(:,1))) ' ' num2str(i)  ' &']
eval(comm)

t = toc/60