classdef ParadigmBaseSimplified < ParadigmBase
    % Simplified base class for BCI paradigms.
    %
    % Derive from this class if in your paradigm, calibration is done based on a single data set
    % (i.e. neither dataset collections nor stream bundles are handled meaningfully by it).
    % * you supply a calibrate_simple() function that takes a single recording and derives a model
    %   from it (optionally specifying a filter chain for efficient pre-processing)
    % * you supply a predict_simple() function that takes a single data set and calculates outputs
    %   from it
    % * (optionally, you may specify a visualization function)
    %
    %
    % If your paradigm can be understood as a dataflow model (i.e. a sequence of signal processing,
    % feature extraction, and machine learning), consider deriving from a simpler dataflow base class
    % instead (ParadigmDataflowSimplified).
    %
    % Notes:
    %   Most BCI paradigms (e.g., almost all from before 2008) do not support the full generality of
    %   possible inputs that are allowed by ParadigmBase (the general definition and implementation
    %   contract of a BCI paradigm, see ParadigmBase.m). Instead, firstly, most traditional BCI
    %   paradigms operate during online processing only on a single (multi-channel) signal instead
    %   of multiple concurrent signals, and secondly, most paradigms are initially calibrated based
    %   on a single calibration recording (usually a 30-60 minute recording of calibration data)
    %   instead of a (possibly tagged) collection of multiple data sets. For any such paradigm, the
    %   additional flexibility is useless and the corresponding organizational structure is an
    %   unnecessary implementation burden.
    %
    %   This base class is a refinement of ParadigmBase which omits the additional flexibility and
    %   provides an interface for simple paradigms. Any such paradigm should implement the
    %   calibrate_simple() method and the predict_simple() method, which are the simplified
    %   equivalents the calibrate() and predict() functions in ParadigmBase (without multiple
    %   concurrent streams and without multiple calibration data sets).
    %
    %   There exists a further specialization of this base class, ParadigmDataflowSimplified, which
    %   provides an additional layer of convenience for BCI paradigms that adhere to a standard
    %   "dataflow" (multi-stage) structure. If a paradigm can be expressed as a sequence of signal
    %   processing, feature extraction and machine learning, it is recommended to derive from this
    %   more specialized class instead (see ParadigmDataflowSimplified.m).
    %
    % Name:
    %   Simplified Base Paradigm (abstract)
    %
    %                            Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
    %                            2011-08-28

    methods

        function model = calibrate_simple(self,varargin)
            % Override this function to implement your model calibration code
            % Model = calibrate_simple(Signal,Arguments...)
            %
            % This function defines how a BCI is calibrated (i.e. adapted) to an individual based on
            % a given calibration recording. The calibration recording is a single EEGLAB data set
            % (though may contain arbitrary signal contents) annotated with target markers that
            % contain information about the desired BCI output at various time points in the
            % recording. Based on these markers and the data a relationship between signal contents
            % and the value of some (assumed) 'cognitive state variable' (to be approximated by the
            % BCI's outputs) is inferred by this function and captured in the predictive model
            % returned by it (a struct with any parameters necessary for predict_simple).
            %
            % Implementations of this function should declare at least a parameter named "Signal",
            % plus any desired custom user options. These parameters should be declared using the
            % arg_define() facility to allow the framework to query the parameter names and defaults
            % (e.g. for GUI display). The returned model also describes any signal (pre-)processing that
            % shall be performed by BCILAB before the predict_simple() function is called by it,
            % by means of its .filter_graph field.
            %
            % In:
            %   Signal : a single continuous EEGLAB data set (annotated with target markers; see
            %            set_targetmarkers for more info)
            %
            %   Arguments : further optional user arguments
            %
            % Out:
            %   Model : a model struct with a mandatory field .filter_graph and arbitrary other content
            %           * The .filter_graph filed is a 1x1 cell array that contains the desciption of
            %             filter steps that is to be applied to the data, and is usually passed as either
            %             the .tracking.online_expression field of the processed Signal or the processed
            %             Signal itself. If no signal processing is performed by this paradigm, the raw
            %             signal may be passed.
            %
            %           * May have optional fields .prediction_function, .prediction_window and
            %             .prediction_channels - though these are generally auto-deduced
            %
            %           The rest of the model struct is arbitrary and should contain whatever
            %           parameters are needed by predict_simple() to perform its operation.
            %
            % Notes:
            %   Overridden functions should declare their arguments using arg_define().

            error('This paradigm implements no calibrate_simple() function.');
        end

        function outputs = predict_simple(self,signal,model)
            % Override this function to implement your prediction code
            % Outputs = predict_simple(Signal,Model)
            %
            % This function defines how this BCI paradigm responds to "prediction" queries, i.e.
            % how, for a given piece of signal, an estimate of (or inference about) the user's
            % cognitive state shall be computed. It receives a segment of a pre-processed signal, as
            % well as a predictive model and shall produce an estimate about the most recent sample
            % in the given signal (although it may utilize any previous samples in its computation).
            % The signal is implicitly pre-processed before the function is called as defined by the
            % .filter_graph field of the predictive model (set by the calibrate_simple) function.
            %
            % The signal may also be "epoched", i.e. contain multiple segments, in which case the
            % output of this function shall be an array of predictions (one for each segment).
            %
            % In:
            %   Signal : a signal pre-processed according to the model's filter graph
            %
            %   Model : a predictive model as created by your calibrate_simple() function
            %
            % Out:
            %   Outputs : a prediction/estimate for the most recent time point in the data (or one for
            %             every epoch if the signal is epoched); see ml_predict for the allowed formats

            error('This paradigm implements no predict_simple() function.');
        end

        function visualize(self,model,varargin)
            % Optionally override this function to implement your visualization code
            % visualize(Model)
            %
            % In:
            %   Model: a model as created by your calibrate() function;
            %          a plot or GUI will be produced to inspect the model
            %
            %   Options : cell array or struct of name-value pairs

            error('This paradigm implements no visualize() function.');
        end

        % --- implementation ----

        function model = calibrate(self,varargin)
            % Implementation of the calibrate() function (see ParadigmBase)
            % Model = calibrate(Collection,GoalIdentifier,Arguments...)
            %
            % This is essentially a wrapper around calibrate_simple() which peels off any unused
            % organizational ballast (for multiple collections and stream bundles) before passing it
            % on. If multiple data sets are passed, they are implicitly merged.
            %
            % In:
            %   Collection : a collection (cell array) of stream bundles
            %
            %   GoalIdentifier: the goal-identifier
            %
            %   Arguments... : further optional user arguments
            %
            % Out:
            %   Model : The returned model struct
            dp;

            % separate the collection argument from the rest
            collection = arg_extract(varargin,{'collection','Collection'},[],{});
            remove = find(strcmpi(varargin(1:2:end),'collection'))-1;
            retain = setdiff(1:length(varargin),[1 + 2*remove,2 + 2*remove]);
            varargin = varargin(retain);
            % also remove the goal identifier argument
            remove = find(strcmpi(varargin,'goal_identifier'));
            varargin([remove remove+1]) = [];
            % and extract the signal argument
            if ~isempty(collection)
                % check if any of the data sets in the collection has more than one stream
                if any(cellfun(@(x)length(x.streams) > 1,collection))
                    error('This paradigm does not support more than one stream in parallel.'); end
                if length(collection) == 1
                    signal = collection{1}.streams{1};
                else
                    % merge all data sets in the collection
                    tmp = cellfun(@(x)x.streams{1},collection,'UniformOutput',false);
                    signal = set_concat(tmp{:});
                end
            else
                signal = {};
            end

            % call calibrate_simple with the signal passed in as additional argument
            model = self.calibrate_simple('signal',signal,varargin{:});
        end

        function outputs = predict(self,bundle,model)
            % Override this function to implement your prediction code
            % Outputs = predict(Bundle,Model)
            %
            % This is a wrapper around the predict_simple() function which peels off the stream bundle
            % representation and just passes on the contained signal.
            %
            % In:
            %   Bundle : stream bundle preprocessed by the model's filter graph
            %
            %   Model : a predictive model
            %
            % Out:
            %   Outputs : the outputs of calibrate_simple()
            dp;

            if length(bundle.streams) > 1
                error('This paradigm does not support more than one stream in parallel.'); end
            outputs = self.predict_simple(bundle.streams{1},model);
        end

    end
end

% (turn off a few editor warnings because some actual implementations are missing in this file)
%#ok<*INUSD,*STOUT,*MANU>


function string = utl_printapproach(app,strip_direct,indent,indent_incr,subset)
% Convert an approach to a string representation
% String = utl_printapproach(Approach)
%
% In:
%   Approach : a BCI approach, either designed in the GUI or constructed in a script
%
%   StripDirect : strip arg_direct flags (default: true)
%
%   Indent : initial indent (default: 0)
%
%   IndentIncrement : indentation increment (default: 4)
%
%   Subset : subset of parameters to display; if 'all' then all parameters are printed,
%            and if 'diff' then only those parameters are printed that differ from the defaults
%            of the respective paradigm (default: 'diff')
%
% Out:
%   String : a string representation of the approach, for use in scripts
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2013-10-22

% check inputs
if nargin < 2 || isempty(strip_direct)
    strip_direct = true; end
if nargin < 3 || isempty(indent)
    indent = 0; end
if nargin < 4 || isempty(indent_incr)
    indent_incr = 4; end
if nargin < 5 || isempty(subset)
    subset = 'diff'; end
if ~isa(strip_direct,'logical')
    error('The StripDirect argument must be a logical/boolean value.'); end

% get required approach properties
if ischar(app)
    paradigm = ['Paradigm' app];
    parameters = {};
elseif iscell(app)
    paradigm = ['Paradigm' app{1}];
    parameters = app(2:end);
elseif all(isfield(app,{'paradigm','parameters'}))
    paradigm = app.paradigm;
    parameters = app.parameters;
else
    error('The given data structure is not an approach.');
end

% get a handle to the paradigm's calibrate() function
try
    instance = eval(paradigm);
catch e
    if ~exist(char(paradigm),'file')
        error('A BCI paradigm with name %s does not exist.',char(paradigm));
    else
        error('Failed to instantiate the paradigm named %s with error: %s; this is likely an error in the Paradigm''s code.',char(paradigm),e.message);
    end
end
func = @instance.calibrate;

% report the defaults of the paradigm
defaults = clean_fields(arg_report('rich',func));

% report the current settings of the paradigm in form of an argument specification
settings = clean_fields(arg_report('lean',func,parameters));

% get the difference between the defaults and settings
if strcmp(subset,'diff')
    specdiff = arg_diff(defaults,settings);
elseif strcmp(subset,'all')
    specdiff = settings;
else
    error('Unsupported subset: %s',hlp_tostring(subset,100));
end

% convert to nested cell arrays of human-readable name-value pairs
difference = arg_tovals(specdiff,[],'HumanReadableCell',false);

% pre-pend the paradigm choice
paradigm_name = char(paradigm);
difference = [{'arg_selection',paradigm_name(9:end)} difference];

% and convert to string
string = arg_tostring(difference,strip_direct,indent,indent_incr);

% clean fields of x, by removing all arg_direct instances and
% all skippable fields
function x = clean_fields(x)
x(strcmp({x.first_name},'arg_direct') | [x.skippable]) = [];
try
    children = {x.children};
    empty_children = cellfun('isempty',children);
    [x(~empty_children).children] = celldeal(cellfun(@clean_fields,children(~empty_children),'UniformOutput',false));
catch %#ok<CTCH>
end


% this function return the transformer's (input argument) loss
function FValue=SP_tlosscost1(InValue)

global KWTransformersTypes OpenCircuitLosses
Tag = find(KWTransformersTypes == InValue);
FValue = OpenCircuitLosses(1,Tag);


function neighborsCell = identifyNeighborsAuto(inputImages, inputSignals, varargin)
	% This code automatically sorts through to find all obj neighbors within a certain distance of the target (boundary to boundary). The output is a cell array with vectors of the neighbor indices to each obj.
	% Biafra Ahanonu
	% started: 2013.11.01
	% based on code by laurie burns, started: sept 2010.
	% inputs
		% inputImages - [x y nCells] matrices containing each set of filters
		% inputSignals - [nFilters frames] matrices containing each set of filter traces
	% options
		% _
	% outputs
		% _

	[neighborsCell] = ciapkg.neighbor.identifyNeighborsAuto(inputImages, inputSignals,'passArgs', varargin);
end


function [data,stats] = ExpPPHeadless(expdirs,jabfiles,varargin)

[paramsfile,statframelimits] = myparse(varargin,'paramsfile','ExpPP.params.txt',...
  'statframelimits',[-inf,inf]);

data = ExpPP.loadexps(expdirs,jabfiles);
data = ExpPP.ensureCustomGroupInit(data);
params = ReadParams(paramsfile);

statframelimits(end) = min(statframelimits(end),max([data.trxt1]));
computeparams = {'statframelimits' statframelimits};

[data,stats] = ExpPP.computeStats(data,params{:},computeparams{:});

% possibly not the cleanest way to do this, copy-pasted
function params = ReadParams(paramsfile)

fh = fopen(paramsfile);
if isequal(fh,-1)
  error('ExpPPHeadless:errRead','Cannot read postprocessing parameter file.');
end
out = textscan(fh,'%s%s%s%s%s','delimiter',',','collectoutput',true);
fclose(fh);
out = out{1};
assert(isequal(out(1,:),{'name' 'type' 'nanok' 'default' 'desc'}));
out = out(2:end,:);
tbl = struct();
tbl.name = out(:,1);
tbl.type = out(:,2);
tbl.nanok = str2double(out(:,3));
tbl.default = str2double(out(:,4));
tbl.desc = out(:,5);
data = [tbl.name num2cell(tbl.default) tbl.desc];
params = struct();
for i = 1:size(data,1)
  prm = data{i,1};
  val = data{i,2};

  assert(strcmp(prm,tbl.name{i}));

  % check val
  if isnan(val)
    if tbl.nanok(i)
      % none
    else
      warningNoTrace('ExpPPControl:nanVal',...
        'Parameter ''%s'' cannot be NaN. Using default value of %d.\n',...
        prm,tbl.default(i));
      val = tbl.default(i);
    end
  else
    switch tbl.type{i}
      case 'nat'
        if floor(val)~=val
          warningNoTrace('ExpPPControl:fracVal',...
            'Parameter ''%s'' should be an integer. Rounding to %d.\n',prm,round(val));
          val = round(val);
        end
        if val<0
          warningNoTrace('ExpPPControl:negVal',...
            'Parameter ''%s'' cannot be negative. Using 0.\n',prm);
          val = 0;
        end
      otherwise
        assert(false,'All types currently nat');
    end
  end

  % assign
  subparams = regexp(prm,'#','split');
  switch numel(subparams)
    case 1
      params.(subparams{1}) = val;
    case 2
      params.(subparams{1}).(subparams{2}) = val;
    otherwise
      assert(false,'Unexpected parameter.');
  end
end

params = struct2paramscell(params);


clear all
close all

wing_tp

wing_lmi

wing_sim


function [nev] = read_neuralynx_nev(filename, varargin);

% READ_NEURALYNX_NEV reads the event information from the *.nev file in a
% Neuralynx dataset directory
%
% Use as
%   nev = read_neuralynx_hdr(datadir, ...)
%   nev = read_neuralynx_hdr(eventfile, ...)
%
% Optional input arguments should be specified in key-value pairs and may include
%   implementation  should be 1, 2 or 3 (default = 3)
%   value           number or list of numbers
%   mintimestamp    number
%   maxtimestamp    number
%   minnumber       number
%   maxnumber       number
%
% The output structure contains all events and timestamps.

% Copyright (C) 2005, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% 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: read_neuralynx_nev.m 2885 2011-02-16 09:41:58Z roboos $

% get the optional input arguments
flt_value        = keyval('value', varargin);
flt_mintimestamp = keyval('mintimestamp', varargin);
flt_maxtimestamp = keyval('maxtimestamp', varargin);
flt_minnumber    = keyval('minnumber', varargin);
flt_maxnumber    = keyval('maxnumber', varargin);
implementation   = keyval('implementation', varargin); if isempty(implementation), implementation = 3; end

if ft_filetype(filename, 'neuralynx_ds')
  % replace the directory name by the filename
  if     exist(fullfile(filename, 'Events.Nev'))
    filename = fullfile(filename, 'Events.Nev');
  elseif exist(fullfile(filename, 'Events.nev'))
    filename = fullfile(filename, 'Events.nev');
  elseif exist(fullfile(filename, 'events.Nev'))
    filename = fullfile(filename, 'events.Nev');
  elseif exist(fullfile(filename, 'events.nev'))
    filename = fullfile(filename, 'events.nev');
  end
end

% The file starts with a 16*1024 bytes header in ascii, followed by a
% number of records (c.f. trials).
%
% The format of an event record is
%   int16 PktId
%   int16 PktDataSize
%   int64 TimeStamp
%   int16 EventId
%   int16 TTLValue
%   int16 CRC
%   int32 Dummy
%   int32 Extra[0]
%   ...
%   int32 Extra[7]
%   char EventString[0]
%   ...
%   char EventString[127]
% PktId is usually 0x1002.
% PktDataSize is random data.
% Dummy is random data.
% CRC may contain random data.
% Extra is user-defined data.
% TTLValue is the value sent to the computer on a parallel input port.

fid = fopen(filename, 'rb', 'ieee-le');

headersize = 16384;
offset     = headersize;
if ~isempty(flt_minnumber)
  offset = offset + (flt_minnumber-1)*184;
end

nev = [];

if implementation==1
  if ~isempty(flt_maxnumber)
    warning('filtering on maximum number not yet implemneted');
  end
  % this is the slow way of reading it
  % it also does not allow filtering
  fseek(fid, offset, 'bof');
  while ~feof(fid)
    nev(end+1).PktStart     = fread(fid, 1, 'int16');
    nev(end  ).PktId        = fread(fid, 1, 'int16');
    nev(end  ).PktDataSize  = fread(fid, 1, 'int16');
    nev(end  ).TimeStamp    = fread(fid, 1, 'uint64');
    nev(end  ).EventId      = fread(fid, 1, 'int16');
    nev(end  ).TTLValue     = fread(fid, 1, 'uint16');
    nev(end  ).CRC          = fread(fid, 1, 'int16');
    nev(end  ).Dummy        = fread(fid, 1, 'int32');
    nev(end  ).Extra        = fread(fid, 8, 'int32');
    nev(end  ).EventString  = fread(fid, 128, 'char');
  end
end

if implementation==2
  if ~isempty(flt_maxnumber)
    warning('filtering on maximum number not yet implemneted');
  end
  % this is a faster way of reading it and it is still using the automatic type conversion from Matlab
  fp = offset;
  fseek(fid, fp+ 0, 'bof'); PktStart       = fread(fid, inf, 'uint16', 184-2);
  num = length(PktStart);
  fseek(fid, fp+ 2, 'bof'); PktId          = fread(fid, num, 'uint16', 184-2);
  fseek(fid, fp+ 4, 'bof'); PktDataSize    = fread(fid, num, 'uint16', 184-2);
  fseek(fid, fp+ 6, 'bof'); TimeStamp      = fread(fid, num, 'uint64=>uint64', 184-8);
  fseek(fid, fp+14, 'bof'); EventId        = fread(fid, num, 'uint16', 184-2);
  fseek(fid, fp+16, 'bof'); TTLValue       = fread(fid, num, 'uint16', 184-2);
  fseek(fid, fp+18, 'bof'); CRC            = fread(fid, num, 'uint16', 184-2);
  fseek(fid, fp+22, 'bof'); Dummy          = fread(fid, num, 'int32' , 184-4);
  % read each of the individual extra int32 values and concatenate them
  fseek(fid, fp+24+0*4, 'bof'); Extra1     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+1*4, 'bof'); Extra2     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+2*4, 'bof'); Extra3     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+3*4, 'bof'); Extra4     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+4*4, 'bof'); Extra5     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+5*4, 'bof'); Extra6     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+6*4, 'bof'); Extra7     = fread(fid, num, 'int32', 184-4);
  fseek(fid, fp+24+7*4, 'bof'); Extra8     = fread(fid, num, 'int32', 184-4);
  Extra = [Extra1 Extra2 Extra3 Extra4 Extra5 Extra6 Extra7 Extra8];
  % read the complete data excluding header as char and cut out the piece with the EventString content
  fseek(fid, fp, 'bof'); EventString        = fread(fid, [184 num], 'char');
  EventString = char(EventString(57:184,:)');
end

if implementation==3
  % this is an even faster way of reading it
  if isempty(flt_minnumber)
    flt_minnumber = 1;
  end
  if isempty(flt_maxnumber)
    flt_maxnumber = inf;
  end
  if fseek(fid, offset, 'bof')~=0
    error(ferror(fid));
  end
  buf = fread(fid, (flt_maxnumber-flt_minnumber+1)*184, 'uint8=>uint8');
  [PktStart, PktId , PktDataSize , TimeStamp , EventId , TTLValue , CRC , Dummy , Extra1 , Extra2 , Extra3 , Extra4 , Extra5 , Extra6 , Extra7 , Extra8 , EventString] = ...
    cstructdecode(buf, 'int16', 'int16', 'int16', 'uint64', 'int16', 'uint16', 'int16', 'int32', 'int32', 'int32', 'int32', 'int32', 'int32', 'int32', 'int32', 'int32', 'char128');
  % the cstructdecode function does not respect the byte order for other-endian numbers
  if bigendian
    PktStart     = swapbytes(PktStart);
    PktId        = swapbytes(PktId);
    PktDataSize  = swapbytes(PktDataSize);
    TimeStamp    = swapbytes(TimeStamp);
    EventId      = swapbytes(EventId);
    TTLValue     = swapbytes(TTLValue);
  % CRC          = swapbytes(CRC);
  % Dummy        = swapbytes(Dummy);
  % Extra1       = swapbytes(Extra1);
  % Extra2       = swapbytes(Extra2);
  % Extra3       = swapbytes(Extra3);
  % Extra4       = swapbytes(Extra4);
  % Extra5       = swapbytes(Extra5);
  % Extra6       = swapbytes(Extra6);
  % Extra7       = swapbytes(Extra7);
  % Extra8       = swapbytes(Extra8);
  end
end

fclose(fid);

if implementation~=1
  % make a selection of events
  sel = true(size(TTLValue));
  if ~isempty(flt_mintimestamp)
    sel = sel & (TimeStamp>=flt_mintimestamp);
  end
  if ~isempty(flt_maxtimestamp)
    sel = sel & (TimeStamp<=flt_maxtimestamp);
  end
  if ~isempty(flt_value)
    tmp = false(size(sel));
    for i=1:length(flt_value)
      tmp = tmp | (TTLValue==flt_value(i));
    end
    sel = sel & tmp;
  end

  % restructure the data into a struct array, by first making cell-arrays out of it ...
  numsel = sum(sel);
  PktStart      = mat2cell(PktStart(sel)     , ones(1,numsel), 1);
  PktId         = mat2cell(PktId(sel)        , ones(1,numsel), 1);
  PktDataSize   = mat2cell(PktDataSize(sel)  , ones(1,numsel), 1);
  TimeStamp     = mat2cell(TimeStamp(sel)    , ones(1,numsel), 1);
  EventId       = mat2cell(EventId(sel)      , ones(1,numsel), 1);
  TTLValue      = mat2cell(TTLValue(sel)     , ones(1,numsel), 1);
  % CRC           = mat2cell(CRC(sel)          , ones(1,numsel), 1);
  % Dummy         = mat2cell(Dummy(sel)        , ones(1,numsel), 1);
  % Extra1        = mat2cell(Extra1(sel)       , ones(1,numsel), 1);
  % Extra2        = mat2cell(Extra2(sel)       , ones(1,numsel), 1);
  % Extra3        = mat2cell(Extra3(sel)       , ones(1,numsel), 1);
  % Extra4        = mat2cell(Extra4(sel)       , ones(1,numsel), 1);
  % Extra5        = mat2cell(Extra5(sel)       , ones(1,numsel), 1);
  % Extra6        = mat2cell(Extra6(sel)       , ones(1,numsel), 1);
  % Extra7        = mat2cell(Extra7(sel)       , ones(1,numsel), 1);
  % Extra8        = mat2cell(Extra8(sel)       , ones(1,numsel), 1);
  EventString   = mat2cell(EventString(sel,:), ones(1,numsel), 128);
  EventNumber   = mat2cell(find(sel) + flt_minnumber - 1, ones(1,numsel), 1); % this helps in the external filtering for BCI
  % ... and then convert the cell-arrays into a single structure
  nev = struct(...
    'PktStart'    , PktStart     , ...
    'PktId'       , PktId        , ...
    'PktDataSize' , PktDataSize  , ...
    'TimeStamp'   , TimeStamp    , ...
    'EventId'     , EventId      , ...
    'TTLValue'    , TTLValue     , ...
    'EventString' , EventString  , ...
    'EventNumber' , EventNumber);
end

% remove null values and convert to strings
for i=1:length(nev)
  nev(i).EventString = nev(i).EventString(find(nev(i).EventString));
  nev(i).EventString = char(nev(i).EventString(:)');
end


function [ dData, iLC, iEvalInfoMask, drecksMDH, iLCPositions ] = fMeas_main( sFilename, lReadData, measReadPara )
%FMEAS_MAIN main function for extracting Data, Loop counters, evalInfoMask
% and drecksMDH
%
% (c) Christian Wuerslin, Thomas Kuestner
% ---------------------------------------------------------------------

if(nargin < 1)
    [sFile, sPath] = uigetfile({'*.dat', 'ADC meas files (*.dat)'},'Select measurement file', pwd);
    sFilename = [sPath,filesep,sFile];
end

if(nargin < 2)
    lReadData = true;
end

% input read parameter
if(nargin < 3)
    % Set, Seg, Smp
    measReadPara = {[0 inf], [0 64999], [21 inf]}; % for CS_Trufi and CS_Flash, CS_Flash_Retro, CS_EPI
end

[sPath, sName, sExt] = fileparts(sFilename);

if(~exist(fullfile(sPath,[sName,'.mat']),'file'))
    fprintf('Creating look-up table for measdata file\n');
    fMeasCreateLUT_main(sFilename);
end

% load data
if(lReadData)
    [dData, iLC, iEvalInfoMask] = fMeasRead(fullfile(sPath,[sName,sExt]), 'Set', measReadPara{1}, 'Seg', measReadPara{2}, 'Smp', measReadPara{3});
else
    dData = [];
    iLC = [];
    iEvalInfoMask = [];
end
matfile = whos('-file', fullfile(sPath,[sName,'.mat']));
if(ismember('iLCDrecks', {matfile.name}) && ismember('iLCPositions', {matfile.name}))
    % drecksMDH 1.0
    [drecksMDH, iLCPositions] = fMeasReadDrecksMDH(fullfile(sPath,[sName,sExt]));

elseif(ismember('SDrecksMDH', {matfile.name}))
    % drecksMDH 2.0
    load(fullfile(sPath,[sName,'.mat']), 'SDrecksMDH');
    drecksMDH = SDrecksMDH;
    iLCPositions = [];
else
    % no drecksMDH at all
    drecksMDH = [];
    iLCPositions = [];
end

end


function ui = mrViewROI(command, ui, varargin);
% ROI Editing and Display functions for mrViewer.
%
% ui = mrViewROI(command, ui, [options]);
%
% [The format is a bit of a break from the usual way of
% specifying the ui first, b/c the ui is usually omitted
% and the active one found w/ mrViewGet, but the command
% is always necessary]
%
% This function incorporates several small commands, which interact
% between the ROI tools and the mrViewer GUI. The commands are:
%   'new': create a new empty ROI
%
%   'add': add coords to the ROI, according to the current edit mode
%
%   'remove': remove coords from the ROI, according to the curr edit mode
%
%   'delete': delete an ROI, prompting with a dialog if one isn't specified
%
%   'draw': re-draw rois according to current view settings
%
%   'edit': edit selected ROI properties
%
%   'select': set selected ROI. If an extra 3rd argument is passed, which
%             is either an index into the ROI list, or a name of an ROI,
%             will select that ROI. Otherwise will select based on the
%             ROI select popup in the ROI panel.
%
%   'restrict': restrict ROI coordinates to within the overlays currently
%             being displayed. (Overlays in which the 'hide' option is
%             selected won't affect this.) mrView('restrict', ui, 'all')
%             will cause all ROIs to be restricted. Otherwise, the selected
%             ROI only will be restricted.
%
%   'load':   load a mrVista ROI into the viewer. The Session GUI must be
%             open for this.
%
%   'save':   save selected ROI in mrVista format. Will save as an Inplane
%             or Volume ROI, depending on the ROI's 'viewType' property.
%             (Edit the ROI to change this.)
%
%   'mesh':   If a mesh is opened, get the ROI points drawn on the mesh
%             as a new ROI. An optional mapping argument can be specified,
%             which determines how to grab the mesh ROI: it can be
%             'layer1', in which case only gray layer 1 nodes are drawn in the
%             new ROI, or 'all', in which case all layers are mapped. If
%             this option is omitted, defaults to using the 'layerMapMode'
%             pref in mrmPreferences.
%
%	'meshgrow': grow an ROI along the cortical surface, using the viewer's
%			  overlay settings to determine the boundaries of the ROI. The
%			  ROI will be a contiguous patch on the cortical surface
%			  bounded by the overlay conditions. (Note that if no
%			  thresholding is specified, the code will warn you and not
%			  make an ROI.) By default the ROI is grown starting from the
%			  mesh cursor. However, an alternate start coordinate can be
%			  specified as an optional input argument.
%
%   'disk':   If a gray-matter segmentation is installed, create a disk
%             ROI along the gray matter. ('disc' also works.) An optional
%             size argument can be specified, which determines the radius
%             of the disc in mm. If omitted, prompts the user.
%
%   'gray':   Create ROI containing all gray matter nodes for the selected
%             segmentation. (If a segmentation is loaded.)
%
% If called with no arguments, instead of returning a ui struct,
% mrViewROI will return the currently-selected ROI in the viewer.
%
% ras 08/05
if notDefined('ui'),        ui = mrViewGet;                         end
if ishandle(ui),            ui = get(ui, 'UserData');               end
if notDefined('command'),   ui = ui.rois(ui.settings.roi); return;  end

if ~isfield(ui,'display'), error('Need an active display');         end

% ras 03/07: I used to have a 'switch' command here, but it got pretty
% long, so I broke each command into its own subfunction to make finding a
% sub-command easier. This m-file has a lot of subfunctions! I'll probably
% move the dedicated ROI stuff (roi*Coords) to their own m-files soon...

% allow british spelling of the 'disk' command :)
if isequal(lower(command), 'disc'), command = 'disk'; end

% this switchyard will call the relevant sub-command functions
subfun = sprintf('mrView%s%sROI', upper(command(1)), lower(command(2:end)));
% try
	ui = feval(subfun, ui, varargin);
% catch
% 	error('Unknown command.')
% end

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewNewROI(ui, varargin);
%%%%%Create a new, empty ROI (and select it)
roi = roiCreate(ui.mr, []);
roi.name = sprintf('ROI%i',length(ui.rois)+1);
roi.lineHandles = []; % for drawing ROIs
roi.prevCoords = []; % for undo
if isempty(ui.rois), ui.rois=roi; else, ui.rois(end+1)=roi; end
ui.settings.roi = length(ui.rois); % select it

% select the ROI
mrViewROI('select', ui, length(ui.rois));
return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewAddROI(ui, varargin)
%%%%%Add to current ROI, using selected method
% If no rois exist, make a new one
if isempty(ui.rois), ui = mrViewROI('new',ui);    end

% get new coords using selected method
method = ui.settings.roiEditMode;
switch method
	case 1, coords = roiRectCoords(ui);
	case 2, coords = roiCircleCoords(ui);
	case 3, coords = roiCubeCoords(ui);
	case 4, coords = roiSphereCoords(ui);
	case 5, coords = roiLineCoords(ui);
	case 6, coords = roiPointCoords(ui);
	case 7, coords = roiGrowCoords(ui);
end

% round and remove redundant
coords = round(coords);
coords = intersectCols(coords, coords);

% add to ROI
roi = ui.rois(ui.settings.roi);
roi.coords = [roi.coords coords];
roi.coords = intersectCols(roi.coords, roi.coords); % rm redundant
roi.modified = datestr(clock);
ui.rois(ui.settings.roi) = roi;

% show changes
mrViewROI('draw',ui);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewRemoveROI(ui, varargin);
%%%%%Remove points from current ROI, using selected method
% If no rois exist, exit quietly
if isempty(ui.rois), return;  end

% get coords to remove using selected method
method = ui.settings.roiEditMode;
switch method
	case 1, coords = roiRectCoords(ui);
	case 2, coords = roiCircleCoords(ui);
	case 3, coords = roiCubeCoords(ui);
	case 4, coords = roiSphereCoords(ui);
	case 5, coords = roiLineCoords(ui);
	case 6, coords = roiPointCoords(ui);
	case 7, coords = roiGrowCoords(ui);
end

% remove coords from ROI
roi = ui.rois(ui.settings.roi);
[ignore oldInd] = setdiff(roi.coords', coords', 'rows');
roi.coords = roi.coords(:,sort(oldInd)); % preserve voxel order
roi.modified = datestr(clock);
ui.rois(ui.settings.roi) = roi;

% show changes
mrViewROI('draw', ui);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewDeleteROI(ui, varargin);
%%%%%Delete an ROI from the UI
varargin = unNestCell(varargin);
% (optional arg is list of ROIs to delete)
if isempty(varargin)
	delRoi = ui.settings.roi;
elseif isequal(lower(varargin{1}),'all')
	delRoi = 1:length(ui.rois);
else
	delRoi = varargin{1};
end

% if we don't have any ROIs and try to delete, don't sweat it
if isempty(ui.rois), return; end

% indices of non-deleted ROIs
newInd = setdiff(1:length(ui.rois), delRoi);

% figure out what the selected ROI index will be after we delete
if ismember(ui.settings.roi, delRoi)
	% selected ROI was deleted -- select last one in list
	selRoi = length(newInd);
else
	% selected ROI was not deleted -- but its index may have
	% changed. Figure out the new index.
	selRoi = ui.rois(ui.settings.roi).name; % can select by name
end

% now, delete -- keep only non-deleted ROIs
ui.rois = ui.rois(newInd);

% set a new selected ROI
mrViewROI('select', ui, selRoi);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewLoadROI(ui);
%%%%%Load an ROI
% mrVista 2, back-compatible version: load from GUI
sessionGUI_loadROI;
return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewSaveROI(ui, varargin);
%%%%%Save an ROI
varargin = unNestCell(varargin);
% for now, we save to a back-compatible mrVista 1 format.
if ~isempty(varargin) & isequal(varargin{1}, 'all')
	roiList = 1:length(ui.rois);
else
	roiList = ui.settings.roi;
end

for r = roiList
	mrViewSave(ui, r, 'roi');
end

% update the sessionGUI to include this ROI
sessionGUI_selectROIType;

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewRestrictROI(ui, varargin);
%%%%%Restrict ROI(s) to within overlays
% (If no overlays, don't restrict -- would just delete ROI)
if isempty(ui.overlays), return; end

varargin = unNestCell(varargin);
if ~isempty(varargin) & isequal(lower(varargin{1}), 'all')
	roiList = 1:length(ui.rois);
else
	roiList = ui.settings.roi;
end

for r = roiList
	roi = ui.rois(r);
	hidden = [ui.overlays.hide];
	roi.coords = mrViewRestrict(ui, roi.coords, find(~hidden));
	roi.modified = datestr(clock);
	ui.rois(r) = roi;
end

% show changes
ui = mrViewROI('draw',ui);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewEditROI(ui, varargin);
%%%%%Edit/view ROI traits, such as name/color
if isempty(ui.rois)
	myWarnDlg('No ROIs Created Yet.');
	return
end
roi = ui.rois(ui.settings.roi);
roi = roiEdit(roi);
ui.rois(ui.settings.roi) = roi;

% show changes (updating popup in this call)
try, ui = mrViewROI('draw', ui); end

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewDrawROI(ui, varargin);
%%%%%Draw rois on display
% delete any existing ROI lines
for ax = ui.display.axes
	delete(findobj('Parent', ax, 'Type', 'line', 'Tag', 'ROI'));
end

% get list of ROIs to draw, based on ROI view mode
if ui.settings.roiViewMode==1 | isempty(ui.rois)
	% hide ROIs, or no ROIs -- return quietly
	for r = 1:length(ui.rois)
		ui.rois(r).lineHandles = [];
	end
	set(ui.fig, 'UserData' ,ui);
	return
elseif ui.settings.roiViewMode==2 % show selected
	roiList = ui.settings.roi;
else,                              % show all
	roiList = 1:length(ui.rois);
end

% draw all selected ROIs on displayed images
for i = 1:length(ui.display.images)
	for r = roiList
		% find ROI points which may lie in image
		C = ui.rois(r).coords;
		if ui.settings.space==1
			% pixel space, use ROI coords directly
			if isempty(C), pts = [];
			else, pts = C(1:2,C(3,:)==ui.display.slices(i));
			end
		else
			% get ROI coords which correspond to imaged
			% region
			imgCoords = round(mrViewGet(ui,'DataCoords',i));
			[ignore ind] = intersectCols(imgCoords,C);
			imgSz = size(ui.display.images{i}); imgSz = imgSz(1:2);
			[rows cols] = ind2sub(imgSz,ind);
			AX = [get(ui.display.axes(i), 'XLim') ...
				  get(ui.display.axes(i), 'YLim')]; % will have to account for axis bounds
			pts = [rows+AX(3)-1 cols+AX(1)-1]';
		end

		% draw points, taking preferences into account
		if ~isempty(pts)
			prefs.color = ui.rois(r).color;
			prefs.axesHandle = ui.display.axes(i);
			prefs.method = cellfind({'perimeter' 'filled' 'patches'}, ...
									ui.rois(r).fillMode);
			if r==ui.settings.roi
				prefs.lineStyle = '-';
				prefs.lineWidth = 1;
				prefs.color = 'w';
			else
				prefs.lineStyle = ':';
				prefs.lineWidth = 0.2;
			end
			axes(ui.display.axes(i));
			ui.rois(r).lineHandles = outline(pts,prefs);
			set(ui.rois(r).lineHandles, 'Tag', 'ROI');
		end
	end
end

% update changes in UI
set(ui.fig, 'UserData', ui);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewSelectROI(ui, varargin);
%%%%%Set selected ROI
% parse the ROI specification
varargin = unNestCell(varargin);
if isempty(varargin)  % get from selected ROI
	selRoi = get(ui.controls.roiSelect, 'Value');
elseif isnumeric(varargin{1}) % ROI index
	selRoi = varargin{1};
elseif ischar(varargin{1}) % ROI name
	selRoi = cellfind({ui.rois.name}, varargin{1});
else
	error('Invalid ROI specification.')
end

ui.settings.roi = selRoi;

% update selected ROI popup if it exists
ui = updateROIPopup(ui);

try,   mrViewROI('draw', ui);   end

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewMeshROI(ui, varargin);
%%%%%Get Mesh ROI
msh = mrViewGet(ui, 'CurMesh');
if isempty(msh), myErrorDlg('No Mesh Loaded.'); end
varargin = unNestCell(varargin);
if isempty(varargin)    % get map method via mrmPreferences
	prefs = mrmPreferences;
	mapMethod = lower(prefs.layerMapMode);
else
	mapMethod = lower(varargin{1});
end

seg = mrViewGet(ui, 'CurSegmentation');
roi = roiFromMesh(seg, mapMethod, ui.mr);
ui = mrViewSet(ui, 'NewROI', roi);
try,   mrViewROI('draw', ui);   end
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewMeshgrowROI(ui, varargin);
%%%%%Grow Mesh ROI along cortical surface
msh = mrViewGet(ui, 'CurMesh');
if isempty(msh), myErrorDlg('No Mesh Loaded.'); end

% get xform between the data and the I|P|R (mesh) coordinates
ii = cellfind( {ui.spaces.name}, 'I|P|R' );
xform = ui.spaces(ii).xform;

% get start coord (in base coordinate space)
varargin = unNestCell(varargin);
if isempty(varargin)
	% xform cursor position into base space
	startCoord = mrmGet(msh, 'CursorPosition');
	startCoord = coordsXform(inv(xform), startCoord);
else
	startCoord = varargin{1};
end

% xform the segmentation's nodes/edges into the base coordinate space, too
seg = mrViewGet(ui, 'segmentation');
seg.nodes([2 1 3],:) = coordsXform( inv(xform), seg.nodes([2 1 3],:) )';
seg.nodes(1:3,:) = round(seg.nodes(1:3,:));

% get gray matter node corresponding to the start coord
startCoord = floor(startCoord);
startNode = find( seg.nodes(2,:)==startCoord(1) & ...
				  seg.nodes(1,:)==startCoord(2) & ...
				  seg.nodes(3,:)==startCoord(3) );
if isempty(startNode)
	myWarnDlg( sprintf('Node not found for start coordinate %s.', ...
					num2str(startCoord)) );
	return
end

%% get data mask based on overlays, thresholds
mask3D = mrViewGet(ui, 'OverlayMask');
sz = size(mask3D);

% index mask according to the nodes
mask = logical( zeros(1, size(seg.nodes, 2)) );
allNodes = seg.nodes;
keep = find( allNodes(1,:) > 0 & allNodes(2,:) < sz(1) & ...
			allNodes(2,:) > 0 & allNodes(1,:) < sz(2) & ...
			allNodes(3,:) > 0 & allNodes(3,:) < sz(3) );
allNodes = allNodes(:,keep);
I = sub2ind( size(mask3D), allNodes(1,:), allNodes(2,:), allNodes(3,:) );
mask(I) = mask3D(I);
% clear mask3D

% does the start node pass the criterion? If not, we shouldn't make an ROI
% with it:
if mask(startNode)==0
	myWarnDlg('The selected start point doesn''t pass the threshold.');
	return
end

%% initialize an empty ROI
roi = roiCreate(ui.mr);
roi.name = ['Mesh ROI ' num2str(startCoord)];
roi.comments = sprintf(['Created by %s ''Meshgrow'' grown from seed %s'], mfilename, ...
						num2str(startCoord));

%% main part: "grow" coords in ROI (recursive)
h = msgbox('Growing Mesh ROI', mfilename);
iNodes = growMeshROICoords(startNode, seg, mask);
close(h);

roi.coords = coordsXform( inv(xform), seg.nodes([2 1 3],iNodes) );

%% add ROI to viewer
ui = mrViewSet(ui, 'AddAndSelectROI', roi);

return
% /-----------------------------------------------------------------/ %

% /-----------------------------------------------------------------/ %
function nodes = growMeshROICoords(nodes, seg, mask);
% recursive function designed to grow mesh ROI coordinates.
% The logic here is: the nodes passed in are all voxels that will
% definitely be included in the mesh ROI. The code looks at neighboring
% voxels (according to the gray matter nodes/edges), evalautes them for
% inclusion (mask==1), and selects those which pass the test.
% If there are any of these neighbors, the function is called again, now
% looking at the neighbors of these neighbors.

%% find neighbors of the input nodes
neighbors = [];
for n = nodes
	nEdges = seg.nodes(4,n);
	startEdge = seg.nodes(5,n);
	neighbors = [neighbors seg.edges(startEdge:startEdge+nEdges-1)];
end

%% which neighbors are contained in the mask?
neighbors = neighbors(mask(neighbors)==1);

% prevent the recursion from bouncing back and forth:
% some of these neighbors may already be included in nodes. Remove them;
% they're obviously okay.
% (If I didn't do this, then if A points to B, and B points to A, and both
% satisfy the criteria, the function would keep getting called, first with
% A as the neigbor, then B, then A, etc...)
neighbors = setdiff(neighbors, nodes);

%% do any neighbors pass the test?
% if no, we're done. If yes, we recurse: call this function on the existing
% nodes plus the neighbors:
if ~isempty(neighbors)
	nodes = growMeshROICoords([nodes neighbors], seg, mask);
end

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewDiskROI(ui, varargin);
%%%%%Create Disk ROI
varargin = unNestCell(varargin);
if isempty(varargin)    % get disk size via dialog
	q = {'Size of Gray Matter Disk?'};
	resp = inputdlg(q, 'Make Disk ROI', 1, {'3'});
	radius = str2num(resp{1});
else
	radius = varargin{1};
end

roi = roiGrayDisk(mrViewGet(ui, 'CurSegmentation'), ui.mr, radius);
ui = mrViewSet(ui, 'AddAndSelectROI', roi);
ui = mrViewRecenter(ui, 'roi');
try,   mrViewROI('draw', ui);   end
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = mrViewGrayROI(ui, varargin);
%%%%%Create Gray Matter ROI
seg = mrViewGet(ui, 'CurSegmentation');
roi = roiGrayAll(seg, ui.mr);
ui = mrViewSet(ui, 'newROI', roi);

try,   mrViewROI('draw', ui);   end

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiRectCoords(ui);
% Get points from the user specifying a rectangle on the mrViewer display,
% and compute a 3xN list of coordinates which that input represents.
figure(ui.fig);
tmp = get(ui.panels.display,'BackgroundColor');
set(ui.panels.display,'BackgroundColor','y');
hmsg = mrMessage('Select Corners of Rectangle');
[X Y] = ginput(2);
X = round(X); Y = round(Y);
set(ui.panels.display,'BackgroundColor',tmp);
close(hmsg);

% figure out what image was clicked on
imgNum = find(ui.display.axes==gca);
if isempty(imgNum)
    warning('Didn''t click on mrViewer display. No points added.')
    coords = [];
    return
end

% get range of rows (Y) and columns (X) corresponding to rectangle
% (the corner of the image isn't always (0,0), because of
% diff't coordinate transforms. So, account for the viewed range.)
AX = axis;
rows = round([min(Y):max(Y)]); %  - AX(3) + 1
cols = round([min(X):max(X)]); %  - AX(1) + 1

% get coordinates (in base MR data) of selected points
imgCoords = mrViewGet(ui,'DataCoords',imgNum); % whole image
imgSz = size(ui.display.images{imgNum}); imgSz = imgSz(1:2);
I = reshape(1:prod(imgSz),imgSz); % index matrix

% get indices that correspond to the rectange, and return those coords
ind = I(rows,cols);
coords = imgCoords(:,ind(:));

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiCircleCoords(ui);
% Get points from the user specifying a circle on the mrViewer display,
% and compute a 3xN list of coordinates which that input represents.
figure(ui.fig);
tmp = get(ui.panels.display,'BackgroundColor');
set(ui.panels.display,'BackgroundColor','y');
hmsg = mrMessage('Select center of circle, then a point on circumference');
AX = axis;
[X Y] = ginput(2);
X = round(X-AX(1)+1);
Y = round(Y-AX(3)+1);
close(hmsg);
set(ui.panels.display,'BackgroundColor',tmp);

% figure out what image was clicked on
imgNum = find(ui.display.axes==gca);
if isempty(imgNum)
    warning('Didn''t click on mrViewer display. No points added.')
    coords = [];
    return
end

% create a matrix R specifying the distance of each pixel in the
% image from the first selected point (center of circle):
imgSz = size(ui.display.images{imgNum});
[xx,yy] = meshgrid(1:imgSz(2),1:imgSz(1));
dX = xx-X(1); dY = yy-Y(1);
R = sqrt(dX.*dX + dY.*dY);

% the points in the circle are points where R is less than the
% radius (the distance between the first and second points):
radius = sqrt(diff(X)^2 + diff(Y)^2);
inCircle = find(R<radius);

% get coordinates (in base MR data) within the circle
allCoords = mrViewGet(ui,'DataCoords',imgNum); % whole image
coords = allCoords(:,inCircle);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiCubeCoords(ui);
% Get points from the user specifying a cube on the mrViewer display,
% and compute a 3xN list of coordinates which that input represents.
coords = [];
myWarnDlg('Sorry, Not Implemented Yet');
return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiSphereCoords(ui);
% Get points from the user specifying the center, and a point on the surface, of a sphere
% in the mrViewer display, and compute a 3xN list of coordinates which that input represents.
figure(ui.fig);
tmp = get(ui.panels.display,'BackgroundColor');
set(ui.panels.display,'BackgroundColor','y');
hmsg = mrMessage('Select center of sphere, then a point on circumference');
AX = axis;
[X Y] = ginput(2);
X = round(X-AX(1)+1);
Y = round(Y-AX(3)+1);
close(hmsg);
set(ui.panels.display,'BackgroundColor',tmp);

% figure out what image was clicked on
imgNum = find(ui.display.axes==gca);
if isempty(imgNum)
    warning('Didn''t click on mrViewer display. No points added.')
    coords = [];
    return
end

% create a matrix R specifying the distance of each pixel in the
% image from the first selected point (center of sphere):
% TODO: xform grid to current view space
[xx yy zz] = meshgrid(1:ui.mr.dims(2), 1:ui.mr.dims(1), 1:ui.mr.dims(3));
dX = xx-X(1); dY = yy-Y(1);  dZ = zz-mrViewGet(ui, 'curslice');
R = sqrt(dX.*dX + dY.*dY + dZ.*dZ);

% the points in the circle are points where R is less than the
% radius (the distance between the first and second points):
radius = sqrt(diff(X)^2 + diff(Y)^2);
inSphere = find(R<radius);

% get coordinates (in base MR data) within the circle
% (This is a temp fix, will only work in pixel space)
coords = [yy(inSphere)'; xx(inSphere)'; zz(inSphere)'];

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiLineCoords(ui);
% Get points from the user specifying a line on the mrViewer display,
% and compute a 3xN list of coordinates which that input represents.
figure(ui.fig);
tmp = get(ui.panels.display,'BackgroundColor');
set(ui.panels.display,'BackgroundColor','y');
hmsg = mrMessage('Select endpoints of line');
pts = round(ginput(2));
close(hmsg);
set(ui.panels.display,'BackgroundColor',tmp);

% figure out what image was clicked on
imgNum = find(ui.display.axes==gca);
if isempty(imgNum)
    warning('Didn''t click on mrViewer display. No points added.')
    coords = [];
    return
end

% find the 2D image coords that lie within the line specified by
% the two points
[cols rows] = findLinePoints(pts(1,:),pts(2,:));

% account for axis bounds
AX = axis;
cols = cols - AX(1) + 1;
rows = rows - AX(3) + 1;

% get coordinates (in base MR data) within the line
imgCoords = mrViewGet(ui,'DataCoords',imgNum); % whole image
imgSz = size(ui.display.images{imgNum}); imgSz=imgSz(1:2);
ind = sub2ind(imgSz,rows,cols);
coords = imgCoords(:,ind);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiPointCoords(ui);
% Get points from the user specifying individual points on the mrViewer
% display, and compute a 3xN list of coordinates which that input
% represents (in the base MR data).
figure(ui.fig);
tmp = get(ui.panels.display,'BackgroundColor');
set(ui.panels.display,'BackgroundColor','y');
hmsg = mrMessage('Left click to select point, right click to quit.');
X = []; Y = []; button = 1;
while button==1
    [newX newY button] = ginput(1);
    X = [X; newX]; Y = [Y; newY];
end
X = round(X); Y = round(Y);
close(hmsg);
set(ui.panels.display,'BackgroundColor',tmp);

% figure out what image was clicked on
imgNum = find(ui.display.axes==gca);
if isempty(imgNum)
    warning('Didn''t click on mrViewer display. No points added.')
    coords = [];
    return
end

% get coordinates (in base MR data) for the selected points
allCoords = mrViewGet(ui,'DataCoords',imgNum); % whole image
imgSz = size(ui.display.images{imgNum}); imgSz=imgSz(1:2);
ind = sub2ind(imgSz,Y,X);
coords = allCoords(:,ind);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function coords = roiGrowCoords(ui);
% Get a point from the user from which to grow a 'blob' of
% interconnected points in 3D,  and return a 3xN list of coordinates
% for those points (in the base MR data).
figure(ui.fig);
tmp = get(ui.panels.display, 'BackgroundColor');
set(ui.panels.display, 'BackgroundColor', 'y');
hmsg = mrMessage('Select point from which to grow.');
pt = round(ginput(1));
close(hmsg);
set(ui.panels.display, 'BackgroundColor', tmp);

% figure out what image was clicked on
imgNum = find(ui.display.axes==gca);
if isempty(imgNum)
    warning('Didn''t click on mrViewer display. No points added.')
    coords = [];
    return
end

% find seed location in the data coords
% (take axis bounds into account)
imgCoords = mrViewGet(ui, 'DataCoords', imgNum);
imgSz = size(ui.display.images{imgNum}); imgSz=imgSz([1 2]);
AX = axis;
ind = sub2ind(imgSz, round(pt(2)-AX(3)+1), round(pt(1)-AX(1)+1));
% ind = sub2ind(imgSz, pt(2), pt(1));
seed = round(imgCoords(:,ind));

% First-pass method of growing a blob efficiently:
% (1) Create an initial box,  centered on seed
% (2) Restrict the box to coords which pass overlay thresholds
% (3) Find contiguous blob which contains seed
% (4) Test if box contains whole blob: if not,  repeat 1-4 iteratively
hmsg = msgbox('Growing ROI...');
boxSize = 10; stepSize = 10;
coords = [];
while 1
    % (1) create box (get coords specifying box in data)
    ymin = max(1, seed(1)-boxSize);
    ymax = min(ui.mr.dims(1), seed(1)+boxSize);
    xmin = max(1, seed(2)-boxSize);
    xmax = min(ui.mr.dims(2), seed(2)+boxSize);
    zmin = max(1, seed(3)-boxSize);
    zmax = min(ui.mr.dims(3), seed(3)+boxSize);
    [X Y Z] = meshgrid(xmin:xmax, ymin:ymax, zmin:zmax);
    boxCoords = [Y(:) X(:) Z(:)]'; clear X Y Z
    mask = logical(zeros(ui.mr.dims(1:3)));

    % (2) restrict box to overlays
    hidden = [ui.overlays.hide];
    boxCoords = mrViewRestrict(ui, boxCoords, find(~hidden));
    ok = sub2ind(size(mask), boxCoords(1,:), boxCoords(2,:), boxCoords(3,:));
    mask(round(ok)) = 1;

    % (3) Find contiguous blob which contains seed
    L = bwlabeln(mask,  6); % integer label matrix of 6-connected blobs
    seedLabel = L(seed(1), seed(2), seed(3));
    if seedLabel==0,  return;   end;  % no data so quit
    blob = (L==seedLabel); % binary matrix where blob is 1
    [i1,  i2,  i3] = ind2sub(size(mask), find(blob>0.5));
    coords = [i1 i2 i3]';

    % (4) Test if the box contains the entire blob
    % (Or is otherwise flush with the bounds of the data)
    inBoundsY=(all(i1>ymin)|ymin==1) & (all(i1<ymax)|ymax==ui.mr.dims(1));
    inBoundsX=(all(i2>xmin)|xmin==1) & (all(i2<xmax)|xmax==ui.mr.dims(2));
    inBoundsZ=(all(i3>zmin)|zmin==1) & (all(i3<zmax)|zmax==ui.mr.dims(3));
    if inBoundsX & inBoundsY & inBoundsZ
        break;
    else
        boxSize = boxSize + stepSize;
    end
end
close(hmsg);

return
% /--------------------------------------------------------------------/ %

% /--------------------------------------------------------------------/ %
function ui = updateROIPopup(ui);
% update selected ROI popup if it exists
if checkfields(ui, 'controls', 'roiSelect') & ishandle(ui.controls.roiSelect)
    str = get(ui.controls.roiSelect, 'String');
    if isempty(ui.rois)
        str = {'(No ROIs)'};
    else
        str = {ui.rois.name};
	end
	val = max(1, ui.settings.roi); % if sel==0, select the '(No ROIs)' string
    set(ui.controls.roiSelect, 'String', str, 'Value', val);
end
return


% Stores the result of a regression algorithm
classdef RegressionResult < Data
    properties (Access = public)
        predictedResults;
        truthResults;
        timestamps;
    end

    methods (Access = public)
        function obj = RegressionResult(predictedResults,truthResults,timestamps)
            if nargin > 0
                obj.predictedResults = predictedResults;
                if nargin > 1
                    obj.truthResults = truthResults;
                    if nargin > 2
                        obj.timestamps = timestamps;
                    end
                end
                if isempty(obj.timestamps)
                    obj.timestamps = 1 : length(predictedResults);
                end
            end
            obj.type = DataType.kRegressionResult;
        end
    end
end


function varargout=yticksi(varargin)
%
% For calling details please see v_yticksi.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_yticksi.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: yticksi.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_yticksi(varargin{:});
else
    v_yticksi(varargin{:});
end


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

%%
clear; close all; clc;

%% Syntax
% |[D]=logic2levelset(varargin);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function val = get(TC,varargin)

%GET    Get threecomp object properties.
%   V = GET(TC,'PropertyName') returns the value of the specified
%   property for the threecomp object specified by TC. Allowable properties
%   include:
%   WAVEFORM          waveform object containing the three component traces
%   BACKAZIMUTH       backazimuth to source
%   RECTILINEARITY    rectilinearity stored in a waveform object
%   PLANARITY         stored in a waveform object
%   ENERGY            energy stored in a waveform object
%   AZIMUTH           azimuth stored in a waveform object
%   INCLINATION       inclination stored in a waveform object
% See also threecomp object

% Author: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
% $Date$
% $Revision$

% Check inputs
if ~isa(TC,'threecomp')
    error('First argment must be a threecomp object');
end
if nargin~=2
    error('Incorrect number of arguments');
end
property = varargin{1};
if ~ischar(property)
    error('Second argument must be a character string');
end

[objSize1,objSize2] = size(TC);
numObj = numel(TC);

% Prepare property values
switch upper(property)

    case 'WAVEFORM'
        if numObj==1
            val = TC.traces;
        elseif objSize1>1 && objSize2==1
            for n = 1:numObj
                val(n,1:3) = TC(n).traces;
            end
        elseif objSize2>1
            for n1 = 1:objSize1
                for n2 = 1:objSize2
                    val(n1,n2,1:3) = TC(n).traces;
                end
            end
        else
            error('threecomp object is not 1x1, nx1, or nxm in size');
        end

    case 'TRIGGER'
        for n = 1:numObj
           val(n) = TC(n).trigger;
        end
        val = reshape(val,objSize1,objSize2);

    case 'BACKAZIMUTH'
        for n = 1:numObj
            if isempty(TC(n).backAzimuth)
                val(n) = NaN;
            else
                val(n) = TC(n).backAzimuth;
            end
        end
        val = reshape(val,objSize1,objSize2);
    case 'NSCL'
        for n = 1:numObj
            w = TC(n).waveform;
            net = get(w(1),'NETWORK');
            sta = get(w(1),'STATION');
            chan = get(w,'CHANNEL');
            chanString = [chan{1}(1:2) '[' chan{1}(3) chan{2}(3) chan{3}(3) ']' ];
            loc = get(w(1),'LOCATION');
            val(n) = {[net '_' sta '_' chanString '_' loc]};
        end
        val = reshape(val,objSize1,objSize2);
    case 'STATION'
        for n = 1:numObj
            w = TC(n).waveform;
            val(n) = {get(w(1),'STATION')};
        end
        val = reshape(val,objSize1,objSize2);
    case 'CHANNEL'
        for n = 1:numObj
            w = TC(n).waveform;
            val(n) = {get(w,'CHANNEL')};
        end
        val = reshape(val,objSize1,objSize2);
    case 'TYPE'
        for n = 1:numObj
            val(n) = gettype(TC(n));
        end
        val = reshape(val,objSize1,objSize2);

    case 'COMPLETENESS'
        for n = 1:numObj
            val(n) = getcompleteness(TC(n));
        end
        val = reshape(val,objSize1,objSize2);

    case 'ORIENTATION'
        for n = 1:numObj
            vals = TC(n).orientation;
            if isempty(vals)
               vals = [NaN NaN NaN NaN NaN NaN];
            end
            val(n,1:6) = vals;
        end
    case 'RECTILINEARITY'
        for n = 1:numObj
            if isempty(TC(n).rectilinearity)
                val(n) = waveform;
            else
                val(n) = TC(n).rectilinearity;
            end
        end
        val = reshape(val,objSize1,objSize2);

    case 'PLANARITY'
        for n = 1:numObj
            if isempty(TC(n).planarity)
                val(n) = waveform;
            else
                val(n) = TC(n).planarity;
            end
        end
        val = reshape(val,objSize1,objSize2);

    case 'ENERGY'
        for n = 1:numObj
            if isempty(TC(n).energy)
                val(n) = waveform;
            else
                val(n) = TC(n).energy;
            end
        end
        val = reshape(val,objSize1,objSize2);

    case 'AZIMUTH'
        for n = 1:numObj
            if isempty(TC(n).azimuth)
                val(n) = waveform;
            else
                val(n) = TC(n).azimuth;
            end
        end
        val = reshape(val,objSize1,objSize2);

    case 'INCLINATION'
        for n = 1:numObj
            if isempty(TC(n).inclination)
                val(n) = waveform;
            else
                val(n) = TC(n).inclination;
            end
        end
        val = reshape(val,objSize1,objSize2);

    otherwise
        error('Property not recognized.');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DETERMINE TYPE PROPERTY
% where TC and val are scalars
%
function val = gettype(TC)

chan = get(TC,'CHANNEL');
chan = chan{1};
for n = 1:3
   val(1) = {[ chan{1}(3) chan{2}(3) chan{3}(3) ]};
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DETERMINE COMPLETENESS PROPERTY
% where TC and val are scalars
%
function val = getcompleteness(TC)

% 0 = no waveforms and no particle motions
% 1 = waveforms but no particle motions
% 2 = waves and all particle motion fields

val = 0;

if all(~isempty(TC.traces)) && ~isempty(TC.rectilinearity) && ~isempty(TC.planarity) && ~isempty(TC.energy) && ~isempty(TC.azimuth)  && ~isempty(TC.inclination)
    val = 2;
elseif all(~isempty(TC.traces))
   val = 1;
else
    val = 0;
end


function [im_out,alpha_out] = texture_map(V,F,TC,im_in,alpha_in)
  % TEXTURE_MAP  texture map a give mesh (V,F) with a texture (TC,im_in) and save
  % it back to an image (im_out)
  %
  % [im_out,alpha_out] = texture_map(V,F,TC,im_in,alpha_in)
  %
  % Inputs:
  %   V  #V by 2 list of mesh vertex positions
  %   F  #F by 3 list of face indices
  %   TC  #V by 2 list of mesh texture coordinates, these should be between 0
  %     and 1, if they're not they will be normalized
  %   im_in  input texture image
  %   alpha_in  input texture image alpha channel
  % Outputs:
  %   im_out  deformed texture image
  %
  % Example:
  %  % original mesh (V,F) deformed mesh (NV,F)
  %  TC = texture_coords(V);
  %  [oim, oalpha] = texture_map(V,F,TC,im,alpha);
  %

  if ~exist('alpha_in')
    alpha_in = ones(size(im_in,1),size(im_in,2));
  end
  if size(V,2) == 2
    V(:,end+1:3) = 0;
  end

  path_to_TexMapPreview = ...
    '/usr/local/igl/igl_apps/TexMapPreview/TexMapPreview';
  path_to_convert = '/usr/local/bin/convert';
  %path_to_TexMapPreviewConvert = ...
  %  '/usr/local/igl/igl_apps/TexMapPreview/TexMapPreviewConvert.sh';

  prefix = tempprefix();
  png_file_name = [prefix '.png'];
  tga_file_name = [prefix '.tga'];
  obj_file_name = [prefix '.obj'];
  output_tga_file_name = [prefix '-out.tga'];
  output_png_file_name = [prefix '-out.png'];

  % write image to png file
  imwrite(im_in,png_file_name,'Alpha',alpha_in);

  % convert the png image to a .tga image
  [status,result] = ...
    issue( ...
      'export DYLD_LIBRARY_PATH="";', ...
      path_to_convert, ...
      png_file_name, ...
      tga_file_name);
  % error on error
  if(status ~= 0)
      error(result);
  end
  % write mesh to obj file
  writeOBJ(obj_file_name,V,F,TC,F);

  % convert the png image to a .tga image
  [status,result] = ...
    issue( ...
      path_to_TexMapPreview, ...
      obj_file_name, ...
      tga_file_name, ...
      output_tga_file_name);
  % error on error
  if(status ~= 0)
      error(result);
  end

  % convert output tga to png

  % convert the png image to a .tga image
  [status, result] = ...
    issue( ...
      'export DYLD_LIBRARY_PATH="";', ...
      path_to_convert, ...
      output_tga_file_name, ...
      output_png_file_name);
  % error on error
  if(status ~= 0)
      error(result);
  end

  % clean up temporary files
  delete(tga_file_name);
  delete(png_file_name);
  delete(obj_file_name);
  delete(output_tga_file_name);

  if(nargout == 1)
    im_out = imread(output_png_file_name);
  elseif(nargout == 2)
    [im_out,m,alpha_out] = imread(output_png_file_name);
  else
    % clean up png file before error
    delete(output_png_file_name);
    error('Too many outputs');
  end
  % clean up png file
  delete(output_png_file_name);

  function [status, result] = issue(varargin)
  % ISSUE issue a system call with each arguement separated by a space
    command = [];
    for ii = 1:nargin
      command = ['' command ' ' varargin{ii}];
    end
    % show the command
    fprintf('%s\n',command);
    % issue the command
    [status, result] = system( command );
  end

end


function [obs,nav]=readrnxobs(obs,nav,opt,fname)

global glc
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);
fprintf('Info:reading obs file %s...',fname0);

fid=fopen(fname);
% read renix header
[headinfo,fid]=decode_rnxh(fid);

if headinfo.type~='O'
    error('\n The file %s is not renix observation file!!!\n',fname);
end

% decode file header
[headinfo,nav,obs,tobs,fid]=decode_obsh(headinfo,nav,obs,fid);

% decode body
obs=decode_obsb(headinfo,obs,tobs,opt,fid);
if obs.n==0,return;end

% sort obs
obs=sortobs(obs);

fprintf('over\n');

return


function [data] = ft_datatype_raw(data, varargin)

% FT_DATATYPE_RAW describes the FieldTrip MATLAB structure for raw data
%
% The raw datatype represents sensor-level time-domain data typically
% obtained after calling FT_DEFINETRIAL and FT_PREPROCESSING. It contains
% one or multiple segments of data, each represented as Nchan X Ntime
% arrays.
%
% An example of a raw data structure with 151 MEG channels is
%
%          label: {151x1 cell}      the channel labels (e.g. 'MRC13')
%           time: {1x266 cell}      the timeaxis [1*Ntime double] per trial
%          trial: {1x266 cell}      the numeric data [151*Ntime double] per trial
%     sampleinfo: [266x2 double]    the begin and endsample of each trial relative to the recording on disk
%      trialinfo: [266x1 double]    optional trigger or condition codes for each trial
%            hdr: [1x1 struct]      the full header information of the original dataset on disk
%           grad: [1x1 struct]      information about the sensor array (for EEG it is called elec)
%           cfg: [1x1 struct]       the configuration used by the function that generated this data structure
%
% Required fields:
%   - time, trial, label
%
% Optional fields:
%   - sampleinfo, trialinfo, grad, elec, opto, hdr, cfg
%
% Deprecated fields:
%   - fsample
%
% Obsoleted fields:
%   - offset
%
% Revision history:
%
% (2011/latest) The description of the sensors has changed, see FT_DATATYPE_SENS
% for further information.
%
% (2010v2) The trialdef field has been replaced by the sampleinfo and
% trialinfo fields. The sampleinfo corresponds to trl(:,1:2), the trialinfo
% to trl(4:end).
%
% (2010v1) In 2010/Q3 it shortly contained the trialdef field which was a copy
% of the trial definition (trl) is generated by FT_DEFINETRIAL.
%
% (2007) It used to contain the offset field, which correcponds to trl(:,3).
% Since the offset field is redundant with the time axis, the offset field is
% from now on not present any more. It can be recreated if needed.
%
% (2003) The initial version was defined
%
% See also FT_DATATYPE, FT_DATATYPE_COMP, FT_DATATYPE_TIMELOCK, FT_DATATYPE_FREQ,
% FT_DATATYPE_SPIKE, FT_DATATYPE_SENS

% Copyright (C) 2011, 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$

% get the optional input arguments, which should be specified as key-value pairs
version       = ft_getopt(varargin, 'version', 'latest');
hassampleinfo = ft_getopt(varargin, 'hassampleinfo', 'ifmakessense'); % can be yes/no/ifmakessense
hastrialinfo  = ft_getopt(varargin, 'hastrialinfo',  'ifmakessense'); % can be yes/no/ifmakessense

% do some sanity checks
assert(isfield(data, 'trial') && isfield(data, 'time') && isfield(data, 'label'), 'inconsistent raw data structure, some field is missing');
assert(length(data.trial)==length(data.time), 'inconsistent number of trials in raw data structure');
for i=1:length(data.trial)
  assert(size(data.trial{i},2)==length(data.time{i}), 'inconsistent number of samples in trial %d', i);
  assert(size(data.trial{i},1)==length(data.label), 'inconsistent number of channels in trial %d', i);
end

% convert it into true/false
if isequal(hassampleinfo, 'ifmakessense')
  hassampleinfo = makessense(data, 'sampleinfo');
else
  hassampleinfo = istrue(hassampleinfo);
end
if isequal(hastrialinfo, 'ifmakessense')
  hastrialinfo = makessense(data, 'trialinfo');
else
  hastrialinfo = istrue(hastrialinfo);
end

if strcmp(version, 'latest')
  version = '2011';
end

if isempty(data)
  return;
end

switch version
  case '2011'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % ensure that the sensor structures are up to date
    if isfield(data, 'grad')
      data.grad = ft_datatype_sens(data.grad);
    end
    if isfield(data, 'elec')
      data.elec = ft_datatype_sens(data.elec);
    end
    if isfield(data, 'opto')
      data.opto = ft_datatype_sens(data.opto);
    end

    if ~isfield(data, 'fsample')
      for i=1:length(data.time)
        if length(data.time{i})>1
          data.fsample = 1/mean(diff(data.time{i}));
          break
        else
          data.fsample = nan;
        end
      end
      if isnan(data.fsample)
        ft_warning('cannot determine sampling frequency');
      end
    end

    if isfield(data, 'offset')
      data = rmfield(data, 'offset');
    end

    % the trialdef field should be renamed into sampleinfo
    if isfield(data, 'trialdef')
      data.sampleinfo = data.trialdef;
      data = rmfield(data, 'trialdef');
    end

    if (hassampleinfo && ~isfield(data, 'sampleinfo')) || (hastrialinfo && ~isfield(data, 'trialinfo'))
      % try to reconstruct the sampleinfo and trialinfo
      data = fixsampleinfo(data);
    end

    if ~hassampleinfo && isfield(data, 'sampleinfo')
      data = rmfield(data, 'sampleinfo');
    end

    if ~hastrialinfo && isfield(data, 'trialinfo')
      data = rmfield(data, 'trialinfo');
    end

  case '2010v2'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isfield(data, 'fsample')
      data.fsample = 1/mean(diff(data.time{1}));
    end

    if isfield(data, 'offset')
      data = rmfield(data, 'offset');
    end

    % the trialdef field should be renamed into sampleinfo
    if isfield(data, 'trialdef')
      data.sampleinfo = data.trialdef;
      data = rmfield(data, 'trialdef');
    end

    if (hassampleinfo && ~isfield(data, 'sampleinfo')) || (hastrialinfo && ~isfield(data, 'trialinfo'))
      % try to reconstruct the sampleinfo and trialinfo
      data = fixsampleinfo(data);
    end

    if ~hassampleinfo && isfield(data, 'sampleinfo')
      data = rmfield(data, 'sampleinfo');
    end

    if ~hastrialinfo && isfield(data, 'trialinfo')
      data = rmfield(data, 'trialinfo');
    end

  case {'2010v1' '2010'}
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isfield(data, 'fsample')
      data.fsample = 1/mean(diff(data.time{1}));
    end

    if isfield(data, 'offset')
      data = rmfield(data, 'offset');
    end

    if ~isfield(data, 'trialdef') && hascfg
      % try to find it in the nested configuration history
      data.trialdef = ft_findcfg(data.cfg, 'trl');
    end

  case '2007'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isfield(data, 'fsample')
      data.fsample = 1/mean(diff(data.time{1}));
    end

    if isfield(data, 'offset')
      data = rmfield(data, 'offset');
    end

  case '2003'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isfield(data, 'fsample')
      data.fsample = 1/mean(diff(data.time{1}));
    end

    if ~isfield(data, 'offset')
      data.offset = zeros(length(data.time),1);
      for i=1:length(data.time);
        data.offset(i) = round(data.time{i}(1)*data.fsample);
      end
    end

  otherwise
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    ft_error('unsupported version "%s" for raw datatype', version);
end

% Numerical inaccuracies in the binary representations of floating point
% values may accumulate. The following code corrects for small inaccuracies
% in the time axes of the trials. See http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=1390
data = fixtimeaxes(data);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function data = fixtimeaxes(data)

if ~isfield(data, 'fsample')
  fsample = 1/mean(diff(data.time{1}));
else
  fsample = data.fsample;
end

begtime   = nan(1, length(data.time));
endtime   = nan(1, length(data.time));
numsample = zeros(1, length(data.time));
for i=1:length(data.time)
  if ~isempty(data.time{i})
    begtime(i) = data.time{i}(1);
    endtime(i) = data.time{i}(end);
  end
  numsample(i) = length(data.time{i});
end

% compute the differences over trials and the tolerance
tolerance     = 0.01*(1/fsample);
begdifference = abs(begtime-begtime(1));
enddifference = abs(endtime-endtime(1));

% check whether begin and/or end are identical, or close to identical
begidentical  = all(begdifference==0);
endidentical  = all(enddifference==0);
begsimilar    = all(begdifference < tolerance);
endsimilar    = all(enddifference < tolerance);

% Compute the offset of each trial relative to the first trial, and express
% that in samples. Non-integer numbers indicate that there is a slight skew
% in the time over trials. This works in case of variable length trials.
offset = fsample * (begtime-begtime(1));
skew   = abs(offset - round(offset));

% try to determine all cases where a correction is needed
% note that this does not yet address all possible cases where a fix might be needed
needfix = false;
needfix = needfix || ~begidentical && begsimilar;
needfix = needfix || ~endidentical && endsimilar;
needfix = needfix || ~all(skew==0) && all(skew<0.01);

% if the skew is less than 1% it will be corrected
if needfix
  ft_warning('correcting numerical inaccuracy in the time axes');
  for i=1:length(data.time)
    % reconstruct the time axis of each trial, using the begin latency of
    % the first trial and the integer offset in samples of each trial
    data.time{i} = begtime(1) + ((1:numsample(i)) - 1 + round(offset(i)))/fsample;
  end
end


function y=label_bibtex(bibtex,k)

%LABEL_BIBTEX labels bibliographic entries in bibtex file
%Syntax: y=label_bibtex(bibtex,k)
%Description: adds a label to each entry composed as Author:Year:[k letters of the title]
%             if k argument is not provided 25 will be used by default
%
%for example file file.bib with contents
%
%------------------------------------------------
%@article{de_Almeida:2001-Analysis-of-genomic-seque,
%   Author = {de Almeida, J. S. and Carrico, J. A. and Maretzek, A. and Noble, P. A. and Fletcher, M.},
%   Title = {Analysis of genomic sequences by Chaos Game Representation},
%   Journal = {Bioinformatics},
%   Volume = {17},
%   Number = {5},
%   Pages = {429-37},
%(...)
%    Year = {2001} }
%
%@article{Almeida:2002-Universal-sequence-map--U,
%   Author = {Almeida, J. S. and Vinga, S.},
%   Title = {Universal sequence map (USM) of arbitrary discrete sequences},
%   Journal = {BMC Bioinformatics},
%   Volume = {3},
%   Number = {1},
%
%   etc ...
%------------------------------------------------
%
%will be rewritten by y=endnote2bibtex('file.bib',25) as
%
%------------------------------------------------
%   Author = {Almeida, J. S. and Carrico, J. A. and Maretzek, A. and Noble, P. A. and Fletcher, M.},
%   Title = {Analysis of genomic sequences by Chaos Game Representation},
%   Journal = {Bioinformatics},
%   Volume = {17},
%   Number = {5},
%(...)
%    Year = {2001} }
%
%@article{Almeida:2002:Universal sequence map (U...,
%   Author = {Almeida, J. S. and Vinga, S.},
%   Title = {Universal sequence map (USM) of arbitrary discrete sequences},
%   Journal = {BMC Bioinformatics},
%   Volume = {3},
%   Number = {1},
%
%   etc ...
%------------------------------------------------
%
%Jonas Almeida, almeidaj@musc.edu, December 2004

if nargin<2;k=25;end

%1.Reads all contents and extracts Author, Year and Title
fid=fopen(bibtex,'r');
L=[];i=0;
while ~feof(fid)
    linha=fgetl(fid);i=i+1;%disp(linha);
    [a,b,c,d,e]=regexpi(linha,'@article{.*');
    if length(e)>0%this is the beggining of an entry
        L=[L,i]; %keep track of the lines that have to be changed
        j=length(L);
        %label{j}='';
    else
        [a,b,c,d,e]=regexpi(linha,'\s+Author = {(.+?),.*');
        if length(e)>0
            %disp(e{1});
            %label(j)=e{1};label{j}=[label{j},':'];
            Author{j}=regexprep(e{1}{1},'\W','_');
            %Author{j}=e{1}{1};
        else
            [a,b,c,d,e]=regexpi(linha,'\s+Year = {(\w+)}.*');
            if length(e)>0
                %disp(e{1});
                %label(j)=e{1};label{j}=[label{j},':'];
                Year{j}=e{1}{1};
            else
                [a,b,c,d,e]=regexpi(linha,'\s+Title = {(.*?)}.*');
                if length(e)>0
                    %disp(e{1});
                    %label(j)=e{1};label{j}=[label{j},':'];
                    Title{j}=regexprep(e{1}{1},'\W','-');
                end
            end
        end
    end
end
fclose(fid);
y.L=L;
y.Author=Author;
y.Year=Year;
y.Title=Title;

%2. And now writes it back to the file
%first copy to temporary file
fid1=fopen(bibtex,'r');
fid2=fopen(['temp_',bibtex],'w');
i=0;j=1;
while ~feof(fid1)
    i=i+1;linha=fgetl(fid1);
    if sum(L==i)>0
        if k>0
            fprintf(fid2,'%s\n',[linha(1:9),y.Author{j},':',y.Year{j},'-',y.Title{j}(1:min([k,length(y.Title{j})])),',']);
        else
            fprintf(fid2,'%s\n',[linha(1:9),y.Author{j},':',y.Year{j},',']);
        end
        j=j+1;
    else
        fprintf(fid2,'%s\n',linha);
    end
end
fclose(fid1);fclose(fid2);
%copy temprary file onto original
copyfile(['temp_',bibtex],bibtex);
%delete temporary file
delete(['temp_',bibtex]);


%--- help for intercept_column ---
%
%  intercept_column - builds a scalar splanar object from a
%  vectorized splanar object. The pointer argument points the
%  element in the vector to be used.
%


% OtQueryEmpty Check whether the record set is empty.
%
% Usage:
%    mt = OtQueryEmpty(hquery)

% OtMatlab: Matlab interface to the Omnitrans transport planning software

% Copyright (c) 2008, VORtech Computing
% Copyright (c) 2010, Omnitrans International

% All rights reserved.

% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:

%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the distribution
%     * Neither the name of VORtech Computing and Omnitrans International nor the names
%       of its contributors may be used to endorse or promote products derived
%       from this software without specific prior written permission.

% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.

% 2006-04-13 Created (Johan Meijdam, VORtech)

function mt = OtQueryEmpty(hquery)
   mt = Ot('query.empty', hquery);
end


function args = flatten_structs(args,structmask)
% Turn a list of name-value pairs/structs into a flat list of name-value pairs
% NVPs = flatten_structs(Arguments,StructMask)
%
% In:
%   Arguments : cell array of function arguments in form of name-value pairs, possibly interleaved
%               with structs {'name',value,STRUCT,'name',value,'name',value, ...}
%
%   StructMask : a bitmask that encodes at what positions Arguments contains structs; optional.
%
% Out:
%   NVPs : a cell array of name-value pairs, where the structs have been flattened into
%          name-value pairs, too
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2013-11-03

if nargin < 2
    structmask = cellfun('isclass',args,'struct'); end

if any(structmask)
    persistent indexcache; %#ok<TLEV>
    try
        % try to look up splice points from cache
        if length(structmask) < 62
            field = char('a'+structmask);
        else
            str = java.lang.String(char('a'+structmask));
            field = ['h' num2str(str.hashCode()+2^31)];
        end
        splicepos = indexcache.(field);
    catch %#ok<CTCH>
        % pre-calculate splice points and cache results
        splicepos = [];
        k = 1;
        while k <= length(args)
            if isstruct(args{k})
                splicepos(end+1) = k; %#ok<AGROW>
                k = k+1; % struct case
            else
                k = k+2; % NVP case
            end
        end
        splicepos = splicepos(end:-1:1);
        indexcache.(field) = splicepos;
    end

    % splice structs in
    for k = splicepos
        args = [args(1:k-1) reshape([fieldnames(args{k}) struct2cell(args{k})]',1,[]) args(k+1:end)]; end
end