% Support only 2 dim array
classdef qdouble
   properties (Constant)
      mex = qdouble.mexSelector();
   end

   methods (Static)
      function func = mexSelector()
         if isarm()
            func = @qdoubleArmMex;
         else
            func = @qdoubleMex;
         end
      end
   end

   properties
      x;
   end

   methods
      function o = qdouble(a)
         if iscell(a) || isa(a, 'uint8')
            o.x = a;
         else
            o.x = qdouble.toMex(a);
         end
      end

      %% Sizes
      function [m, n] = size(a, dim)
         a = a.x;
         if (iscell(a))
            s = double(size(a{1}));
         else
            s = [size(a, 2) size(a, 3)];
         end

         if (nargin == 1)
            if (nargout == 2)
               m = s(1);
               n = s(2);
            else
               m = s;
            end
         else
            m = s(dim);
         end
      end

      function r = length(a)
         s = size(a);
         if (min(s) == 0)
            r = 0;
         else
            r = max(s);
         end
      end

      function r = numel(a)
         r = prod(size(a)); %#ok<*PSIZE>
      end

      function r = isscalar(a)
         r = (numel(a) == 1);
      end

      function r = isvector(a)
         r = (size(a,1) == 1 || size(a,2) == 1);
      end

      function r = isempty(a)
         r = (numel(a) == 0);
      end

      function r = isrow(a)
         r = (size(a,1) == 1);
      end

      function r = iscolumn(a)
         r = (size(a,2) == 1);
      end

      function r = ismatrix(~)
         r = true;
      end

      function r = end(a, k, n)
         if n == 2
            r = size(a,k);
         else
            r = size(a,1) * size(a,2);
         end
      end

      %% Conversions
      function disp(a)
         disp(double(a))
      end

      function r = double(a)
         r = qdouble.UnaryOp('double', a);
      end

      function r = logical(a)
         r = qdouble.UnaryOp('logical', a);
      end

      function r = sparse(a,b,c,d,e,f)
         if nargin == 1
            if ~issparse(a)
               A = logical(sparse(double(a)));
               s = struct('type', '()');
               s.subs = {find(A)};
               s = qdouble(subsref(a, s));
               s.x = reshape(s.x, [size(s.x,1) numel(s.x)/size(s.x,1)]);
               r = qdouble({A;s.x});
            else
               r = qdouble(a);
            end
         else
            assert(nargin == 3 || nargin == 5 || nargin == 6, "unsupported number of arguments for sparse");
            if nargin == 3
               i = a; j = b; s = c; m = max(i); n = max(j); nzmax = length(s);
               if isempty(i)
                  m = 0; n = 0;
               end
            elseif nargin == 5
               i = a; j = b; s = c; m = d; n = e; nzmax = length(s);
            elseif nargin == 6
               i = a; j = b; s = c; m = d; n = e; nzmax = f;
            end
            A = sparse(i, j, ones(nzmax,1,'logical'),m,n,nzmax);
            assert(length(s) == nzmax);
            s = qdouble(s(:));
            r = qdouble({A;s.x});
         end
      end

      function r = full(a)
         if issparse(a)
            A = a.x{1};
            s = a.x{2};
            r = zeros(size(s,1), size(A,1), size(A,2), 'uint8');
            idx = find(a.x{1});
            r(:, idx) = s;
            r = qdouble(r);
         else
            r = qdouble(a);
         end
      end

      function r = issparse(a)
         r = iscell(a.x);
      end

      function r = issymmetric(a)
         if size(a,1) ~= size(a,2)
            r = false;
         else
            r = full(all(a == a', 'all'));
         end
      end

      function r = diag(a)
         assert(nargin == 1, "Support only one parameters")
         if isvector(a)
            r = qdouble(sparse(a));
            if size(a,1) == 1
               r = r';
            end
            r.x{1} = diag(double(a));
            if ~issparse(a)
               r = full(r);
            end
         else
            k = min(size(a));
            if k == 0
               r = qdouble([]);
            else
               idx = (1:k) + size(a,1) * (0:(k-1));
               r =  subsref(a, struct('type', '()', 'subs', {{idx}}));
            end
            if issparse(a)
               r = sparse(r);
            end
            if size(a,2) < size(a,1)
               r = r';
            end
         end
      end

      function r = reshape(a, s)
         if issparse(a)
            a.x{1} = reshape(a.x{1}, s);
         else
            a.x = reshape(a.x, [size(a.x,1) s]);
         end
         r = qdouble(a.x);
      end

      function r = eps(~)
         r = qdouble(qdouble.mex('eps'));
      end

      %% Comparisons
      function r = lt(a, b)
         r = qdouble.BinaryOp('lt', a, b);
         if ((issparse(a) || issparse(b)) && ~issparse(r)), r = sparse(r); end
      end

      function r = gt(a, b)
         r = qdouble.BinaryOp('gt', a, b);
         if ((issparse(a) || issparse(b)) && ~issparse(r)), r = sparse(r); end
      end

      function r = le(a, b)
         r = ~gt(a,b);
      end

      function r = ge(a, b)
         r = ~lt(a,b);
      end

      function r = ne(a, b)
         r = qdouble.BinaryOp('ne', a, b);
         if ((issparse(a) || issparse(b)) && ~issparse(r)), r = sparse(r); end
      end

      function r = eq(a, b)
         r = ~ne(a,b);
      end

      function r = and(a, b)
         r = qdouble.BinaryOp('and', a, b);
      end

      function r = or(a, b)
         r = qdouble.BinaryOp('or', a, b);
      end

      function r = not(a)
         r = ~logical(a);
      end

      %% Arithmetic
      function r = plus(a, b)
         r = qdouble.BinaryOp('plus', a, b);
      end

      function r = minus(a, b)
         r = qdouble.BinaryOp('minus', a, b);
      end

      function r = times(a, b)
         r = qdouble.BinaryOp('times', a, b);
      end

      function r = power(a, b)
         assert(isscalar(b) && b == 2, "support only power(a, 2)");
         r = a .* a;
      end

      function r = rdivide(a, b)
         if issparse(b)
            b = full(b);
         end
         r = qdouble.BinaryOp('rdivide', a, b);

         if issparse(a) % To fix the bug regarding x / 0
            r2 = double(a) ./ double(b);
            r(~isfinite(r2)) = r2(~isfinite(r2));
         end
      end

      function r = ldivide(a, b)
         r = b./a;
      end

      function r = uminus(a)
         r = qdouble.UnaryOp('uminus', a);
      end

      function r = uplus(a)
         r = a;
      end

      function r = abs(a)
         r = qdouble.UnaryOp('abs', a);
      end

      function r = sqrt(a)
         r = qdouble.UnaryOp('sqrt', a);
      end

      function r = sum(varargin)
         r = qdouble.ReductionOp('sum', varargin{:});
      end

      function r = prod(varargin)
         r = qdouble.ReductionOp('prod', varargin{:});
      end

      function r = all(a, dim)
         if nargin == 1
            r = all(logical(a));
         else
            r = all(logical(a), dim);
         end
      end

      function r = any(a, dim)
         if nargin == 1
            r = any(logical(a));
         else
            r = any(logical(a), dim);
         end
      end

      function r = max(a, b, c)
         if nargin == 1
            r = qdouble.ReductionOp('max', a);
         elseif nargin == 3 && size(b,1) == 0 && size(b,2) == 0
            r = qdouble.ReductionOp('max', a, c);
         else
            assert(nargin == 2);
            r = qdouble.BinaryOp('max2', a, b);
            if issparse(a) || issparse(b)
               r = sparse(r);
            end
         end
      end

      function r = min(a, b, c)
         if nargin == 1
            r = qdouble.ReductionOp('min', a);
         elseif nargin == 3 && size(b,1) == 0 && size(b,2) == 0
            r = qdouble.ReductionOp('min', a, c);
         else
            assert(nargin == 2);
            r = qdouble.BinaryOp('min2', a, b);
            if issparse(a) || issparse(b)
               r = sparse(r);
            end
         end
      end

      function r = norm(a)
         assert(isvector(a), "norm supports only vectors.");
         r = sqrt(full(sum(a.^2)));
      end

      function r = nnz(a)
         r = full(sum(logical(a),'all'));
      end

      %% Access
      function [i,j,v] = find(a)
         if nargout == 1
            i = find(logical(a));
         elseif nargout == 2
            [i,j] = find(logical(a));
         else
            a = sparse(qdouble(a));
            [i,j] = find(a.x{1});
            v = qdouble(a.x{2});
            if size(a,1) == 1
               v = v';
            end
            if numel(v) == 0
               v = qdouble([]);
            end
         end
      end

      %% Matrix operations
      function r = ctranspose(a)
         r = transpose(a);
      end

      function r = transpose(a)
         r = qdouble.UnaryOp('transpose', a);
      end

      function r = mtimes(a, b)
         if isscalar(a) || isscalar(b)
            r = a .* b;
         else
            r = qdouble.BinaryOp('mtimes', a, b);
         end
      end

      function r = mldivide(a, b)
         assert(size(a,1) == size(b,1), 'Incompatible Size.');
         s = [size(a,2), size(b,2)];
         if size(a,2) == 0 || size(a,1) == 0 || size(b,2) == 0
            r = qdouble(zeros(s));
         elseif isscalar(a)
            r = reshape(b ./ a, s);
         else
            b_full = full(b); % sparsity usually does not help. Do this for simplicity
            r = qdouble.BinaryOp('mldivide', a, b_full);
         end
         if (issparse(a) && issparse(b))
            r = sparse(r);
         end
      end

      function r = mrdivide(a, b)
         r = (b'\a')';
      end

      function r = horzcat(varargin)
         allDense = true;
         for k = 1:length(varargin)
            allDense = allDense & ~issparse(varargin{k});
         end

         if (allDense)
            cat_input = cell(length(varargin), 1);
            for k = 1:length(varargin)
               cat_input{k} = varargin{k}.x;
            end
            r = qdouble(cat(3, cat_input{:}));
         else
            A_bool = [];
            m = []; v = [];
            for k = 1:length(varargin)
               A = sparse(qdouble(varargin{k}));
               if k == 1
                  m = size(A,1);
                  A_bool = A.x{1};
                  v = A.x{2};
               else
                  assert(m == size(A,1), 'Incompatible size.');
                  A_bool = [A_bool A.x{1}];
                  v = [v A.x{2}];
               end
            end
            r = qdouble({A_bool;v});
         end
      end

      function r = vertcat(varargin)
         for i = 1:length(varargin)
            varargin{i} = varargin{i}';
         end
         r = horzcat(varargin{:})';
      end

      function r = subsref(a,s)
         if strcmp(s(1).type, '()')
            if issparse(a)
               idx = subsref(qdouble.ToIndex(a),s);
               A = logical(idx);
               [~,~,idx] = find(idx);
               v = a.x{2};
               v = v(:, idx);
               r = qdouble({A;v});
            else
               idx = subsref(qdouble.ToIndex(a),s);
               r = qdouble(reshape(a.x(:,idx), [size(a.x,1) size(idx)]));
            end
         else
            r = builtin('subsref',a,s);
         end
      end

      function r = subsasgn(a,s,b)
         if strcmp(s(1).type, '()')
            [a_idx, a_v] = qdouble.ToIndex(a);
            [b_idx, b_v] = qdouble.ToIndex(b);
            b_idx = max(a_idx,[],'all') + b_idx;
            v = [a_v b_v];

            r_idx = subsasgn(a_idx,s,b_idx);

            if issparse(r_idx)
               A = logical(r_idx);
               [~,~,idx] = find(r_idx);
               v = v(:, idx);
               r = {A;v};
            else
               r = reshape(v(:, r_idx), [size(v,1) size(r_idx)]);
            end
            r = qdouble(r);
         else
            r = builtin('subsasgn',a,s,b);
         end
      end

      %% cholesky related
      function r = dissect(a)
         r = dissect(double(a));
      end

      function r = amd(a)
         r = amd(double(a));
      end

      function r = colamd(a)
         r = colamd(double(a));
      end

      function r = symbfact(a)
         r = symbfact(double(a));
      end

      function [r1, r2] = etree(a)
         [r1, r2] = etree(double(a));
      end

      function r = chol(a)
         r = qdouble.UnaryOp('chol', a);
      end
   end

   methods (Static)
      function r = ones(varargin)
         r = qdouble(ones(varargin{:}));
      end

      function r = zeros(varargin)
         r = qdouble(zeros(varargin{:}));
      end

      function r = eye(varargin)
         r = qdouble(eye(varargin{:}));
      end

      function r = rand(varargin)
         r = qdouble(rand(varargin{:}));
      end

      function r = randn(varargin)
         r = qdouble(randn(varargin{:}));
      end

      function r = randi(varargin)
         r = qdouble(randi(varargin{:}));
      end

      function r = toMex(a)
         if isa(a, 'qdouble')
            r = a.x;
         elseif isobject(a)
            r = a.x;
            r = qdouble.mex('toMex', r);
         else
            r = qdouble.mex('toMex', double(a));
         end
      end

      function r = UnaryOp(cmd, a)
         a = qdouble.toMex(a);
         r = qdouble.mex(cmd, a);

         if iscell(r) || isa(r, 'uint8')
            r = qdouble(r);
         end
      end

      function r = BinaryOp(cmd, a, b)
         a = qdouble.toMex(a);
         b = qdouble.toMex(b);
         r = qdouble.mex(cmd, a, b);

         if iscell(r) || isa(r, 'uint8')
            r = qdouble(r);
         end
      end

      function [r, v] = ToIndex(a)
         if nargout == 2 && ~isa(a, 'qdouble')
            a = qdouble(a);
         end

         if issparse(a)
            [i,j] = find(double(a));
            r = sparse(i,j,1:length(i),size(a,1),size(a,2));

            if nargout == 2
               v = a.x{2};
            end
         else
            r = reshape(1:numel(a),[size(a,1) size(a,2)]);

            if nargout == 2
               v = reshape(a.x, [size(a.x,1) numel(a.x)/size(a.x,1)]);
            end
         end
      end

      function r = ReductionOp(cmd, a, dim_)
         a_size = size(a);
         a = qdouble(a);

         if nargin == 2
            if (size(a,1) > 1)
               dim = 1;
            elseif (size(a,2) > 1)
               dim = 2;
            else
               dim = 1;
               a = subsref(a, struct('type', '()', 'subs', {{':'}}));
            end
         else
            assert(strcmp(dim_, 'all') || isscalar(dim_), 'dim can either be all or a scalar');
            if strcmp(dim_, 'all')
               dim = 1;
               a = subsref(a, struct('type', '()', 'subs', {{':'}}));
            else
               dim = dim_;
            end
         end

         if size(a,1) == 0
            switch cmd
               case 'sum'
                  r = qdouble(0.0 * ones(1, size(a,2)));
               case 'prod'
                  r = qdouble(1.0 * ones(1, size(a,2)));
               case 'max'
                  r = qdouble(ones(0, a_size(2)));
               case 'min'
                  r = qdouble(ones(0, a_size(2)));
            end
            if dim == 2
               r = r';
            end
         elseif dim == 1
            r = qdouble.mex(cmd, a.x);
            r = qdouble(r);
         elseif dim == 2
            a = a';
            r = qdouble.mex(cmd, a.x);
            r = qdouble(r)';
         end

         if issparse(a)
            r = sparse(r);
         end
      end
   end
end


function cell2csv(C,filename)
%CELL2CSV Output a cell array to a CSV file
%
%   IOSR.GENERAL.CELL2CSV(C,FILENAME) writes the cell array C to a CSV file
%   specified by filename.

%   Copyright 2016 University of Surrey.

    %% make sure filename has a .csv extension

    [pathstr, name, ext] = fileparts(filename);
    if ~strcmp(ext,'.csv')
        filename = [pathstr filesep name '.csv'];
    end

    %% write data

    [nrows,ncols]= size(C);

    % trap and remove cell arrays of strings
    IX = cell2mat(cellfun(@iscell,C,'UniformOutput',false));
    C(IX) = cellfun(@char,C(IX),'UniformOutput',false);

    % create file
    fid = fopen(filename, 'w');

    % create format string
    format = cell(1,ncols);
    ind = cellfun(@ischar,C(2,:));
    format(ind) = {'%s,'};
    format(~ind) = {'%f,'};
    format = wrap(format);

    if any(cellfun(@ischar,C(1,:))~=cellfun(@ischar,C(2,:)))
        % the cell array has a heading line
        header = repmat({'%s,'},[1,ncols]);
        header = wrap(header);
        start = 2;
        fprintf(fid, header, C{1,:});
    else
        % the cell array does not have a heading line
        start = 1;
    end

    for row=start:nrows
        fprintf(fid, format, C{row,:});
    end

    fclose(fid);

end

function y = wrap(x)
%WRAP Concatenate cells and add end EOL

    y = cell2mat(x);
    i = strfind(y,',');
    y = [y(1:i(end)-1) '\n'];

end


function mtexColorMap(arg1,varargin)
% define an MTEX colormap

% get input
if length(arg1)==1 && ishandle(arg1) &&...
    (isa(arg1,'axis') || isa(arg1,'matlab.graphics.axis.Axes') || isa(arg1,'matlab.ui.Figure'))
  ax = arg1;
  name = varargin{1};
else
  ax = gcf;
  name = arg1;
end

% get axes
try
  mtexFig = getappdata(ax,'mtexFig');
  ax = mtexFig.children;
end

% detect colormap
if ischar(name)
  if isempty(which([name '.m']))
    name = [name,'ColorMap'];
    if isempty(which(name))
      error('unknown colormap name');
    end
  end
  try
    map = feval(name);
  catch
    map = feval(lower(name));
  end
else
  map = name;
end

% apply the colormap
for i = 1:length(ax), colormap(ax(i),map); end

end


function rmReconCrossCorrelate(numOfStimuli,roi,method,datatype)

    if ~exist('HOMEDIR','var') || isempty(HOMEDIR)
        homedir = pwd;
    else
        homedir = HOMEDIR;
    end

    if ~exist('numOfStimuli','var') || isempty(numOfStimuli)
        error('Need the number of different stimuli.');
    end

    if ~exist('method','var') || isempty(method)
        method = 'betasum';
        fprintf('[%s] No method supplied, using default (betasum) \n',mfilename);
    end

    if ~exist('roi','var') || isempty(roi)
        roi ='V1';
        fprintf('[%s] No ROI supplied, using default (V1) \n',mfilename);
    end

    numstim = numOfStimuli;

    correl = zeros(numstim,numstim);
    pval = zeros(numstim,numstim);
    cond = single(zeros(128*128,numstim));

    for i = 1:numstim
        stimuli(i) = load([homedir '/Recon/RFcovs/' datatype '/' roi '/' method '/RFcov-stim' num2str(i) '.mat']);

        covstim = load([homedir '/Gray/' datatype '/methods/' method '/CovPlot_' roi '_stim' num2str(i) '-' method '.mat']);

        cond(:,i) = single(reshape(covstim.CovPlot,1,128*128));
    end

    for si = 1 : numstim
        for si2 = 1 : numstim

            [cor, p] = corr(cond(:,si), stimuli(si2).RFcov(:));

            correl(si,si2) = cor;
            pval(si,si2) = p;
        end
    end

    save([homedir '/Recon/Correlations/CrossCorr-' roi '-' method '.mat'],'correl');
    save([homedir '/Recon/Correlations/CrossPval-' roi '-' method '.mat'],'pval');
end


function C = cs_symperm (A,p)                                               %#ok
%CS_SYMPERM symmetric permutation of a symmetric matrix.
%   C = cs_symperm(A,p) computes C = A(p,p), but accesses only the
%   upper triangular part of A, and returns C upper triangular (A and C are
%   symmetric with just their upper triangular parts stored).  A must be square.
%
%   Example:
%       Prob = UFget ('HB/bcsstk01') ; A = Prob.A ;
%       p = cs_amd (A) ;
%       C = cs_symperm (A, p) ;
%       cspy (A (p,p)) ;
%       cspy (C) ;
%       C - triu (A (p,p))
%
%   See also CS_PERMUTE, SUBSREF, TRIU.

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

error ('cs_symperm mexFunction not found') ;


%GETOPT_PARS Get optimal parameters from REGOPTC
%
%	   PARS = GETOPT_PARS
%    GETOPT_PARS
%
% DESCRIPTION
% This routine retrieves the parameters as used in the final call
% in computing a classifier they are optimised by REGOPTC.

function pars = getopt_pars

global REGOPT_PARS

if nargout == 0
	s = [];
	for j = 1:length(REGOPT_PARS)
		if isempty(REGOPT_PARS{j})
			s = [s '  []'];
		elseif isstr(REGOPT_PARS{j})
			s = [s '  ' REGOPT_PARS{j}];
		elseif isdataset(REGOPT_PARS{j})
			s = [s '  dataset'];
		elseif ismapping(REGOPT_PARS{j})
			s = [s '  mapping'];
		elseif isstruct(REGOPT_PARS{j})
			s = [s '  structure'];
		else
			s = [s '  ' num2str(REGOPT_PARS{j})];
		end
	end
	fprintf(1,'\nParameters used: %s \n\n',s);
else
	pars = REGOPT_PARS;
end


function B = vertcat(varargin)
%VERTCAT   Horizontally concatenate LINOP objects.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Cast the result as a linop if there are any linop arguments.
B = linop( vertcat@chebmatrix(varargin{:}) );

end


function output = dissimilarInsert(dataStruct, newElement, index, nullData)
%"dissimilarInsert"
%   Add a dissimilar element to a datastructure, in position index.  If the
%   element has more fields than the structure, the new fields are added to
%   the structure and filled with nullData.  If the structure has more fields
%   than the element, the reverse occurs. Any data in that position is
%   deleted, as it would be in a normal indexing operation. If index is blank
%   or not entered it is assumed to be the end, resulting in append.
%
%   If nulldata is undefined [] is used.
%
%JRA 10/7/03
%JOD, 10 Nov 03, define nullData if needed.
%JRA, 10/1/04, Modifications to make compatible with ML6.1.
%JRA, 11/4/04, BugFix: Crashed if identical but misordered fieldnames.
%              Also added some more comments, and fixed initialization.
%
%Usage:
%   function output = dissimilarInsert(dataStruct, newElement, index, nullData)
%
% 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/>.

%nullData defaults to [].
if nargin < 4
    nullData = [];
end

%Insert index defaults to appending.
if ~exist('index','var') || (exist('index','var') && isempty(index))
    index = length(dataStruct)+1;
end

%Get all fieldnames, find common fields.
structNames = fieldnames(dataStruct);
newNames = fieldnames(newElement);
commonNames = intersect(structNames,newNames);

%If same number of fields in both...
if length(commonNames) == length(structNames) && length(commonNames) == length(newNames)
    differences = find(~strcmpi(structNames, newNames));
    %If no differences...
    if isempty(differences)
        %then insert normally.
        dataStruct(index) = newElement;
    %If there were differences...
    else
        %Fieldnames were identical but misordered, insert with reordering.
        for i=1:length(newNames)
            dataStruct = setfield(dataStruct, {index}, newNames{i}, getfield(newElement, newNames{i}));
        end
        %warning('Element''s fieldnames were misordered, but the same.')
    end
    output = dataStruct;
    return;
end

%If more fields in new element...
if length(commonNames) < length(newNames)
    newFieldsForStruct = setdiff(newNames, commonNames);
    for i = 1:length(newFieldsForStruct)
        %dataStruct = setfield(dataStruct, {}, newFieldsForStruct{i}, []);
        for j=1:length(dataStruct)
            dataStruct = setfield(dataStruct, {j}, newFieldsForStruct{i}, nullData);
        end
    end
end

%If more fields in data structure...
if length(commonNames) < length(structNames)
    newFieldsForElement = setdiff(structNames, commonNames);
    for i=1:length(newFieldsForElement)
        newElement = setfield(newElement, newFieldsForElement{i}, nullData);
    end
end

%Now actually perform the insert.
finalNames = fieldnames(newElement);
siz = size(dataStruct);
if prod(siz) == 0
    indV = 1:2:2*length(finalNames);
    argV = {};
    [argV{indV}] = deal(finalNames{:});
    argV{end+1} = [];
    dataStruct = struct(argV{:});
end

for i=1:length(finalNames)
    dataStruct = setfield(dataStruct, {index}, finalNames{i}, getfield(newElement, finalNames{i}));
end
output = dataStruct;
return;


function reducedModel=removeMets(model,metsToRemove,isNames,removeUnusedRxns,removeUnusedGenes,removeUnusedComps)
% removeMets
%   Deletes a set of metabolites from a model
%
%   model             a model structure
%   metsToRemove      either a cell array of metabolite IDs, a logical vector
%                     with the same number of elements as metabolites in the model,
%                     of a vector of indexes to remove
%   isNames           true if the supplied mets represent metabolite names
%                     (as opposed to IDs). This is a way to delete
%                     metabolites in several compartments at once without
%                     knowing the exact IDs. This only works if metsToRemove
%                     is a cell array (opt, default false)
%   removeUnusedRxns  remove reactions that are no longer in use (opt,
%                     default false)
%   removeUnusedGenes remove genes that are no longer in use (opt,
%                     default false)
%   removeUnusedComps remove compartments that are no longer in use (opt,
%                     default false)
%
%   reducedModel      an updated model structure
%
%   Usage: reducedModel=removeMets(model,metsToRemove,isNames,...
%           removeUnusedRxns,removeUnusedGenes,removeUnusedComps)
if ~islogical(metsToRemove) && ~isnumeric(metsToRemove)
    metsToRemove=convertCharArray(metsToRemove);
end

if nargin<3
    isNames=false;
end

if nargin<4
    removeUnusedRxns=false;
end

if nargin<5
    removeUnusedGenes=false;
end

if nargin<6
    removeUnusedComps=false;
end

%Check that metsToRemove is a cell array
if isNames==true && ~iscell(metsToRemove)
    error('Must supply a cell array of strings if isNames=true');
end

reducedModel=model;

if isNames==false
    indexesToDelete=getIndexes(model,metsToRemove,'mets');
else
    indexesToDelete=[];
    for i=1:numel(metsToRemove)
        indexesToDelete=[indexesToDelete;find(strcmp(metsToRemove(i),model.metNames))];
    end
end

%Remove metabolites
if ~isempty(indexesToDelete)
    reducedModel.mets(indexesToDelete)=[];
    reducedModel.S(indexesToDelete,:)=[];
    if isfield(reducedModel,'b')
        reducedModel.b(indexesToDelete,:)=[];
    end
    if isfield(reducedModel,'metNames')
        reducedModel.metNames(indexesToDelete)=[];
    end
    if isfield(reducedModel,'metComps')
        reducedModel.metComps(indexesToDelete)=[];
    end
    if isfield(reducedModel,'inchis')
        reducedModel.inchis(indexesToDelete)=[];
    end
    if isfield(reducedModel,'metSmiles')
        reducedModel.metSmiles(indexesToDelete)=[];
    end
    if isfield(reducedModel,'metFormulas')
        reducedModel.metFormulas(indexesToDelete)=[];
    end
    if isfield(reducedModel,'metMiriams')
        reducedModel.metMiriams(indexesToDelete)=[];
    end
    if isfield(reducedModel,'unconstrained')
        reducedModel.unconstrained(indexesToDelete)=[];
    end
    if isfield(reducedModel,'metFrom')
        reducedModel.metFrom(indexesToDelete)=[];
    end
    if isfield(reducedModel,'metCharges')
        reducedModel.metCharges(indexesToDelete)=[];
    end
end

%Remove unused reactions
if removeUnusedRxns==true
    %Get unused reactions
    [~, a]=find(reducedModel.S);
    rxnsToRemove=1:numel(reducedModel.rxns);
    rxnsToRemove(a)=[];
    reducedModel=removeReactions(reducedModel,rxnsToRemove,false,removeUnusedGenes);
end

%Remove unused compartments
if removeUnusedComps==true
    oldComps=reducedModel.comps;
    I=ismember(1:numel(oldComps),reducedModel.metComps);
    if ~all(I)
        reducedModel.comps(~I)=[];
        reducedModel.compNames(~I)=[];
        if isfield(reducedModel,'compOutside')
            reducedModel.compOutside(~I)=[];
        end
        if isfield(reducedModel,'compMiriams')
            reducedModel.compMiriams(~I)=[];
        end
        [~, J]=ismember(oldComps(reducedModel.metComps),reducedModel.comps);
        reducedModel.metComps=J;
    end
end
end


function create_table_of_algorithms(up)
%CREATE_TABLE_OF_ALGORITHMS creates a table of algorithms and their performances
%	            create_table_of_algorithms(up)
%
%	Inputs:
%		data            data files should be stored in the specified format
%       up              universal parameters structure
%
%	Outputs:
%       tables          csv tables of results
%

fprintf('\n--- Creating Results Tables ');

% save setup
save_name = up.paths.filenames.results_table;
savepath = [up.paths.tables_save_folder, save_name, '.mat'];
if ~up.analysis.redo_stats
    exist_log = check_exists(savepath, save_name);
    if exist_log
        return
    end
end

% Load BA Data
load_name = 'BA_results';
loadpath = [up.paths.data_save_folder, up.paths.filenames.global_BA, '.mat'];
load(loadpath, load_name);

% Load algorithm names
load_name = up.paths.filenames.alg_names;
loadpath = [up.paths.data_save_folder, up.paths.filenames.alg_names, '.mat'];
load(loadpath, load_name);

% Load study data
load_name = 'trad_stats';
loadpath = [up.paths.data_save_folder, up.paths.filenames.study_stats, '.mat'];
load(loadpath, load_name);

% identify groups
groups = fieldnames(BA_results);

%% Create a BA table and a Stats table for each group

for group_no = 1 : length(groups)
    group = groups{group_no};

    %% Extract relevant data
    rel_data = extract_rel_data(group, BA_results, trad_stats, up);

    %% Make Table of BA Results
    BA_results_table = create_table_results(alg_names, rel_data, up, group, 'BA');

    %% Save to file
    save_name = [up.paths.filenames.BA_results_table, '_', group];
    savepath = [up.paths.tables_save_folder, save_name];
    xlswrite(savepath, BA_results_table)

    %% Make Table of Stats Results
    stats_results_table = create_table_results(alg_names, rel_data, up, group, 'stats');

    %% Save to file
    save_name = [up.paths.filenames.stats_results_table, '_', group];
    savepath = [up.paths.tables_save_folder, save_name];
    xlswrite(savepath, stats_results_table)

end

end

function rel_data = extract_rel_data(group, BA_results, stats, up)

rel_data.BA = extractfield(BA_results, group); rel_data.BA = rel_data.BA{1,1};
rel_data.stats = extractfield(stats, group); rel_data.stats = rel_data.stats{1,1};

end

function table_data = create_table_results(alg_names, rel_data, up, group, type)

% Find alg numbers:
alg_names.no = cell(length(alg_names.names),1);
for s = 1 : length(alg_names.no)
    alg_names.no{s} = ['a', num2str(s)];
end

% Extract relevant variables for table:
tab_vars.alg_no = alg_names.no;
if isfield(alg_names.meths, 'xa')
    tab_vars.m_xa = alg_names.meths.xa;
    tab_vars.m_xb = alg_names.meths.xb;
    tab_vars.m_ef = alg_names.meths.ef;
    tab_vars.m_et = alg_names.meths.et;
    tab_vars.m_fm = alg_names.meths.fm;
    tab_vars.m_ft = alg_names.meths.ft;
    % modify the fme:
    rel_els = ~isnan(tab_vars.m_fm);
    tab_vars.m_xb(rel_els) = 99;
end
tab_vars.alg_name = alg_names.names;
tab_vars.signal = alg_names.sigs;

% Extract relevant statistics for table:
if strcmp(type, 'BA')
    tab_vars.bias = rel_data.BA.bias.val;
    tab_vars.two_sd = rel_data.BA.two_sd.val;
    tab_vars.prop_wins_est = rel_data.stats.prop_wins_est;
    tab_vars.prop_wins_ref_and_good_sqi = rel_data.stats.prop_wins_good_sqi_and_ref;
elseif strcmp(type, 'stats')
    tab_vars.percerr = rel_data.stats.percerr;
    tab_vars.mae = rel_data.stats.mae;
    tab_vars.sdae = rel_data.stats.sdae;
    tab_vars.rmse = rel_data.stats.rmse;
    tab_vars.cp2 = rel_data.stats.cp2;
    tab_vars.prop_wins_est = rel_data.stats.prop_wins_est;
    tab_vars.total_wins_all = rel_data.stats.total_wins_all;
end

%% Determine what goes into the table
headers = fieldnames(tab_vars);
table_data = cell(1+length(tab_vars.alg_name), length(headers));
table_data(1,:) = headers;
for col_no = 1 : length(headers)
    eval(['col_data = tab_vars.' headers{col_no} ';']);
    if ~iscell(col_data)
        table_data(2:end,col_no) = num2cell(col_data);
    else
        table_data(2:end,col_no) = col_data;
    end
end

end

function [subj_data, BA_data, stats_data, old_names] = load_data(group, up)

% Load subj data
load_name = ['data_', group];
loadpath = [up.paths.data_save_folder, up.paths.filenames.group_data, group, '.mat'];
load(loadpath, load_name)
eval(['subj_data = data_' group  ';']);

% Load B-A results
load_name = 'BA';
loadpath = [up.paths.data_save_folder, up.paths.filenames.group_BA, group, '.mat'];
load(loadpath, load_name)
BA_data = BA; clear BA

% Load Stats data
load_name = 'acc';
loadpath = [up.paths.data_save_folder, up.paths.filenames.group_stats, group, '.mat'];
load(loadpath, load_name)
stats_data = acc;
old_names = acc.rr_alg_names;

end

function create_table_stats_results_subj(alg_names, sig_names, old_names, subj_data, up, group)

%% Find prop with an abs error of < 1 bpm
eval(['subjs = unique(subj_data.' old_names{1} '.subj);']);
prop_acc = zeros(length(old_names), length(subjs));
for alg_no = 1 : length(old_names)
     eval(['rel_data = subj_data.' old_names{alg_no} ';']);

     rel_data.error = rel_data.est - rel_data.ref;
     rel_data.abs_error = abs(rel_data.error);
     rel_data.acc_log = rel_data.abs_error < 1;

     for subj_no = 1:length(subjs)
         subj = subjs(subj_no);
         rel_els = logical(rel_data.subj == subj);
         prop_acc(alg_no, subj_no) = sum(rel_data.acc_log(rel_els)) / length(rel_data.acc_log(rel_els));
     end

     % extract relevant parts of algs:
     for comp_str = {'FMe', 'Flt', 'RSa', 'PDt', 'Est', 'MFu', 'TFu'}
         if ~exist([lower(comp_str{1,1}), '_meth'], 'var')
             eval([lower(comp_str{1,1}), '_meth = nan(length(old_names),1);']);
         end
         rel_el = strfind(alg_names{alg_no}, comp_str{1,1});
         if rel_el
             temp = str2num(alg_names{alg_no}(rel_el+3));
             eval([lower(comp_str{1,1}), '_meth(alg_no) = temp;']);
         end
     end

     clear rel_data
end

%% Determine what goes into the table
headers = {'Signal', 'Algorithm Name', 'Old Name', 'FMe', 'Flt', 'RSa', 'PDt', 'Est', 'MFu', 'TFu'};
for subj_no = 1:length(subjs)
    headers{end+1} = ['Prop_acc ' num2str(subjs(subj_no))];
end

table_data = cell(1+length(alg_names), length(headers));
table_data(1,:) = headers;
table_data(2:end,1) = sig_names;
table_data(2:end,2) = alg_names;
table_data(2:end,3) = old_names;
table_data(2:end,4) = num2cell(fme_meth);
table_data(2:end,5) = num2cell(flt_meth);
table_data(2:end,6) = num2cell(rsa_meth);
table_data(2:end,7) = num2cell(pdt_meth);
table_data(2:end,8) = num2cell(est_meth);
table_data(2:end,9) = num2cell(mfu_meth);
table_data(2:end,10) = num2cell(tfu_meth);
for s = 1 : size(prop_acc,2)
    table_data(2:end,10+s) = num2cell(prop_acc(:,s));
end

%% Save to file
save_name = [up.paths.filenames.subj_results_table '_' group];
savepath = [up.paths.tables_save_folder, save_name];
xlswrite(savepath,table_data)

end

function create_table_BA_results(alg_names, sig_names, BA_data, up, group)

%% Determine what goes into the table
headers = {'Signal', 'Algorithm Name', 'Bias', 'Bias (LCI)', 'Bias (UCI)', 'LLOA', 'LLOA (LCI)', 'LLOA (UCI)', 'ULOA', 'ULOA (LCI)', 'ULOA (UCI)', 'Precision', 'Precision (LCI)', 'Precision (UCI)'};
table_data = cell(1+length(alg_names), length(headers));
table_data(1,:) = headers;
table_data(2:end,1) = sig_names;
table_data(2:end,2) = alg_names;
table_data(2:end,3) = num2cell(BA_data.bias.val);
table_data(2:end,4) = num2cell(BA_data.bias.lci);
table_data(2:end,5) = num2cell(BA_data.bias.uci);
table_data(2:end,6) = num2cell(BA_data.lloa.val);
table_data(2:end,7) = num2cell(BA_data.lloa.lci);
table_data(2:end,8) = num2cell(BA_data.lloa.uci);
table_data(2:end,9) = num2cell(BA_data.uloa.val);
table_data(2:end,10) = num2cell(BA_data.uloa.lci);
table_data(2:end,11) = num2cell(BA_data.uloa.uci);
table_data(2:end,12) = num2cell(BA_data.prec.val);
table_data(2:end,13) = num2cell(BA_data.prec.lci);
table_data(2:end,14) = num2cell(BA_data.prec.uci);

%% Save to file
save_name = [up.paths.filenames.BA_results_table '_' group];
savepath = [up.paths.tables_save_folder, save_name];
xlswrite(savepath,table_data)

end

function create_table_stats_results(alg_names, sig_names, stats_data, up, group)

%% Determine what goes into the table
headers = {'Signal', 'Algorithm Name', 'MAE', 'MAE (lq)', 'MAE (uq)', 'SDAE', 'SDAE (lq)', 'SDAE (uq)', 'PERC ERR', 'PERC ERR (lq)', 'PERC ERR (uq)', 'RMSE', 'RMSE (lq)', 'RMSE (uq)', 'MEAN ERROR', 'MEAN ERROR (lq)', 'MEAN ERROR (uq)', 'STD ERROR', 'STD ERROR (lq)', 'STD ERROR (uq)', 'PROP WINS', 'PROP WINS (lq)', 'PROP WINS (uq)'};
table_data = cell(1+length(alg_names), length(headers));
table_data(1,:) = headers;
table_data(2:end,1) = sig_names;
table_data(2:end,2) = alg_names;
table_data(2:end,3) = num2cell(stats_data.mae.med);
table_data(2:end,4) = num2cell(stats_data.mae.lq);
table_data(2:end,5) = num2cell(stats_data.mae.uq);
table_data(2:end,6) = num2cell(stats_data.sdae.med);
table_data(2:end,7) = num2cell(stats_data.sdae.lq);
table_data(2:end,8) = num2cell(stats_data.sdae.uq);
table_data(2:end,9) = num2cell(stats_data.percerr.med);
table_data(2:end,10) = num2cell(stats_data.percerr.lq);
table_data(2:end,11) = num2cell(stats_data.percerr.uq);
table_data(2:end,12) = num2cell(stats_data.rmse.med);
table_data(2:end,13) = num2cell(stats_data.rmse.lq);
table_data(2:end,14) = num2cell(stats_data.rmse.uq);
table_data(2:end,15) = num2cell(stats_data.mean_diff.med);
table_data(2:end,16) = num2cell(stats_data.mean_diff.lq);
table_data(2:end,17) = num2cell(stats_data.mean_diff.uq);
table_data(2:end,18) = num2cell(stats_data.std_diff.med);
table_data(2:end,19) = num2cell(stats_data.std_diff.lq);
table_data(2:end,20) = num2cell(stats_data.std_diff.uq);
table_data(2:end,21) = num2cell(stats_data.prop_wins.med);
table_data(2:end,22) = num2cell(stats_data.prop_wins.lq);
table_data(2:end,23) = num2cell(stats_data.prop_wins.uq);

%% Save to file
save_name = [up.paths.filenames.stats_results_table '_' group];
savepath = [up.paths.tables_save_folder, save_name];
xlswrite(savepath,table_data)

end


function fixPSlinestyle(varargin)

%FIXPSLINESTYLE Fix line styles in exported post script files
%
% FIXPSLINESTYLE(FILENAME) fixes the line styles in the postscript file
%   FILENAME. The file will be over-written. This takes a .PS or .EPS file
%   and fixes the dotted and dashed line styles to be a little bit more
%   esthetically pleasing. It fixes the four default line styles (line,
%   dotted, dashed, dashdot).
%
% FIXPSLINESTYLE(FILENAME, NEWFILENAME) creates a new file NEWFILENAME.
%
%   This is meant to be used with postscript files created by MATLAB
%   (print, export).
%
% Example:
%   x  = 1:.1:10;
%   y1 = sin(x);
%   y2 = cos(x);
%   h  = plot(x, y1, '--', x, y2, '-.');
%   set(h, 'LineWidth', 2);
%   grid on;
%   legend('line 1', 'line2');
%
%   print -depsc test.eps
%   fixPSlinestyle('test.eps', 'fixed_test.eps');
%
% See also PRINT.

% Copyright 2005-2010 The MathWorks, Inc.

% Error checking
error(nargchk(1, 2, nargin));
if ~ischar(varargin{1}) || (nargin == 2 && ~ischar(varargin{2}))
  error('Input arguments must be file names (char).');
end

% Make sure the files specified are postscript files
[p1, n1, e1] = fileparts(varargin{1});
if isempty(e1) || ~ismember(lower(e1), {'.ps', '.eps'})
  error('The extension has to be .ps or .eps');
end

% Open file and read it in
fid = fopen(varargin{1}, 'r');
str = fread(fid);
str = char(str');
fclose(fid);

% Find where the line types are defined
id   = findstr(str, '% line types:');
str1 = str(1:id-1);
[line1     , remline ] = strtok(str(id:end), '/');
[replacestr, remline2] = strtok(remline    , '%');

% Define the new line styles
solidLine   = sprintf('/SO { [] 0 setdash } bdef\n');
dotLine     = sprintf('/DO { [3 dpi2point mul 3 dpi2point mul] 0 setdash } bdef\n');
dashedLine  = sprintf('/DA { [6 dpi2point mul] 0 setdash } bdef\n');
dashdotLine = sprintf('/DD { [2 dpi2point mul 2 dpi2point mul 6 dpi2point mul 2 dpi2point mul] 0 setdash } bdef\n');

% Construct the new file with the new line style definitions
newText     = [str1, line1, solidLine, dotLine, dashedLine, dashdotLine, remline2];

% Check for output file name
if nargin == 2
  [p2, n2, e2] = fileparts(varargin{2});
  if isempty(e2)
    fname = fullfile(p2, [n2, e1]);
  else
    if strcmpi(e1, e2)
      fname = varargin{2};
    else
      error('Output file must have same file extension.');
    end
  end
else % if not defined, over-write
  fname = varargin{1};
end

% Write out to file
fid = fopen(fname, 'w');
fprintf(fid, '%s', newText);
fclose(fid);


function bnd = prepare_mesh_manual(cfg, mri)

% PREPARE_MESH_MANUAL is called by PREPARE_MESH and opens a GUI to manually
% select points/polygons in an mri dataset.
%
% It allows:
%   Visualization of 3d data in 3 different projections
%   Adjustment of brightness for every slice
%   Storage of the data points in an external .mat file
%   Retrieval of previously saved data points
%   Slice fast scrolling with keyboard arrows
%   Polygons or points selection/deselection
%
% See also PREPARE_MESH_SEGMENTATION, PREPARE_MESH_HEADSHAPE

% Copyrights (C) 2009, Cristiano Micheli & Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% FIXME: control slice's cmap referred to abs values
% FIXME: clean structure slicedata
% FIXME: check function assign3dpoints

global obj

mri = ft_checkdata(mri, 'datatype', {'volume', 'segmentation'}, 'hasunit', 'yes');

hasheadshape = isfield(cfg, 'headshape');
hasbnd       = isfield(cfg, 'bnd');  % FIXME why is this in cfg?
hasmri       = nargin>1;

% check the consistency of the input arguments
if hasheadshape && hasbnd
  ft_error('you should not specify cfg.headshape and cfg.bnd simultaneously');
end

% check the consistency of the input arguments
if ~hasmri
  % FIXME give a warning or so?
  mri.anatomy = [];
  mri.transform = eye(4);
else
  % ensure that it is double precision
  mri.anatomy = double(mri.anatomy);
end

% start with an empty boundary
bnd.pnt = [];
bnd.tri = [];

if hasheadshape
  if ~isempty(cfg.headshape)
    % start with the headshape
    [bnd.pos, bnd.tri] = headsurface([], [], 'headshape', cfg.headshape);
  end
elseif hasbnd
  if ~isempty(cfg.bnd)
    % start with the prespecified boundaries
    bnd = cfg.bnd;
  end
end

% creating the GUI
fig = figure;

% initialize some values
slicedata = []; points = bnd.pnt;
axs = floor(size(mri.anatomy,1)/2);

% initialize properties
set(fig, 'KeyPressFcn',@keypress);
set(fig, 'CloseRequestFcn', @cb_close);
setappdata(fig,'data',mri.anatomy);
setappdata(fig,'prop',{1,axs,0,[]});
setappdata(fig,'slicedata',slicedata);
setappdata(fig,'points',points);
setappdata(fig,'box',[]);

% add GUI elements
cb_creategui(gca);
cb_redraw(gca);
waitfor(fig);

% close sequence
global pnt
try
  tmp = pnt;
  clear global pnt
  pnt = tmp;
  clear tmp
  [tri] = projecttri(pnt);
  bnd.pnt = pnt;
  bnd.tri = tri;
catch
  bnd.pnt = [];
  bnd.tri = [];
end

function cb_redraw(hObject, eventdata, handles)
fig  = get(hObject, 'parent');
prop = getappdata(fig,'prop');
data = getappdata(fig,'data');
slicedata = getappdata(fig,'slicedata');
points = getappdata(fig,'points');

% draw image
try
  cla
  % i,j,k axes
  if (prop{1}==1) %jk
    imh=imagesc(squeeze(data(prop{2},:,:)));
    xlabel('k');
    ylabel('j');
    colormap bone
  elseif (prop{1}==2) %ik
    imh=imagesc(squeeze(data(:,prop{2},:)));
    xlabel('k');
    ylabel('i');
    colormap bone
  elseif (prop{1}==3) %ij
    imh=imagesc(squeeze(data(:,:,prop{2})));
    xlabel('j');
    ylabel('i');
    colormap bone
  end
  axis equal; axis tight
  brighten(prop{3});
  title([ 'slice ' num2str(prop{2}) ])
catch
end
if ~ishold,hold on,end
% draw points and lines
for zz = 1:length(slicedata)
  if(slicedata(zz).proj==prop{1})
    if(slicedata(zz).slice==prop{2})
      polygon = slicedata(zz).polygon;
      for kk=1:length(polygon)
        if ~isempty(polygon{kk})
          [xs,ys]=deal(polygon{kk}(:,1),polygon{kk}(:,2));
          plot(xs, ys, 'g.-');
        end
      end
    end
  end
end % end for

% draw other slices points
points = getappdata(fig,'points');
pnts   = round(points);
if ~isempty(pnts)
  % exclude polygons inside the same slice
  indx  = find(points(:,prop{1})==prop{2});
  tmp   = ones(1,size(points,1));
  tmp(indx)  = 0;
  pnts  = points(find(tmp),:);
  % calculate indexes of other proj falling in current slice
  indx2 = find(round(pnts(:,prop{1}))==prop{2});
  rest  = setdiff([1 2 3],prop{1});
  % plot the points
  for jj=1:length(indx2)
    [x,y] = deal(pnts(indx2(jj),rest(1)),pnts(indx2(jj),rest(2)));
    plot(y,x,'g*')
  end
end

% add blue cross markers in case of box selection
box        = getappdata(fig,'box');
point2mark = getappdata(fig,'point2mark');

if ~isempty(point2mark)
  plot(point2mark.x,point2mark.y,'marker','+')
end

if ~isempty(box)
  for kk=1:size(box,1)
    proj   = box(kk,1);
    slice  = box(kk,2);
    rowmin = box(kk,3);
    rowmax = box(kk,4);
    colmin = box(kk,5);
    colmax = box(kk,6);
    aaa = get(findobj(fig, 'color', 'g'));
    for ii=1:length(aaa)
      if ispolygon(aaa(ii))
        L = length(aaa(ii).YData);
        for jj=1:L
          cond = lt(aaa(ii).YData(jj),rowmax).*gt(aaa(ii).YData(jj),rowmin).* ...
            lt(aaa(ii).XData(jj),colmax).*gt(aaa(ii).XData(jj),colmin);
          if cond
            plot(aaa(ii).XData(jj),aaa(ii).YData(jj),'marker','+')
          end
        end
      elseif ispoint(aaa(ii))
        cond = lt(aaa(ii).YData,rowmax).*gt(aaa(ii).YData,rowmin).* ...
          lt(aaa(ii).XData,colmax).*gt(aaa(ii).XData,colmin);
        % the test after cond takes care the box doesnt propagate in 3D
        if (cond && (proj == prop{1}) && (slice == prop{2}))
          plot(aaa(ii).XData,aaa(ii).YData,'marker','+')
        end
      end
    end
  end
end

if get(findobj(fig, 'tag', 'toggle axes'), 'value')
  axis on
else
  axis off
end

function cb_creategui(hObject, eventdata, handles)

fig = get(hObject, 'parent');
% define the position of each GUI element
% constants
CONTROL_WIDTH  = 0.10;
CONTROL_HEIGHT = 0.075;
CONTROL_HOFFSET = 0.8;
CONTROL_VOFFSET = 0.6;

% control buttons
uicontrol('tag', 'view', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'View', 'value', 1, 'callback', @which_task1);
ft_uilayout(fig, 'tag', 'view',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);

uicontrol('tag', 'ins', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'Ins', 'value', 0, 'callback', @which_task2);
ft_uilayout(fig, 'tag', 'ins',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+2.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'del', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'Del', 'value', 0, 'callback', @which_task3);
ft_uilayout(fig, 'tag', 'del',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+2.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'slice', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'slice', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'slice',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+1.25*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'min', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '<', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'min',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET+1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'max', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'max',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET+1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'brightness', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'brightness', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'brightness',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-0.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'plus', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '+', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'plus',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'minus', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '-', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'minus',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'toggle axes', 'parent', fig, 'units', 'normalized', 'style', 'checkbox', 'string', 'axes', 'value', 0, 'callback', @cb_redraw);
ft_uilayout(fig, 'tag', 'toggle axes',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-2.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);

uicontrol('tag', 'plane', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'plane', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'plane',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-3.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'one', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'jk', 'value', 0, 'callback', @cb_btnp1);
ft_uilayout(fig, 'tag', 'one',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-3.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);
uicontrol('tag', 'two', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'ik', 'value', 0, 'callback', @cb_btnp2);
ft_uilayout(fig, 'tag', 'two',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'three', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'ij', 'value', 0, 'callback', @cb_btnp3);
ft_uilayout(fig, 'tag', 'three',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'mesh', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'mesh', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'mesh',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-5.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);

uicontrol('tag', 'smoothm', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'smooth', 'value', [], 'callback', @smooth_mesh);
ft_uilayout(fig, 'tag', 'smoothm',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'viewm', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'view', 'value', [], 'callback', @view_mesh);
ft_uilayout(fig, 'tag', 'viewm',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'cancel', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'cancel', 'value', [], 'callback', @cancel_mesh);
ft_uilayout(fig, 'tag', 'cancel',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'ok', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'ok', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'ok',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

function cb_btn(hObject, eventdata, handles)
fig  = get(gca, 'parent');
prop = getappdata(fig,'prop');
slice = prop{2};
br    = prop{3};
datdim = size(getappdata(fig,'data'));
% p1 = [];p2 = [];p3 = [];
p1  = get(findobj('string','jk'),'value');
p2  = get(findobj('string','ik'),'value');
p3  = get(findobj('string','ij'),'value');
set(findobj('string','-'),'Value',prop{3});
set(findobj('string','+'),'Value',prop{3});
beta = get(findobj('string','-'),'Value');

if (p1)     %jk
  setappdata(fig,'prop',{1,round(datdim(1)/2),br,prop{4}});
  cb_redraw(gca);
elseif (p2) %ik
  setappdata(fig,'prop',{2,round(datdim(2)/2),br,prop{4}});
  cb_redraw(gca);
elseif (p3) %ij
  setappdata(fig,'prop',{3,round(datdim(3)/2),br,prop{4}});
  cb_redraw(gca);
end
if strcmp(get(hObject,'string'),'-')
  beta=beta-0.05;
  set(findobj('string','-'),'Value',beta);
  set(findobj('string','+'),'Value',beta);
  setappdata(fig,'prop',{prop{1},prop{2},beta,prop{4}});
  cb_redraw(gca);
elseif strcmp(get(hObject,'string'),'+')
  beta=beta+0.05;
  set(findobj('string','+'),'Value',beta);
  setappdata(fig,'prop',{prop{1},prop{2},beta,prop{4}});
  cb_redraw(gca);
end

if strcmp(get(hObject,'string'),'<')
  setappdata(fig,'prop',{prop{1},slice-1,0,prop{4}});
  cb_redraw(gca);
end
if strcmp(get(hObject,'string'),'>')
  setappdata(fig,'prop',{prop{1},slice+1,0,prop{4}});
  cb_redraw(gca);
end
if strcmp(get(hObject,'string'),'OK')
  close(fig)
end

function keypress(h, eventdata, handles, varargin)
fig   = get(gca, 'parent');
prop  = getappdata(fig,'prop');
dat   = guidata(gcbf);
key   = get(gcbf, 'CurrentCharacter');
slice = prop{2};
if  key
  switch key
    case 28
      setappdata(fig,'prop',{prop{1},slice-1,0,prop{4}});
      cb_redraw(gca);
    case 29
      setappdata(fig,'prop',{prop{1},slice+1,0,prop{4}});
      cb_redraw(gca);
    otherwise
  end
end
uiresume(h)

function build_polygon
fig   = get(gca, 'parent');
prop  = getappdata(fig,'prop');
data  = getappdata(fig,'data');
ss = size(data);
proj  = prop{1};
slice = prop{2};
thispolygon =1;
polygon{thispolygon} = zeros(0,2);
maskhelp = [ ...
  '------------------------------------------------------------------------\n' ...
  'specify polygons for masking the topographic interpolation\n' ...
  'press the right mouse button to add another point to the current polygon\n' ...
  'press backspace on the keyboard to remove the last point\n' ...
  'press "c" on the keyboard to close this polygon and start with another\n' ...
  'press "q" or ESC on the keyboard to continue\n' ...
  ];
again = 1;
if ~ishold,hold,end
fprintf(maskhelp);
fprintf('\n');

while again
  for i=1:length(polygon)
    fprintf('polygon %d has %d points\n', i, size(polygon{i},1));
  end

  [x, y, k] = ginput(1);
  okflag = 0;

  % check points do not fall out of image boundaries
  if get(findobj('string','Ins'),'value')
    if (proj == 1 && y<ss(2) && x<ss(3) && x>1 && y>1)
      okflag = 1;
    elseif (proj == 2 && y<ss(1) && x<ss(3) && x>1 && y>1)
      okflag = 1;
    elseif (proj == 3 && y<ss(1) && x<ss(2) && x>1 && y>1)
      okflag = 1;
    else
      okflag = 0;
    end
  end

  if okflag
    switch lower(k)
      case 1
        polygon{thispolygon} = cat(1, polygon{thispolygon}, [x y]);
        % add the last line segment to the figure
        if size(polygon{thispolygon},1)>1
          x = polygon{i}([end-1 end],1);
          y = polygon{i}([end-1 end],2);
        end
        plot(x, y, 'g.-');

      case 8 % backspace
        if size(polygon{thispolygon},1)>0
          % redraw existing polygons
          cb_redraw(gca);
          % remove the last point of current polygon
          polygon{thispolygon} = polygon{thispolygon}(1:end-1,:);
          for i=1:length(polygon)
            x = polygon{i}(:,1);
            y = polygon{i}(:,2);
            if i~=thispolygon
              % close the polygon in the figure
              x(end) = x(1);
              y(end) = y(1);
            end
            set(gca,'nextplot','new')
            plot(x, y, 'g.-');
          end
        end

      case 'c'
        if size(polygon{thispolygon},1)>0
          % close the polygon
          polygon{thispolygon}(end+1,:) = polygon{thispolygon}(1,:);
          % close the polygon in the figure
          x = polygon{i}([end-1 end],1);
          y = polygon{i}([end-1 end],2);
          plot(x, y, 'g.-');
          % switch to the next polygon
          thispolygon = thispolygon + 1;
          polygon{thispolygon} = zeros(0,2);
          slicedata = getappdata(fig,'slicedata');
          m = length(slicedata);
          slicedata(m+1).proj    = prop{1};
          slicedata(m+1).slice   = prop{2};
          slicedata(m+1).polygon = polygon;
          setappdata(fig,'slicedata',slicedata);
        end

      case {'q', 27}
        if size(polygon{thispolygon},1)>0
          % close the polygon
          polygon{thispolygon}(end+1,:) = polygon{thispolygon}(1,:);
          % close the polygon in the figure
          x = polygon{i}([end-1 end],1);
          y = polygon{i}([end-1 end],2);
          plot(x, y, 'g.-');
        end
        again = 0;
        %set(gcf,'WindowButtonDownFcn','');
        slicedata = getappdata(fig,'slicedata');
        m = length(slicedata);
        if ~isempty(polygon{thispolygon})
          slicedata(m+1).proj    = prop{1};
          slicedata(m+1).slice   = prop{2};
          slicedata(m+1).polygon = polygon;
          setappdata(fig,'slicedata',slicedata);
        end
      otherwise
        ft_warning('invalid button (%d)', k);
    end

  end
  assign_points3d
end

function cb_btn_dwn(hObject, eventdata, handles)
build_polygon
uiresume

function cb_btn_dwn2(hObject, eventdata, handles)
global obj
erase_points2d(obj)
uiresume

function erase_points2d (obj)
fig       = get(gca, 'parent');
prop      = getappdata(fig,'prop');
slicedata = getappdata(fig,'slicedata');
pntsslice = [];

% 2d slice selected box boundaries
if strcmp(get(obj,'string'),'box')
  [x, y] = ft_select_box;
  rowmin = min(y);    rowmax = max(y);
  colmin = min(x);    colmax = max(x);
  box = getappdata(fig,'box');
  box = [box; prop{1} prop{2} rowmin rowmax colmin colmax];
  setappdata(fig,'box',box);
else
  % converts lines to points
  pos = slicedata2pnts(prop{1},prop{2});
  tmp = ft_select_point(pos);
  point2mark.x = tmp(1); point2mark.y = tmp(2);
  setappdata(fig,'point2mark',point2mark);
end

maskhelp = [ ...
  '------------------------------------------------------------------------\n' ...
  'Delete points:\n' ...
  'press "c" on the keyboard to undo all selections\n' ...
  'press "d" or DEL on the keyboard to delete all selections\n' ...
  ];
fprintf(maskhelp);
fprintf('\n');
again = 1;
if ~ishold,hold,end
cb_redraw(gca);

% waits for a key press
while again
  [junk1, junk2, k] = ginput(1);

  switch lower(k)
    case 'c'
      if strcmp(get(obj,'string'),'box')
        % undoes all the selections, but only in the current slice
        ind = [];
        for ii=1:size(box,1)
          if box(ii,1)==prop{1} && box(ii,2)==prop{2}
            ind = [ind,ii];
          end
        end
        box(ind,:) = [];
        setappdata(fig,'box',box);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      else
        setappdata(fig,'point2mark',[]);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      end
    case {'d', 127}
      if strcmp(get(obj,'string'),'box')
        update_slicedata
        % deletes only the points selected in the current slice
        ind = [];
        for ii=1:size(box,1)
          if box(ii,1)==prop{1} && box(ii,2)==prop{2}
            ind = [ind,ii];
          end
        end
        box(ind,:) = [];
        setappdata(fig,'box',box);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      else
        update_slicedata
        setappdata(fig,'point2mark',[]);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      end
    otherwise
  end
end
assign_points3d

function assign_points3d
fig       = get(gca, 'parent');
slicedata = getappdata(fig,'slicedata');

points = [];
for zz = 1:length(slicedata)
  slice   = slicedata(zz).slice;
  proj    = slicedata(zz).proj;
  polygon = slicedata(zz).polygon;
  for kk=1:length(polygon)
    if ~isempty(polygon{kk})
      [xs,ys]=deal(polygon{kk}(:,1),polygon{kk}(:,2));
      if (proj==1)     %jk
        tmp    = [ slice*ones(length(xs),1),ys(:),xs(:) ];
        points = [points; unique(tmp,'rows')];
      elseif (proj==2) %ik
        tmp    = [ ys(:),slice*ones(length(xs),1),xs(:) ];
        points = [points; unique(tmp,'rows')];
      elseif (proj==3) %ij
        tmp    = [ ys(:),xs(:),slice*ones(length(xs),1) ];
        points = [points; unique(tmp,'rows')];
      end
    end
  end
end
setappdata(fig,'points',points);

function update_slicedata
fig       = get(gca, 'parent');
prop      = getappdata(fig,'prop');
slicedata = getappdata(fig,'slicedata');
box       = getappdata(fig,'box');
point2mark = getappdata(fig,'point2mark');
% case of box selection
if ~isempty(box) && ~isempty(slicedata)
  for zz = 1:length(slicedata)
    slice   = slicedata(zz).slice;
    proj    = slicedata(zz).proj;
    polygon = slicedata(zz).polygon;
    for uu=1:size(box,1)
      if (box(uu,1)==proj) && (box(uu,2)==slice)
        for kk=1:length(polygon)
          if ~isempty(polygon{kk})
            [xs,ys] = deal(polygon{kk}(:,1),polygon{kk}(:,2));
            tmpind = lt(ys,ones(length(xs),1)*box(uu,4)).*gt(ys,ones(length(xs),1)*box(uu,3)).* ...
              lt(xs,ones(length(xs),1)*box(uu,6)).*gt(xs,ones(length(xs),1)*box(uu,5));
            slicedata(zz).polygon{kk} = [ xs(find(~tmpind)),ys(find(~tmpind)) ];
          end
        end
      end
    end
  end
  % case of point selection
else
  if ~isempty(slicedata)
    for zz = 1:length(slicedata)
      slice   = slicedata(zz).slice;
      proj    = slicedata(zz).proj;
      polygon = slicedata(zz).polygon;
      for kk=1:length(polygon)
        if ~isempty(polygon{kk})
          [xs,ys] = deal(polygon{kk}(:,1),polygon{kk}(:,2));
          tmpind = eq(xs,point2mark.x).*eq(ys,point2mark.y);
          slicedata(zz).polygon{kk} = [ xs(find(~tmpind)),ys(find(~tmpind)) ];
        end
      end
    end
  end
end
setappdata(fig,'slicedata',slicedata)

% FIXME: obsolete: replaced by headshape at the beginning
function smooth_mesh(hObject, eventdata, handles)
fig = get(gca,'parent');
disp('not yet implemented')

% FIXME: make it work for pre-loaded meshes
function view_mesh(hObject, eventdata, handles)
fig  = get(gca, 'parent');
assign_points3d
pnt  = getappdata(fig,'points');
pnt_ = pnt;
if ~isempty(pnt)
  tri = projecttri(pnt);
  bnd.pnt = pnt_;
  bnd.tri = tri;
  slicedata = getappdata(fig,'slicedata');
  figure
  ft_plot_mesh(bnd,'vertexcolor','k');
end

function cancel_mesh(hObject, eventdata, handles)
fig  = get(gca, 'parent');
close(fig)

function cb_close(hObject, eventdata, handles)
% get the points from the figure
fig    = hObject;
global pnt
pnt   = getappdata(fig, 'points');
set(fig, 'CloseRequestFcn', @delete);
delete(fig);

function cb_btnp1(hObject, eventdata, handles)
set(findobj('string','jk'),'value',1);
set(findobj('string','ik'),'value',0);
set(findobj('string','ij'),'value',0);
cb_btn(hObject);

function cb_btnp2(hObject, eventdata, handles)
set(findobj('string','jk'),'value',0);
set(findobj('string','ik'),'value',1);
set(findobj('string','ij'),'value',0);
cb_btn(hObject);

function cb_btnp3(hObject, eventdata, handles)
set(findobj('string','jk'),'value',0);
set(findobj('string','ik'),'value',0);
set(findobj('string','ij'),'value',1);
cb_btn(hObject);

function which_task1(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');
set(findobj('string','View'),'value',1);
set(findobj('string','Ins'), 'value',0);
set(findobj('string','Del'), 'value',0);
set(gcf,'WindowButtonDownFcn','');
change_panel

function which_task2(hObject, eventdata, handles)
set(findobj('string','View'),'value',0);
set(findobj('string','Ins'), 'value',1);
set(findobj('string','Del'), 'value',0);
set(gcf,'WindowButtonDownFcn',@cb_btn_dwn);
change_panel

function which_task3(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');
set(findobj('string','View'),'value',0);
set(findobj('string','Ins'), 'value',0);
set(findobj('string','Del'), 'value',1);
change_panel

function change_panel
% affect panel visualization
w1 = get(findobj('string','View'),'value');
w2 = get(findobj('string','Ins'), 'value');
w3 = get(findobj('string','Del'), 'value');

if w1
  set(findobj('tag','slice'),'string','slice');
  set(findobj('tag','min'),'string','<');
  set(findobj('tag','max'),'string','>');
  set(findobj('tag','min'),'style','pushbutton');
  set(findobj('tag','max'),'style','pushbutton');
  set(findobj('tag','min'),'callback',@cb_btn);
  set(findobj('tag','max'),'callback',@cb_btn);
  set(findobj('tag','mesh'),'visible','on');
  set(findobj('tag','openm'),'visible','on');
  set(findobj('tag','viewm'),'visible','on');
  set(findobj('tag','brightness'),'visible','on');
  set(findobj('tag','plus'),'visible','on');
  set(findobj('tag','minus'),'visible','on');
  set(findobj('tag','toggle axes'),'visible','on');
  set(findobj('tag','plane'),'visible','on');
  set(findobj('tag','one'),'visible','on');
  set(findobj('tag','two'),'visible','on');
  set(findobj('tag','three'),'visible','on');
elseif w2
  set(findobj('tag','slice'),'string','select points');
  set(findobj('tag','min'),'string','close');
  set(findobj('tag','max'),'string','next');
  set(findobj('tag','min'),'style','pushbutton');
  set(findobj('tag','max'),'style','pushbutton');
  set(findobj('tag','min'),'callback',@tins_close);
  set(findobj('tag','max'),'callback',@tins_next);
  set(findobj('tag','mesh'),'visible','off');
  set(findobj('tag','openm'),'visible','off');
  set(findobj('tag','viewm'),'visible','off');
  set(findobj('tag','brightness'),'visible','off');
  set(findobj('tag','plus'),'visible','off');
  set(findobj('tag','minus'),'visible','off');
  set(findobj('tag','toggle axes'),'visible','off');
  set(findobj('tag','plane'),'visible','off');
  set(findobj('tag','one'),'visible','off');
  set(findobj('tag','two'),'visible','off');
  set(findobj('tag','three'),'visible','off');
elseif w3
  set(findobj('tag','slice'),'string','select points');
  set(findobj('tag','min'),'string','box');
  set(findobj('tag','max'),'string','point');
  set(findobj('tag','min'),'style','pushbutton');
  set(findobj('tag','max'),'style','pushbutton');
  set(findobj('tag','min'),'callback',@tdel_box);
  set(findobj('tag','max'),'callback',@tdel_single);
  set(findobj('tag','mesh'),'visible','off');
  set(findobj('tag','openm'),'visible','off');
  set(findobj('tag','viewm'),'visible','off');
  set(findobj('tag','brightness'),'visible','off');
  set(findobj('tag','plus'),'visible','off');
  set(findobj('tag','minus'),'visible','off');
  set(findobj('tag','toggle axes'),'visible','off');
  set(findobj('tag','plane'),'visible','off');
  set(findobj('tag','one'),'visible','off');
  set(findobj('tag','two'),'visible','off');
  set(findobj('tag','three'),'visible','off');
end

function tins_close(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');

function tins_next(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');

function tdel_box(hObject, eventdata, handles)
global obj
obj = gco;
set(gcf,'WindowButtonDownFcn',@cb_btn_dwn2);

function tdel_single(hObject, eventdata, handles)
global obj
obj = gco;
set(gcf,'WindowButtonDownFcn',@cb_btn_dwn2);

% accessory functions:
function [pnts] = slicedata2pnts(proj,slice)
fig       = get(gca, 'parent');
slicedata = getappdata(fig,'slicedata');
pnts = [];
for i=1:length(slicedata)
  if slicedata(i).slice==slice && slicedata(i).proj == proj
    for j=1:length(slicedata(i).polygon)
      if ~isempty(slicedata(i).polygon{j})
        tmp = slicedata(i).polygon{j};
        xs = tmp(:,1); ys = tmp(:,2);
        pnts = [pnts;[unique([xs,ys],'rows')]];
      end
    end
  end
end

function h = ispolygon(x)
h = length(x.XData)>1;

function h = ispoint(x)
h = length(x.XData)==1;

function [T,P] = points2param(pnt)
x = pnt(:,1); y = pnt(:,2); z = pnt(:,3);
[phi,theta,R] = cart2sph(x,y,z);
theta = theta + pi/2;
phi   = phi + pi;
T     = theta(:);
P     = phi(:);

function [bnd2,a,Or] = spherical_harmonic_mesh(bnd, nl)

% SPHERICAL_HARMONIC_MESH realizes the smoothed version of a mesh contained in the first
% argument bnd. The boundary argument (bnd) contains typically 2 fields
% called .pnt and .tri referring to vertices and triangulation of a mesh.
% The degree of smoothing is given by the order in the second input: nl
%
% Use as
%   bnd2 = spherical_harmonic_mesh(bnd, nl);

% nl    = 12; % from van 't Ent paper

bnd2 = [];

% calculate midpoint
Or = mean(bnd.pnt);
% rescale all points
x = bnd.pnt(:,1) - Or(1);
y = bnd.pnt(:,2) - Or(2);
z = bnd.pnt(:,3) - Or(3);
X = [x(:), y(:), z(:)];

% convert points to parameters
[T,P] = points2param(X);

% basis function
B     = shlib_B(nl, T, P);
Y     = B'*X;

% solve the linear system
a     = pinv(B'*B)*Y;

% build the surface
Xs = zeros(size(X));
for l = 0:nl-1
  for m = -l:l
    if m<0
      Yml = shlib_Yml(l, abs(m), T, P);
      Yml = (-1)^m*conj(Yml);
    else
      Yml = shlib_Yml(l, m, T, P);
    end
    indx = l^2 + l + m+1;
    Xs = Xs + Yml*a(indx,:);
  end
  fprintf('%d of %d\n', l, nl);
end
% Just take the real part
Xs = real(Xs);
% reconstruct the matrices for plotting.
xs = reshape(Xs(:,1), size(x,1), size(x,2));
ys = reshape(Xs(:,2), size(x,1), size(x,2));
zs = reshape(Xs(:,3), size(x,1), size(x,2));

bnd2.pnt = [xs(:)+Or(1) ys(:)+Or(2) zs(:)+Or(3)];
[bnd2.tri] = projecttri(bnd.pnt);

function B = shlib_B(nl, theta, phi)
% function B = shlib_B(nl, theta, phi)
%
% Constructs the matrix of basis functions
% where b(i,l^2 + l + m) = Yml(theta, phi)
%
% See also: shlib_Yml.m, shlib_decomp.m, shlib_gen_shfnc.m
%
% Dr. A. I. Hanna (2006).
B = zeros(length(theta), nl^2+2*nl+1);
for l = 0:nl-1
  for m = -l:l
    if m<0
      Yml = shlib_Yml(l, abs(m), theta, phi);
      Yml = (-1)^m*conj(Yml);
    else
      Yml = shlib_Yml(l, m, theta, phi);
    end
    indx = l^2 + l + m+1;
    B(:, indx) = Yml;
  end
end
return;

function Yml = shlib_Yml(l, m, theta, phi)
% function Yml = shlib_Yml(l, m, theta, phi)
%
% MATLAB function that takes a given order and degree, and the matrix of
% theta and phi and constructs a spherical harmonic from these. The
% analogue in the 1D case would be to give a particular frequency.
%
% Inputs:
%  m - order of the spherical harmonic
%  l - degree of the spherical harmonic
%  theta - matrix of polar coordinates \theta \in [0, \pi]
%  phi - matrix of azimuthal cooridinates \phi \in [0, 2\pi)
%
% Example:
%
% [x, y] = meshgrid(-1:.1:1);
% z = x.^2 + y.^2;
% [phi,theta,R] = cart2sph(x,y,z);
% Yml = spharm_aih(2,2, theta(:), phi(:));
%
% See also: shlib_B.m, shlib_decomp.m, shlib_gen_shfnc.m
%
% Dr. A. I. Hanna (2006)
Pml=legendre(l,cos(theta));
if l~=0
  Pml=squeeze(Pml(m+1,:,:));
end
Pml = Pml(:);
% Yml = sqrt(((2*l+1)/4).*(factorial(l-m)/factorial(l+m))).*Pml.*exp(sqrt(-1).*m.*phi);
% new:
Yml = sqrt(((2*l+1)/(4*pi)).*(factorial(l-m)/factorial(l+m))).*Pml.*exp(sqrt(-1).*m.*phi);
return;


function hole_num = p08_hole_num ( )

%*****************************************************************************80
%
%% P08_HOLE_NUM counts the holes in problem 08.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 April 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer HOLE_NUM, the number of holes.
%
  hole_num = 1;

  return
end


function g = endpoints(f)

persistent lut
if isempty(lut)
    lut = makelut(@endpoint_fcn, 3);
end

g = applylut(f,lut);

function is_end_point = endpoint_fcn(nhood)
is_end_point = nhood(2,2) & (sum(nhood(:)) == 2);


function voxels = carveall( voxels, cameras )
%CARVEALL  carve away voxels using all cameras
%
%   VOXELS = CARVEALL(VOXELS, CAMERAS) simple calls CARVE for each of the
%   cameras specified

%   Copyright 2005-2009 The MathWorks, Inc.
%   $Revision: 1.0 $    $Date: 2006/06/30 00:00:00 $

for ii=1:numel(cameras);
    voxels = carve(voxels,cameras(ii));
end


function LinearVariables = depends(varargin)

if nargin > 1
    LinearVariables = [];
    for i = 1:nargin
        LinearVariables_i = depends(varargin{i});
        LinearVariables = [LinearVariables;LinearVariables_i(:)];
    end
    LinearVariables = unique(LinearVariables);
    return
else
    LinearVariables = depends(lmi(varargin{1}));
end


function [ line_num, line_data_num ] = xyl_header_read ( input_filename )

%*****************************************************************************80
%
%% XYL_HEADER_READ determines the number of line items in an XYL file.
%
%  Discussion:
%
%    This routine assumes that the file contains exactly three kinds of
%    records:
%
%    COMMENTS which begin with a '#' character in column 1;
%    BLANKS which contain nothing but 'whitespace';
%    LINE ITEMS, which are indices of points on a line.
%
%    The routine ignores comments and blanks and returns
%    the number of line items.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 February 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string INPUT_FILENAME, the name of the input file.
%
%    Output, integer LINE_NUM, the number of lines.
%
%    Output, integer LINE_DATA_NUM, the number of line items.
%
  line_data_num = 0;
  line_num = 0;
%
%  Open the file.
%
  input_unit = fopen ( input_filename, 'r' );

  if ( input_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'XYL_HEADER_READ - Error!\n' );
    fprintf ( 1, '  Could not open the input file "%s".\n', input_filename );
    error ( 'XYL_HEADER_READ - Error!' );
  end
%
%  Use FGETL, not FGETS, so we don't pick up the NEWLINE character.
%
  while ( 1 )

    text = fgetl ( input_unit );

    if ( text == -1 )
      break;
    end

    if ( text(1) == '#' || s_len_trim ( text ) == 0 )
      continue
    end

    n = s_word_count ( text );

    line_data_num = line_data_num + n;

    line_num = line_num + 1;

  end
%
%  Close the file.
%
  fclose ( input_unit );

  return
end


function[H]=loadH(pref)
% load the data from Excel
[H txt]=xlsread(pref.excelFile,'Long run prior');
end


function a = reshape(b,varargin)
% Overloaded reshape function for file_array objects
%__________________________________________________________________________
% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging

%
% $Id: reshape.m 7147 2017-08-03 14:07:01Z spm $

if length(struct(b))~=1, error('Can only reshape simple file_array objects.'); end

args = [];
for i=1:length(varargin)
    args = [args varargin{i}(:)'];
end
if prod(args)~=prod(b.dim)
    error('To RESHAPE the number of elements must not change.');
end
a = b;
a.dim = args;


function [trackA, trackB] = TrimTracks(trackA, trackB)
nFrame = min(trackA.nFrame, trackB.nFrame);

goodA = trackA.head <= nFrame;
trackA.points = trackA.points(goodA, 1:nFrame, :);
trackA.head = trackA.head(goodA);
trackA.tail = trackA.tail(goodA);
trackA.tail = min(trackA.tail, nFrame);
trackA.len = trackA.tail - trackA.head + 1;
trackA.nFrame = nFrame;
trackA.nTrack = length(trackA.head);

goodB = trackB.head <= nFrame;
trackB.points = trackB.points(goodB, 1:nFrame, :);
trackB.head = trackB.head(goodB);
trackB.tail = trackB.tail(goodB);
trackB.tail = min(trackB.tail, nFrame);
trackB.len = trackB.tail - trackB.head + 1;
trackB.nFrame = nFrame;
trackB.nTrack = length(trackB.head);

end


function varargout = sccn_xdf(filename, hdr, begsample, endsample, chanindx)

% This is a wrapper to the reading function from the XDF MATLAB toolbox.
%
% Use as
%   hdr = sccn_xdf(filename);
%   dat = sccn_xdf(filename, hdr, begsample, endsample, chanindx);
%   evt = sccn_xdf(filename, hdr);
%
% See also FT_FILETYPE, FT_READ_HEADER, FT_READ_DATA, FT_READ_EVENT, XDF2FIELDTRIP

% Copyright (C) 2019, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% ensure this is on the path
ft_hastoolbox('xdf', 1);

needhdr = (nargin==1);
needevt = (nargin==2);
needdat = (nargin==5);

streams = load_xdf(filename);

iscontinuous = false(size(streams));

% figure out which streams contain continuous/regular and discrete/irregular data
for i=1:numel(streams)

    % if the nominal srate is non-zero, the stream is considered continuous
    if ~strcmpi(streams{i}.info.nominal_srate, '0')

       iscontinuous(i) =  true;

       if ~isfield(streams{i}.info, 'effective_srate')

           % in case effective srate field value is missing, add one
           num_samples  = numel(streams{i}.time_stamps);
           t_begin      = streams{i}.time_stamps(1);
           t_end        = streams{i}.time_stamps(end);
           duration     = t_end - t_begin;
           streams{i}.info.effective_srate = (num_samples - 1) / duration;

       elseif isempty(streams{i}.info.effective_srate)

           % in case effective srate field value is missing, add one
           num_samples  = numel(streams{i}.time_stamps);
           t_begin      = streams{i}.time_stamps(1);
           t_end        = streams{i}.time_stamps(end);
           duration     = t_end - t_begin;
           streams{i}.info.effective_srate = (num_samples - 1) / duration;

       end

    end

end

% determine the stream with the highest sampling rate
srate = nan(size(streams));
for i=1:numel(streams)
  if iscontinuous(i)
    srate(i) = streams{i}.info.effective_srate;
  end
end
[dum, indx] = max(srate);

% only keep the stream with the maximum sampling rate
% this is probably the EEG stream
stream = streams{indx};

if needhdr
  % this section of code is shared with xdf2fieldtrip
  hdr = [];
  if isfield(stream.info, 'effective_srate')
    % the stream contains continuously sampled data
    hdr.Fs                  = stream.info.effective_srate;
    hdr.nSamplesPre         = 0;
    hdr.nSamples            = length(stream.time_stamps);
    hdr.nTrials             = 1;
    hdr.FirstTimeStamp      = stream.time_stamps(1);
    hdr.TimeStampPerSample  = (stream.time_stamps(end)-stream.time_stamps(1)) / (length(stream.time_stamps) - 1);
  else
    % the stream does not contain continuously sampled data
    hdr.Fs                  = NaN;
    hdr.nSamplesPre         = NaN;
    hdr.nSamples            = NaN;
    hdr.nTrials             = NaN;
    hdr.FirstTimeStamp      = NaN;
    hdr.TimeStampPerSample  = NaN;
  end
  if isfield(stream.info.desc, 'channels')
    hdr.nChans    = numel(stream.info.desc.channels.channel);
  else
    hdr.nChans    = str2double(stream.info.channel_count);
  end
  hdr.label       = cell(hdr.nChans, 1);
  hdr.chantype    = cell(hdr.nChans, 1);
  hdr.chanunit    = cell(hdr.nChans, 1);

  prefix = stream.info.name;
  for j=1:hdr.nChans
    if isfield(stream.info.desc, 'channels')
      hdr.label{j} = [prefix '_' stream.info.desc.channels.channel{j}.label];
      hdr.chantype{j} = stream.info.desc.channels.channel{j}.type;
      hdr.chanunit{j} = stream.info.desc.channels.channel{j}.unit;
    else
      % the stream does not contain continuously sampled data
      hdr.label{j} = num2str(j);
      hdr.chantype{j} = 'unknown';
      hdr.chanunit{j} = 'unknown';
    end
  end

  % keep the original header details
  hdr.orig = stream.info;

  % return the header
  varargout = {hdr};

elseif needevt
  streams = streams(~iscontinuous);
  event = [];
  for i=1:numel(streams)
    for j=1:numel(streams{i}.time_series)

      % convert the timestamps to the corresponding sample in the selected data stream
      % the first sample in the data stream corresponds to 1
      timestamp = streams{i}.time_stamps(j);
      sample = round((timestamp - hdr.FirstTimeStamp)/hdr.TimeStampPerSample) + 1;

      event(end+1).type      = streams{i}.info.type;
      event(end  ).value     = streams{i}.time_series{j};
      event(end  ).timestamp = timestamp;
      event(end  ).sample    = sample;
    end
  end

  % return the events
  varargout = {event};

elseif needdat
  dat = stream.time_series(chanindx, begsample:endsample);

  % return the data
  varargout = {dat};
end


function rbfard2KernDisplay(kern, spacing)

% RBFARD2KERNDISPLAY Display parameters of the RBFARD2 kernel.
% FORMAT
% DESC displays the parameters of the automatic relevance determination radial basis function
% kernel and the kernel type to the console.
% ARG kern : the kernel to display.
%
% FORMAT does the same as above, but indents the display according
% to the amount specified.
% ARG kern : the kernel to display.
% ARG spacing : how many spaces to indent the display of the kernel by.
%
% SEEALSO : rbfard2KernParamInit, modelDisplay, kernDisplay
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005, 2006
%
% COPYRIGHT : Michalis K. Titsias, 2009

% KERN

if nargin > 1
  spacing = repmat(32, 1, spacing);
else
  spacing = [];
end
spacing = char(spacing);
fprintf(spacing);
fprintf('RBF ARD Variance: %2.4f\n', kern.variance)
fprintf(spacing);
for i = 1:kern.inputDimension
  fprintf(spacing);
  fprintf('RBF ARD Input %d scale: %2.4f\n', i, kern.inputScales(i))
end


function model = ZF_for_Faster_RCNN_VOC2007(model)

model.mean_image                                = fullfile(pwd, 'models', 'pre_trained_models', 'ZF', 'mean_image');
model.pre_trained_net_file                      = fullfile(pwd, 'models', 'pre_trained_models', 'ZF', 'ZF.caffemodel');
% Stride in input image pixels at the last conv layer
model.feat_stride                               = 16;

%% stage 1 rpn, inited from pre-trained network
model.stage1_rpn.solver_def_file                = fullfile(pwd, 'models', 'rpn_prototxts', 'ZF', 'solver_60k80k.prototxt');
model.stage1_rpn.test_net_def_file              = fullfile(pwd, 'models', 'rpn_prototxts', 'ZF', 'test.prototxt');
model.stage1_rpn.init_net_file                  = model.pre_trained_net_file;

% rpn test setting
model.stage1_rpn.nms.per_nms_topN              	= -1;
model.stage1_rpn.nms.nms_overlap_thres        	= 0.7;
model.stage1_rpn.nms.after_nms_topN           	= 2000;

%% stage 1 fast rcnn, inited from pre-trained network
model.stage1_fast_rcnn.solver_def_file          = fullfile(pwd, 'models', 'fast_rcnn_prototxts', 'ZF', 'solver_30k40k.prototxt');
model.stage1_fast_rcnn.test_net_def_file        = fullfile(pwd, 'models', 'fast_rcnn_prototxts', 'ZF', 'test.prototxt');
model.stage1_fast_rcnn.init_net_file            = model.pre_trained_net_file;

%% stage 2 rpn, only finetune fc layers
model.stage2_rpn.solver_def_file                = fullfile(pwd, 'models', 'rpn_prototxts', 'ZF_fc6', 'solver_60k80k.prototxt');
model.stage2_rpn.test_net_def_file              = fullfile(pwd, 'models', 'rpn_prototxts', 'ZF_fc6', 'test.prototxt');

% rpn test setting
model.stage2_rpn.nms.per_nms_topN             	= -1;
model.stage2_rpn.nms.nms_overlap_thres       	= 0.7;
model.stage2_rpn.nms.after_nms_topN           	= 2000;

%% stage 2 fast rcnn, only finetune fc layers
model.stage2_fast_rcnn.solver_def_file          = fullfile(pwd, 'models', 'fast_rcnn_prototxts', 'ZF_fc6', 'solver_30k40k.prototxt');
model.stage2_fast_rcnn.test_net_def_file        = fullfile(pwd, 'models', 'fast_rcnn_prototxts', 'ZF_fc6', 'test.prototxt');

%% final test
model.final_test.nms.per_nms_topN            	= 6000; % to speed up nms
model.final_test.nms.nms_overlap_thres       	= 0.7;
model.final_test.nms.after_nms_topN          	= 300;
end


function [res, list] = modality(this, scalp, planar)
% Returns data modality
% FORMAT [res, list] = modality(this, scalp)
%
% scalp - 1 (default) only look at scalp modalities
%         0  look at all modalities
% planar - 1 distinguish between MEG planar and other MEG
%          0 (default) do not distinguish
% If more than one modality is found the function returns 'Multimodal'
% in res and a cell array of modalities in list.
% _______________________________________________________________________
% Copyright (C) 2008-2012 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: modality.m 6542 2015-09-09 11:48:34Z karl $

if nargin == 1
    scalp = 1;
end
if nargin < 3
    planar = 0;
end

list = {};

if ~isempty(indchantype(this, {'MEG', 'MEGPLANAR', 'MEGCOMB'}))
    if planar
        if ~isempty(indchantype(this, 'MEGPLANAR'))
            list = [list {'MEGPLANAR'}];
        end
        if ~isempty(indchantype(this, 'MEG'))
            list = [list {'MEG'}];
        end
        if ~isempty(indchantype(this, 'MEGCOMB'))
            list = [list {'MEGCOMB'}];
        end
    else
        list = [list {'MEG'}];
    end
end

if ~isempty(indchantype(this, 'EEG'))
    list = [list {'EEG'}];
end

if  ~isempty(indchantype(this, 'LFP')) && ~scalp
    list = [list {'LFP'}];
end

if  ~isempty(indchantype(this, 'ILAM')) && ~scalp
    list = [list {'ILAM'}];
end

switch numel(list)
    case 0
        res = 'Other';
    case 1
        res = list{1};
    otherwise
        res = 'Multimodal';
end


 function out = subsref(ob, args)
%function out = subsref(ob, args)
% handle subscript references like ob.ref or ob(ref,:)
% Copyright 2002-2-20, Jeff Fessler, University of Michigan

out = fatrix2_subsref1(ob, args(1)); % handle first subscript

if numel(args) > 1 % handle multiple subscripts, e.g., ob.field()
	out = subsref(out, args(2:end));
end

% fatrix2_subsref1()
function out = fatrix2_subsref1(ob, arg)

switch(arg.type)

case '.' % ob.?
	out = fatrix2_subsref_dot(struct(ob), arg);
	return

case '()' % ob(?)
	subs = arg.subs;

	% A(:,:) or A(:,j)
	if length(subs) == 2 && streq(subs{1}, ':')
		out = fatrix2_subsref_colon(ob, subs{2});

	% A(i,:)
	elseif length(subs) == 2 && streq(subs{2}, ':')
		out = fatrix2_subsref_colon(ob', subs{1})'; % trick: (A'(:,i))'

	% A(i,j)
	elseif length(subs) == 2
		out = fatrix2_subsref_colon(ob, subs{2}); % A(:,j) first
		if numel(subs{2}) > 1
			out = full(out); % fatrix2 to array
		end
		out = out(subs{1},:); % A(i,j) using normal array indexing

	% A(:)
	elseif length(subs) == 1 && streq(subs{1}, ':')
		out = col(fatrix2_subsref_colon(ob, ':')); % col(A(:,:))

	% A(k)
	elseif length(subs) == 1 && isnumeric(subs{1})
		[ii, jj] = ind2sub(size(ob), subs{1});
		out = zeros(numel(jj),1);
		for ll=1:numel(jj)
			tmp = fatrix2_subsref_colon(ob, jj(ll)); % A(:,j)
			out(ll) = tmp(ii(ll)); % A(i,j)
		end

	else
		printm('A subsref of type () called with these args:')
		pr subs
		error('That subsref type is unknown.  Do you mean {1}?')
	end

case '{}' % ob{?} (for ordered-subsets / block methods)
	if length(arg.subs) ~= 1, fail('"{?}" usage'), end

	out = fatrix2_subsref_brace(ob, arg.subs{1});

otherwise
	fail('subscript type %s unknown', arg.type)
end


%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                         %
%              COMMON ROBOT CONFIGURATION PARAMETERS                      %
%                                                                         %
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Init simulator core physics paramaters
physics_config.GRAVITY_ACC = [0,0,-9.81];
physics_config.TIME_STEP = Config.tStepSim;

% Robot configuration for WBToolbox
WBTConfigRobotSim = WBToolbox.Configuration;
WBTConfigRobotSim.RobotName = 'icubSim';
WBTConfigRobotSim.UrdfFile = 'model.urdf';
WBTConfigRobotSim.LocalName = 'WBT';
WBTConfigRobotSim.GravityVector = physics_config.GRAVITY_ACC;

% Controlboards and joints list. Each joint is associated to the corresponding controlboard
WBTConfigRobotSim.ControlBoardsNames = {'torso','left_arm','right_arm','left_leg','right_leg'}; %,'head'};
WBTConfigRobotSim.ControlledJoints = [];
numOfJointsForEachControlboard = [];

ControlBoards = struct();
ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{1}) = {'torso_pitch','torso_roll','torso_yaw'};
ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{2}) = {'l_shoulder_pitch','l_shoulder_roll','l_shoulder_yaw','l_elbow'};
ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{3}) = {'r_shoulder_pitch','r_shoulder_roll','r_shoulder_yaw','r_elbow'};
ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{4}) = {'l_hip_pitch','l_hip_roll','l_hip_yaw','l_knee','l_ankle_pitch','l_ankle_roll'};
ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{5}) = {'r_hip_pitch','r_hip_roll','r_hip_yaw','r_knee','r_ankle_pitch','r_ankle_roll'};
% ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{6}) = {'neck_pitch','neck_roll','neck_yaw'};

for n = 1:length(WBTConfigRobotSim.ControlBoardsNames)
    WBTConfigRobotSim.ControlledJoints = [WBTConfigRobotSim.ControlledJoints, ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{n})];
    numOfJointsForEachControlboard = [numOfJointsForEachControlboard; length(ControlBoards.(WBTConfigRobotSim.ControlBoardsNames{n}))];
end

% structure used to configure the Robot class
%
robot_config.jointOrder = WBTConfigRobotSim.ControlledJoints;
robot_config.numOfJointsForEachControlboard = numOfJointsForEachControlboard;

% Note: Since iDynTree 3.0.0, if meshFilePrefix='', the standard iDynTree workflow of locating the
% mesh via the ExternalMesh.getFileLocationOnLocalFileSystem method is used. The iCub model meshes
% file tree is compatible with this workflow.
robot_config.meshFilePrefix = '';
robot_config.fileName = WBTConfigRobotSim.UrdfFile;
robot_config.N_DOF = numel(WBTConfigRobotSim.ControlledJoints);
robot_config.N_DOF_MATRIX = eye(robot_config.N_DOF);

% Initial condition of iCub and for the integrators.
initialConditions.base_position = [0; 0; 0.619];
initialConditions.orientation = diag([-1, -1, 1]);
initialConditions.w_H_b = mwbs.Utils.Rp2H(initialConditions.orientation, initialConditions.base_position);

% joint (inital) position
initialConditions.s = [
    0; 0; 0; ...
    -35.97; 29.97; 0.06; 50.00; ...
    -35.97; 29.97; 0.06; 50.00; ...
    10; 0; 0; -20; -10; 0; ...
    10; 0; 0; -20; -10; 0]*pi/180;

% velocty initial conditions
initialConditions.base_linear_velocity = [0; 0; 0];
initialConditions.base_angular_velocity = [0; 0; 0];
initialConditions.base_pose_dot = [initialConditions.base_linear_velocity; initialConditions.base_angular_velocity];
initialConditions.s_dot = zeros(robot_config.N_DOF, 1);

robot_config.initialConditions = initialConditions;

% Reflected inertia
robot_config.SIMULATE_MOTOR_REFLECTED_INERTIA = true;
INCLUDE_COUPLING = true;

% Robot frames list
FramesSim.BASE = 'root_link';
FramesSim.IMU = 'imu_frame';
FramesSim.LEFT_FOOT = 'l_sole';
FramesSim.RIGHT_FOOT = 'r_sole';
FramesSim.COM = 'com';

robot_config.robotFrames = FramesSim;

% structure used to configure the Contacts class
%

% foot print of the feet (iCub)
vertex = zeros(3, 4);
vertex(:, 1) = [-0.06; 0.04; 0];
vertex(:, 2) = [0.11; 0.04; 0];
vertex(:, 3) = [0.11; -0.035; 0];
vertex(:, 4) = [-0.06; -0.035; 0];

contact_config.foot_print = vertex;
contact_config.total_num_vertices = size(vertex,2)*2;

% friction coefficient for the feet
contact_config.friction_coefficient = 0.1;

%% Motors reflected inertia

% transmission ratio (1/N)
Gamma                 = 0.01*eye(ROBOT_DOF);

% modify the value of the transmission ratio for the hip pitch.
% TODO: avoid to hard-code the joint numbering
Gamma(end-5, end-5)   = 0.0067;
Gamma(end-11,end-11)  = 0.0067;

% motors inertia (Kg*m^2)
legsMotors_I_m               = 0.0827*1e-4;
torsoPitchRollMotors_I_m     = 0.0827*1e-4;
torsoYawMotors_I_m           = 0.0585*1e-4;
armsMotors_I_m               = 0.0585*1e-4;

% add harmonic drives reflected inertia
legsMotors_I_m           = legsMotors_I_m + 0.054*1e-4;
torsoPitchRollMotors_I_m = torsoPitchRollMotors_I_m + 0.054*1e-4;
torsoYawMotors_I_m       = torsoYawMotors_I_m + 0.021*1e-4;
armsMotors_I_m           = armsMotors_I_m + 0.021*1e-4;

I_m                   = diag([torsoPitchRollMotors_I_m*ones(2,1);
                                     torsoYawMotors_I_m;
                                     armsMotors_I_m*ones(8,1);
                                     legsMotors_I_m*ones(12,1)]);

% parameters for coupling matrices. Updated according to the wiki:
%
% http://wiki.icub.org/wiki/ICub_coupled_joints
%
% and corrected according to https://github.com/robotology/robots-configuration/issues/39
t            = 0.615;
r            = 0.022;
R            = 0.04;

% coupling matrices
T_LShoulder  = [-1  0  0;
                -1 -t  0;
                 0  t -t];

T_RShoulder  = [ 1  0  0;
                 1  t  0;
                 0 -t  t];

T_torso      = [ 0.5    -0.5     0;
                 0.5     0.5     0;
                 r/(2*R) r/(2*R) r/R];

if INCLUDE_COUPLING
    T = blkdiag(T_torso,T_LShoulder,1,T_RShoulder,1,eye(12));
else
    T = eye(robot_config.N_DOF);
end

motorsReflectedInertia = wbc.computeMotorsReflectedInertia(Gamma,T,I_m);

% Joint friction

% === Mapping ===
jointDefaultOrder = {...
    'torso_pitch','torso_roll','torso_yaw', ...
    'l_shoulder_pitch','l_shoulder_roll','l_shoulder_yaw','l_elbow', ...
    'r_shoulder_pitch','r_shoulder_roll','r_shoulder_yaw','r_elbow', ...
    'l_hip_pitch','l_hip_roll','l_hip_yaw','l_knee','l_ankle_pitch','l_ankle_roll', ...
    'r_hip_pitch','r_hip_roll','r_hip_yaw','r_knee','r_ankle_pitch','r_ankle_roll'};

KvmechMappingTorso = 0.2*ones(3,1);
KvmechMappingLeftArm = 0.2*ones(4,1);
KvmechMappingRightArm = 0.2*ones(4,1);
KvmechMappingLeftLeg = [0.2 0.2 0.2 0.2 0.6 0.6]';
KvmechMappingRightLeg = [0.2 0.2 0.2 0.2 0.6 0.6]';

KvmechMapping = containers.Map(...
    jointDefaultOrder, ...
    [
    KvmechMappingTorso
    KvmechMappingLeftArm
    KvmechMappingRightArm
    KvmechMappingLeftLeg
    KvmechMappingRightLeg
    ]);

KvmechMat = diag(cell2mat(KvmechMapping.values(robot_config.jointOrder)));

jointFrictionMat = wbc.computeMotorsReflectedInertia(eye(robot_config.N_DOF),T,KvmechMat);

%% size of the square you see around the robot
visualizerAroundRobot = 1; % mt

clear ControlBoards numOfJointsForEachControlboard FramesSim initialConditions vertex