function spikes = bz_GetSpikes(varargin)
% bz_getSpikes - Get spike timestamps.
%       if loading from clu/res/fet/spk files - must be formatted as:
%       baseName.clu.shankNum
%
% USAGE
%
%    spikes = bz_getSpikes(varargin)
%
% INPUTS
%
%    spikeGroups     -vector subset of shank IDs to load (Default: all)
%    region          -string region ID to load neurons from specific region
%                     (requires sessionInfo file or units->structures in xml)
%    UID             -vector subset of UID's to load
%    basepath        -path to recording (where .dat/.clu/etc files are)
%    getWaveforms    -logical (default=true) to load mean of raw waveform data
%    forceReload     -logical (default=false) to force loading from
%                     res/clu/spk files
%    onlyLoad        -[shankID cluID] pairs to EXCLUSIVELY LOAD from
%                       clu/res/fet to spikes.cellinfo.mat file
%    saveMat         -logical (default=false) to save in buzcode format
%    noPrompts       -logical (default=false) to supress any user prompts
%
% OUTPUTS
%
%    spikes - cellinfo struct with the following fields
%          .sessionName    -name of recording file
%          .UID            -unique identifier for each neuron in a recording
%          .times          -cell array of timestamps (seconds) for each neuron
%          .spindices      -sorted vector of [spiketime UID], useful for
%                           input to some functions and plotting rasters
%          .region         -region ID for each neuron (especially important large scale, high density probes)
%          .shankID        -shank ID that each neuron was recorded on
%          .maxWaveformCh  -channel # with largest amplitude spike for each neuron
%          .rawWaveform    -average waveform on maxWaveformCh (from raw .dat)
%          .cluID          -cluster ID, NOT UNIQUE ACROSS SHANKS
%          .numcells       -number of cells/UIDs
%
% NOTES
%
% This function can be used in several ways to load spiking data.
% Specifically, it loads spiketimes for individual neurons and other
% sessionInfodata that describes each neuron.  Spiketimes can be loaded using the
% UID(1-N), the shank the neuron was on, or the region it was recorded in.
% The default behavior is to load all spikes in a recording. The .shankID
% and .cluID fields can be used to reconstruct the 'units' variable often
% used in FMAToolbox.
% units = [spikes.shankID spikes.cluID];
%
%
% first usage recommendation:
%
%   spikes = bz_getSpikes('saveMat',true); Loads and saves all spiking data
%                                          into buzcode format .cellinfo. struct
% other examples:
%
%   spikes = bz_getSpikes('spikeGroups',1:5); first five shanks
%
%   spikes = bz_getSpikes('region','CA1'); cells tagged as recorded in CA1
%
%   spikes = bz_getSpikes('UID',[1:20]); first twenty neurons
%
%
% written by David Tingley, 2017
%% Deal With Inputs
spikeGroupsValidation = @(x) assert(isnumeric(x) || strcmp(x,'all'),...
    'spikeGroups must be numeric or "all"');

p = inputParser;
addParameter(p,'spikeGroups','all',spikeGroupsValidation);
addParameter(p,'region','',@isstr); % won't work without sessionInfodata
addParameter(p,'UID',[],@isvector);
addParameter(p,'basepath',pwd,@isstr);
addParameter(p,'getWaveforms',true)
addParameter(p,'forceReload',false,@islogical);
addParameter(p,'saveMat',false,@islogical);
addParameter(p,'noPrompts',false,@islogical);
addParameter(p,'onlyLoad',[]);

parse(p,varargin{:})

spikeGroups = p.Results.spikeGroups;
region = p.Results.region;
UID = p.Results.UID;
basepath = p.Results.basepath;
getWaveforms = p.Results.getWaveforms;
forceReload = p.Results.forceReload;
saveMat = p.Results.saveMat;
noPrompts = p.Results.noPrompts;
onlyLoad = p.Results.onlyLoad;

[sessionInfo] = bz_getSessionInfo(basepath, 'noPrompts', noPrompts);
baseName = bz_BasenameFromBasepath(basepath);

spikes.samplingRate = sessionInfo.rates.wideband;
nChannels = sessionInfo.nChannels;

cellinfofile = [basepath filesep sessionInfo.FileName '.spikes.cellinfo.mat'];
%% if the cellinfo file exist and we don't want to re-load files
if exist(cellinfofile,'file') && forceReload == false
    disp('loading spikes from cellinfo file..')
    load(cellinfofile)
    %Check that the spikes structure fits cellinfo requirements
    [iscellinfo] = bz_isCellInfo(spikes);
    switch iscellinfo
        case false
            warning(['The spikes structure in baseName.spikes.cellinfo.mat ',...
                'does not fit buzcode standards. Sad.'])
    end

    %If regions have been added since creation... add them
    if ~isfield(spikes,'region') & isfield(sessionInfo,'region')
        if ~isfield(spikes,'numcells')
            spikes.numcells = length(spikes.UID);
        end
        for cc = 1:spikes.numcells
            spikes.region{cc} = sessionInfo.region{spikes.maxWaveformCh(cc)==sessionInfo.channels};
        end

        if saveMat
            save(cellinfofile,'spikes')
        end
    end

else % do the below then filter by inputs... (Load from clu/res/fet)

    if ~noPrompts & saveMat == 0 %Inform the user that they should save a file for later
        savebutton = questdlg(['Would you like to save your spikes in ',...
            sessionInfo.FileName,'.spikes.cellinfo.mat?  ',...
            'This will save significant load time later.']);
        if strcmp(savebutton,'Yes'); saveMat = true; end
    end

disp('loading spikes from clu/res/spk files..')
% find res/clu/fet/spk files here
cluFiles = dir([basepath filesep '*.clu*']);
resFiles = dir([basepath filesep '*.res.*']);
if any(getWaveforms)
    spkFiles = dir([basepath filesep '*.spk*']);
end

% remove *temp*, *autosave*, and *.clu.str files/directories
tempFiles = zeros(length(cluFiles),1);
for i = 1:length(cluFiles)
    dummy = strsplit(cluFiles(i).name, '.'); % Check whether the component after the last dot is a number or not. If not, exclude the file/dir.
    if ~isempty(findstr('temp',cluFiles(i).name)) | ~isempty(findstr('autosave',cluFiles(i).name)) | ...
            isempty(str2num(dummy{length(dummy)})) | find(contains(dummy, 'clu')) ~= length(dummy)-1  | ...
            ~strcmp(dummy{1},baseName)
        tempFiles(i) = 1;
    end
end
cluFiles(tempFiles==1)=[];
tempFiles = zeros(length(resFiles),1);
for i = 1:length(resFiles)
    dummy = strsplit(resFiles(i).name, '.');
    if ~isempty(findstr('temp',resFiles(i).name)) | ~isempty(findstr('autosave',resFiles(i).name)) | ...
            ~strcmp(dummy{1},baseName)
        tempFiles(i) = 1;
    end
end
if any(getWaveforms)
    resFiles(tempFiles==1)=[];
    tempFiles = zeros(length(spkFiles),1);
    for i = 1:length(spkFiles)
        dummy = strsplit(spkFiles(i).name, '.');
        if ~isempty(findstr('temp',spkFiles(i).name)) | ~isempty(findstr('autosave',spkFiles(i).name)) | ...
            ~strcmp(dummy{1},baseName)
            tempFiles(i) = 1;
        end
    end
    spkFiles(tempFiles==1)=[];
end

if isempty(cluFiles)
    disp('no clu files found...')
    spikes = [];
    return
end

% ensures we load in sequential order (forces compatibility with FMAT
% ordering)
for i = 1:length(cluFiles)
    temp = strsplit(cluFiles(i).name,'.');
    shanks(i) = str2num(temp{length(temp)});
end
[shanks ind] = sort(shanks);
cluFiles = cluFiles(ind); %Bug here if there are any files x.clu.x that are not your desired clus
resFiles = resFiles(ind);
if any(getWaveforms)
    spkFiles = spkFiles(ind);
end

% check if there are matching #'s of files
if length(cluFiles) ~= length(resFiles) & length(cluFiles) ~= length(spkFiles)
    error('found an incorrect number of res/clu/spk files...')
end

% use the .clu files to get spike ID's and generate UID and spikeGroup
% use the .res files to get spike times
count = 1;

if isempty(sessionInfo.spikeGroups.groups)
    sessionInfo.spikeGroups = sessionInfo.AnatGrps;
end
for i=1:length(cluFiles)
    disp(['working on ' cluFiles(i).name])

    temp = strsplit(cluFiles(i).name,'.');
    shankID = str2num(temp{length(temp)}); %shankID is the spikegroup number
    clu = load(fullfile(basepath,cluFiles(i).name));
    clu = clu(2:end); % toss the first sample to match res/spk files
    res = load(fullfile(basepath,resFiles(i).name));
    spkGrpChans = sessionInfo.spikeGroups.groups{shankID}; % we'll eventually want to replace these two lines

    if any(getWaveforms) && sum(clu)>0 %bug fix if no clusters
        nSamples = sessionInfo.spikeGroups.nSamples(shankID);
        % load waveforms
        chansPerSpikeGrp = length(sessionInfo.spikeGroups.groups{shankID});
        fid = fopen(fullfile(basepath,spkFiles(i).name),'r');
        wav = fread(fid,[1 inf],'int16=>int16');
        try %bug in some spk files... wrong number of samples?
            wav = reshape(wav,chansPerSpikeGrp,nSamples,[]);
        catch
            if strcmp(getWaveforms,'force')
                wav = nan(chansPerSpikeGrp,nSamples,length(clu));
                display([spkFiles(i).name,' error.'])
            else
            error(['something is wrong with ',spkFiles(i).name,...
                ' Use ''getWaveforms'', false to skip waveforms or ',...
                '''getWaveforms'', ''force'' to write nans on bad shanks.'])
            end
        end
        wav = permute(wav,[3 1 2]);
    end

    cells  = unique(clu);
    % remove MUA and NOISE clusters...
    cells(cells==0) = [];
    cells(cells==1) = [];  % consider adding MUA as another input argument...?

    for c = 1:length(cells)
       spikes.UID(count) = count; % this only works if all shanks are loaded... how do we optimize this?
       ind = find(clu == cells(c));
       spikes.times{count} = res(ind) ./ spikes.samplingRate;
       spikes.shankID(count) = shankID;
       spikes.cluID(count) = cells(c);

       %Waveforms
       if any(getWaveforms)
           wvforms = squeeze(mean(wav(ind,:,:)))-mean(mean(mean(wav(ind,:,:)))); % mean subtract to account for slower (theta) trends
           if prod(size(wvforms))==length(wvforms)%in single-channel groups wvforms will squeeze too much and will have amplitude on D1 rather than D2
               wvforms = wvforms';%fix here
           end
           for t = 1:size(wvforms,1)
              [a(t) b(t)] = max(abs(wvforms(t,:)));
           end
           [aa bb] = max(a,[],2);
           spikes.rawWaveform{count} = wvforms(bb,:);
           spikes.maxWaveformCh(count) = spkGrpChans(bb);
           %Regions (needs waveform peak)
           if isfield(sessionInfo,'region') %if there is regions field in your metadata
                spikes.region{count} = sessionInfo.region{find(spkGrpChans(bb)==sessionInfo.channels)};
           elseif isfield(sessionInfo,'Units') %if no regions, but unit region from xml via Loadparamteres
                %Find the xml Unit that matches group/cluster
                unitnum = cellfun(@(X,Y) X==spikes.shankID(count) && Y==spikes.cluID(count),...
                    {sessionInfo.Units(:).spikegroup},{sessionInfo.Units(:).cluster});
                if sum(unitnum) == 0
                    display(['xml Missing Unit - spikegroup: ',...
                        num2str(spikes.shankID(count)),' cluster: ',...
                        num2str(spikes.cluID(count))])
                    spikes.region{count} = 'missingxml';
                else %possible future bug: two xml units with same group/clu...
                    spikes.region{count} = sessionInfo.Units(unitnum).structure;
                end
           end
           clear a aa b bb
       end

       count = count + 1;
    end
end

if ~isempty(onlyLoad)
    toRemove = true(size(spikes.UID));
    for cc = 1:size(onlyLoad,1)
        whichUID = ismember(spikes.shankID,onlyLoad(cc,1)) & ismember(spikes.cluID,onlyLoad(cc,2));
        toRemove(whichUID) = false;
        if ~any(whichUID)
            display(['No unit with shankID:',num2str(onlyLoad(cc,1)),...
                ' cluID:',num2str(onlyLoad(cc,2))])
        end
    end
    spikes = removeCells(toRemove,spikes,getWaveforms);
end

spikes.sessionName = sessionInfo.FileName;
end

%% save to buzcode format (before exclusions)
if saveMat
    save(cellinfofile,'spikes')
end

%% EXCLUSIONS %%

%filter by spikeGroups input
if ~strcmp(spikeGroups,'all')
    [toRemove] = ~ismember(spikes.shankID,spikeGroups);
    spikes = removeCells(toRemove,spikes,getWaveforms);
end

%filter by region input
if ~isempty(region)
    if ~isfield(spikes,'region') %if no region information in metadata
        error(['You selected to load cells from region "',region,...
            '", but there is no region information in your sessionInfo'])
    end

  toRemove = ~ismember(spikes.region,region);
    if sum(toRemove)==length(spikes.UID) %if no cells from selected region
        warning(['You selected to load cells from region "',region,...
            '", but none of your cells are from that region'])
    end

    spikes = removeCells(toRemove,spikes,getWaveforms);
end

%filter by UID input
if ~isempty(UID)
	[toRemove] = ~ismember(spikes.UID,UID);
    spikes = removeCells(toRemove,spikes,getWaveforms);
end

%% Generate spindices matrics
spikes.numcells = length(spikes.UID);
for cc = 1:spikes.numcells
    groups{cc}=spikes.UID(cc).*ones(size(spikes.times{cc}));
end
if spikes.numcells>0
    alltimes = cat(1,spikes.times{:}); groups = cat(1,groups{:}); %from cell to array
    [alltimes,sortidx] = sort(alltimes); groups = groups(sortidx); %sort both
    spikes.spindices = [alltimes groups];
end

%% Check if any cells made it through selection
if isempty(spikes.times) | spikes.numcells == 0
    spikes = [];
end

end

%%
function spikes = removeCells(toRemove,spikes,getWaveforms)
%Function to remove cells from the structure. toRemove is the INDEX of
%the UID in spikes.UID

    spikes.UID(toRemove) = [];
    spikes.times(toRemove) = [];
    spikes.region(toRemove) = [];
    spikes.cluID(toRemove) = [];
    spikes.shankID(toRemove) = [];

    if any(getWaveforms)
        spikes.rawWaveform(toRemove) = [];
        spikes.maxWaveformCh(toRemove) = [];
    end

end


function str=getSummaryStr(obj, format)
% get summary of tests that were run and their output
%
% str=getSummaryStr(obj, format)
%
% Inputs:
%   obj                 MOxUnitTestReport instance
%   format              Output format: 'xml' or 'text'
%
% Output:
%   str                 text or XML string representation of the results of
%                       the tests
%

    format2converter=struct();
    format2converter.text=@report2summary_text;
    format2converter.xml=@report2summary_xml;

    f=format2converter.(format);
    str=f(obj);

function str=report2summary_xml(obj)
% return summary in XML format
    header=sprintf('<testsuite name="%s" time="%.3f" %s>',...
                    moxunit_util_escape_xml(getName(obj)),...
                    getDuration(obj),...
                    statistics_xml(obj));

    summary_text_cell=get_outcome_summary_cell(obj,'xml');
    body=moxunit_util_strjoin(summary_text_cell,'\n');

    footer='</testsuite>';
    str=sprintf('%s\n%s\n%s',header,body,footer);

function str=report2summary_text(obj)
% return summary in text format
    verbosity=obj.verbosity;

    hor_line=repmat('-',1,50);

    body='';
    if verbosity>=2 || ~wasSuccessful(obj)
        summary_text_cell=get_outcome_summary_cell(obj,'text');
        non_empty_msk=~cellfun(@isempty,summary_text_cell);
        if any(non_empty_msk)
            summary_text_cell_nonempty=summary_text_cell(non_empty_msk);
            body_non_pass=moxunit_util_strjoin(...
                                summary_text_cell_nonempty,'\n\n');
            body=sprintf('\n%s\n\n%s\n%s\n\n',hor_line,body_non_pass);
        end
    end

    if verbosity>=1
        footer=sprintf('\n%s\n\n%s',hor_line,statistics_text(obj));
    else
        footer='';
    end

    str=sprintf('%s%s',body,footer);

function [c,n_tests]=get_outcome_summary_cell(obj, format)
% helper function to get the summary from each test
    n_tests=countTestOutcomes(obj);
    c=cellfun(@(x)getSummaryStr(getTestOutcome(obj,x),format),...
                    num2cell(1:n_tests),...
                    'UniformOutput',false);

function str=statistics_xml(obj)
% return xml string indicating number of tests, and how many were failures,
% skips and errors
%
% Example outputs:
%       'tests="9"'
%       'tests="9" failures="2"'

    total_tests=sprintf('tests="%d"',countTestOutcomes(obj));

    labels_singular_plural={'failure','failures';...
                            'skipped','skipped';...
                            'error','errors'};
    n_labels=size(labels_singular_plural,1);

    label2count=getTestOutputStatistics(obj);
    non_success_tests_cell=cell(n_labels,1);
    for k=1:n_labels
        singular=labels_singular_plural{k,1};
        plural=labels_singular_plural{k,2};

        if isfield(label2count,singular)
            count=label2count.(singular);
        else
            count=0;
        end

        non_success_tests_cell{k}=sprintf('%s="%d"',plural,count);
    end

    str=sprintf('%s %s',total_tests,...
                    moxunit_util_strjoin(non_success_tests_cell,' '));

function str=statistics_text(obj)
% return text string indicating whether all tests passed or not, and
% number of failures, skips and errors.
%
% Example outputs:
%       'OK'
%       'FAILED (skipped=2)'

    if wasSuccessful(obj)
        str='OK';
    else
        str='FAILED';
    end

    label_counts=getTestOutputStatistics(obj);
    labels=fieldnames(label_counts);

    n_labels=numel(labels);
    if n_labels>0
        cell_stats=cellfun(@(x) sprintf('%s=%d',x, label_counts.(x)),...
                                    fieldnames(label_counts),...
                                    'UniformOutput',false);
        str=sprintf('%s (%s)',str,moxunit_util_strjoin(cell_stats,', '));
    end


function functionals2mrGray(volumeView, coordMask)
%
% functionals2mrGray(volumeView, [coordMask])
%
% AUTHOR:  S. Chial
% DATE:  02.05.99
% PURPOSE:
%   Writes out the functional data currently on display in the
%   volume window into an output file that can be read in by
%   mrGray (and mrUnfold) as an overlay file.
%
% volumeView: structure that contains all the information
% related to the volume functional data and user interface.
%
% sjc, 02/05/99
% rfd, 04/20/99 replaced the call to the now obsolete
%      "getOverlayClip" with a call to "getMapWindow".
% bw/hab 08/09/99
%      Introduced a subtraction of 1 from outLocs.  mrGray
%      locations run from [0 to n-1] and mrLoadRet run from [1 n].
%      This follows the change in readGrayGraph.  We abstracted
%      the conversion from mrLoadRet into mrGray with a new routine,
%      mrLoadRet2mrGray.
% rfd 10/15/99
%      Fixed a minor bug that produced bad cmap indices for some
%      clip ranges.  Basically, we just have to clip cmapIdx after we scale it.
% bw  01.16.01
%       Updated for mrLoadRet-2.5
%
% rfd 2002.08.08 added optional coordMask and updated to mrLoadRet-3
% bw  2003.08.28 added persistent recentDir, handled case of cancel on uiputfile

if(~exist('coordMask','var'))
    coordMask = [];
end
persistent recentDir      % Most recently visited directory

% Figure out which scan is being viewed.
%
scanNum = getCurScan(volumeView);

% Find the data that is above the correlation threshold
% and within the phase window.
%
coThreshold = getCothresh(volumeView);
validCoIdx = find(volumeView.co{scanNum} >= coThreshold);

phaseWindow = getPhWindow(volumeView);
validPhIdx = find((volumeView.ph{scanNum} >= phaseWindow(1)) & ...
    (volumeView.ph{scanNum} <= phaseWindow(2)));

validDataIdx = intersect(validCoIdx,validPhIdx);

% Extract the data being displayed and the corresponding locations
%
cmd = ['validData = volumeView.' volumeView.ui.displayMode '{scanNum}(validDataIdx);'];
eval(cmd);
outLocs = volumeView.coords(:,validDataIdx);
if(~isempty(coordMask))
    [outLocs, keepThese] = intersectCols(outLocs, coordMask);
else
    keepThese = [];
end

% Take mrLoadRet-2.0 locations (here outLocs) and convert them to
% mrGray locations.
%
outLocs = mrLoadRet2mrGray(outLocs);
%
% This is now done in mrLoadRet2mrGray:
%    outLocs = [outLocs(2,:); outLocs(1,:); outLocs(3,:)];

% Get the colormap for the data, convert it from having
% a range of 0 to 1 to a range of 0 to 255.
%
modeStr=['volumeView.ui.',volumeView.ui.displayMode,'Mode'];
mode = eval(modeStr);
cmap = round(255*mode.cmap);
numGrays = mode.numGrays;
numColors = mode.numColors;
clipMode = mode.clipMode;

% Only keep the part of the colormap that is color
%
cmap = cmap([numGrays+1:numGrays+numColors],:);

% Map the data to a color, clipping the colormap appropriately
%
overlayClip = getMapWindow(volumeView);
if ~isempty(validData)
    if strcmp(clipMode,'auto')
        minVal = min(validData);
        maxVal = max(validData);
        overClipMin = min(overlayClip)*(maxVal-minVal) + minVal;
        overClipMax = max(overlayClip)*(maxVal-minVal) + minVal;
    else
        overClipMin = min(clipMode);
        overClipMax = max(clipMode);
    end
    cmapIdx = round(scale_im(validData,1,numColors,overClipMin,overClipMax));
    % RFD: we need to clip, in case there are values above overClipMax or
    % under overClipMin.
    cmapIdx = round(clip(cmapIdx,1,numColors));
end
if(~isempty(keepThese))
    cmapIdx = cmapIdx(keepThese);
end

% Prompt user for a file name to save the data under
%
% This part of the routine should probably be a call to the new routine:
%
%    writeMrGray([outLocs; cmapIdx(:)'],cmap)
%
curDir = pwd;
if ~isempty(recentDir)
    if(exist(recentDir,'dir')) chdir(recentDir); end
else
    anatDir = getAnatomyPath([]);
    if(exist(anatDir,'dir')) chdir(anatDir); end;
end

[f p] = uiputfile('*.*','Save mrGray overlay file...');
if isequal(f,0) | isequal(p,0)
    return;
else
    chdir(curDir);
    filename = fullfile(p,f);
end

if ~isempty(filename)
    recentDir = p;  % Save the most recently visited directory.

    fid = fopen(filename,'w');

    % Write out the number of colors
    fprintf(fid,'%d\n',numColors);

    % Write out the colormap [R,G,B]
    fprintf(fid,'%d %d %d\n', cmap');

    % Write out the location and index into the colormap for
    % each data point.
    fprintf(fid,'%d %d %d %d\n', [outLocs; cmapIdx(:)']);

    fclose(fid);
    fprintf('Finished saving functional data overlay.\n');
end

return;


function res_feat = extract_features(image, pos, scales, features, gparams, extract_info)

% Sample image patches at given position and scales. Then extract features
% from these patches.
% Requires that cell size and image sample size is set for each feature.

if ~iscell(features)
    error('Wrong input');
end

if ~isfield(gparams, 'use_gpu')
    gparams.use_gpu = false;
end
if ~isfield(gparams, 'data_type')
    gparams.data_type = zeros(1, 'single');
end
if nargin < 6
    % Find used image sample size
    extract_info = get_feature_extract_info(features);
end

num_features = length(features);
num_scales = length(scales);
num_sizes = length(extract_info.img_sample_sizes);

% Extract image patches
img_samples = cell(num_sizes,1);
for sz_ind = 1:num_sizes
    img_sample_sz = extract_info.img_sample_sizes{sz_ind};
    img_input_sz = extract_info.img_input_sizes{sz_ind};
    img_samples{sz_ind} = zeros(img_input_sz(1), img_input_sz(2), size(image,3), num_scales, 'uint8');
    for scale_ind = 1:num_scales
        img_samples{sz_ind}(:,:,:,scale_ind) = get_pixels(image, pos, round(img_sample_sz*scales(scale_ind)),img_input_sz);
    end
end

% Find the number of feature blocks and total dimensionality
num_feature_blocks = 0;
total_dim = 0;
for feat_ind = 1:num_features
    num_feature_blocks = num_feature_blocks + length(features{feat_ind}.fparams.nDim);
    total_dim = total_dim + sum(features{feat_ind}.fparams.nDim);
end

feature_map = cell(1, 1, num_feature_blocks);

% Extract feature maps for each feature in the list
ind = 1;
CNN_ind = -1;
for feat_ind = 1:num_features
    feat = features{feat_ind};

    % get the image patch index
    img_sample_ind = cellfun(@(sz) isequal(feat.img_sample_sz, sz), extract_info.img_sample_sizes);

    % do feature computation
    if feat.is_cell
        num_blocks = length(feat.fparams.nDim);
        feature_map(ind:ind+num_blocks-1) = feat.getFeature(img_samples{img_sample_ind}, feat.fparams, gparams);
        CNN_ind = ind;
    else
        num_blocks = 1;
        feature_map{ind} = feat.getFeature(img_samples{img_sample_ind}, feat.fparams, gparams);
    end

    ind = ind + num_blocks;
end

% Do CNN feature normalization per channel
if(CNN_ind ~= -1)
    CNN_feat = {feature_map{CNN_ind}};
    delta = 1e-7;

    for i = 1:numel(CNN_feat)
        min_ele = repmat(min(min(CNN_feat{i},[],2),[],1), [size(CNN_feat{i},1),size(CNN_feat{i},2),1,1]);
        max_ele = repmat(max(max(CNN_feat{i},[],2),[],1), [size(CNN_feat{i},1),size(CNN_feat{i},2),1,1]) + delta;
        CNN_feat{i} = ( CNN_feat{i} - min_ele ) ./ (max_ele - min_ele);
    end
end

% Combine the features. In particular, the hand-crafted features are concatnated together
% along the channels.
if(CNN_ind ~= -1)
    res_feat = cell(2, 1);
    res_feat{2} = CNN_feat{1};
end

% concatnate the grayscale and HOG features only when the input is the grayscale
% image.
if(CNN_ind ~=-1)
    if(num_features == 3)
        res_feat{1} = cat(3,feature_map{1}, feature_map{2});
    else
        res_feat{1} = cat(3,feature_map{1}, feature_map{2}, feature_map{3});
    end
else
    if(num_features == 3)
        res_feat{1} = cat(3,feature_map{1}, feature_map{2}, feature_map{3});
    else
        res_feat{1} = cat(3,feature_map{1}, feature_map{2});
    end
end

end


% Script to make a mrSESSION directory from analyze-format data
% You need to fill in many of the parameters below.
% Note that you need to have converted everything (Inplanes and TSeries) to analyze format before
% you run this script.
% Assume we run this in the destination dir.

clear all;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Set up directory info

anatomyInplaneDir=26; % This is the location of the IRRARE T1 weighted data

% Where are the source files for the data?
% sourceFileBaseDir='/raid/MRI/data/wade/Nikos_Data/Monkey/Spring2003/original/C01.j51/converted/'
% sourceFileBaseDir='//biac1/wandell/data/monkey/retinal-lesion/A01/Ky1/converted/'
 sourceFileBaseDir='G:/data/monkey/retinal-lesion/convertedScans/A01/ky1/converted/'

sourceSubDirArray=[16]; %locations of the functional scans, ex. [1:4];
nFunctionals=length(sourceSubDirArray);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Enter mrSESSION info - you will need to edit many of these parameters
% These steps replace mrInitRet.

MLR_ScanOffset=0;  % mrLoadRet needs scans numbered 1:n; we need to convert from scans numbered 16:25, for example
                   % the offsest lets us start the mrLoadRet numbering at a
                   % different number other than 1, when adding scans to a
                   % previously created directory.

M.mrLoadRetVersion=3.0100;
M.sessionCode='A01_Ky1_Ret'
M.description='MPI: Ret scans A01, session Ky1'
M.subject='A01'
M.examNum='A01_Ky1';

% INPLANES
I.FOV=128; % in mm
I.fullSize=[256 256]; % pixels
I.voxelSize=[0.5 0.5 2] % in mm
I.spacing=0
I.nSlices=17
I.examNum=M.examNum
I.crop=[0 0;255 255]; % top left, bottom right coordinates. In this case, no crop.
I.cropSize=[256 256];

M.inplanes=I;

% FUNCTIONALS
F.PfileName=0; % To be filled in later when we loop over the functionals
F.totalFrames=132;
F.junkFirstFrames=0;
F.nFrames=F.totalFrames-F.junkFirstFrames;
F.slices=1:I.nSlices;
F.fullSize=[256 256]; % Resolution, in pixels    %%128?
F.cropSize=[256 256]; % no need to crop image    %%128?
F.crop=[0 0;127 127];
F.voxelSize=[I.FOV./F.fullSize,  I.voxelSize(3)];
F.effectiveResolution=F.voxelSize;
F.framePeriod=6.5;  % The length of 1 TR (TR = 'effective frame duration' = tAcq*nshots) times the number of interleaves
                    % for 15 slices, TR = 6; for 17 slices, TR = 6.5

% RECONPARAMS
R.nframes=F.totalFrames;
R.nshots=8;         %check excel file for this
R.FOV=I.FOV;
R.sliceThickness=I.voxelSize(3);
R.skip=0
R.TR=F.framePeriod;

R.tAcq=806;        %tAcq is the actual TR. Multiply this by the number of
                    %shots to get the effective frame duration. This is 8
                    %for 17 slice monkeys - check excel file.

R.slquant=I.nSlices;

R.equivMatSize=256;  %%128?
R.imgsize=128;  %%128?
F.reconParams=R;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now we loop through all the n directories listed in sourceSubDirArray
% We will create a 1xn functionals structure in mrSESSION by copying F a lot. The only thing we'll change will
% be F.PfileName We also create dataTYPES at this point. dataTYPES will be a single structure with some
% 1xn sub-structures.
%            scanParams: [1x14 struct]
%            blockedAnalysisParams: [1x14 struct]
%            eventAnalysisParams: [1x14 struct]
% eventAnalysisParams are all 0
% Scan params and blockedAnalysisParams are to be set in the loop by copying in the structures we define next.....

%SCAN PARAMETERS
S.annotation='retinotopy';
S.nFrames=F.nFrames;
S.framePeriod=F.framePeriod
S.slices=F.slices;
S.cropSize=F.cropSize;

%BLOCKED ANALYSIS PARAMETERS
B.blockedAnalysis=1;
B.detrend=1;      % -1 = linear detrend; 1 = high pass filter; varied opinions on which is better.
B.inhomoCorrect=1;
B.nCycles=11; % For the color expts=4. For the retinotopies, this is 12??? For J02 this is 11;

B.temporalNormalization=0; % This is essential for the MPG scans that were converted brucker to analyze with the BUG.
                           % For all good/normal scans set this to 0.

E.eventAnalysis=0;

nScans=length(sourceSubDirArray);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Make more Dirs. Be sure to run makemrLoadRet3Session in the destination
% directory.

disp('Generating sub directories');

a=mkdir('Inplane'); % Holds data in 'slice' format
a=mkdir('Gray'); % Holds data in 3D restricted to the cortical gray matter
a=mkdir('Volume'); % Barely used. Holds data in 3D
a=mkdir('Raw'); % Original FID files, IRRARE files etc.
a=mkdir('Raw/Anatomy');
a=mkdir('Raw/Anatomy/Inplane');
a=mkdir('Inplane/ROIs'); % Regions of interest
a=mkdir('Inplane/Original');
a=mkdir('Inplane/Original/TSeries');
a=mkdir('Gray/ROIs');

tSerDir=['Inplane/Original/TSeries/'];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Convert the inplanes and generate the anat.mat file.

inpIndex=sprintf('%02d',anatomyInplaneDir);

rotateInplanes=1; % Number of 90degree ccw rotations to apply to everything to make it look nice.
                    % # rotations = rotateInplanes * 90

% anatFile=fullfile(sourceFileBaseDir,int2str(anatomyInplaneDir),[M.subject,'_',inpIndex])
% anat=analyze2mrLoadRetInplanes(fullfile(sourceFileBaseDir,int2str(anatomyInplaneDir),[M.subject,'_',inpIndex]),'./');
% anatFile=fullfile(sourceFileBaseDir,int2str(anatomyInplaneDir))
% anat=analyze2mrLoadRetInplanes(anatFile,'./');
anat=analyze2mrLoadRetInplanes(fullfile(sourceFileBaseDir,int2str(anatomyInplaneDir),'2dseq_001'),'./Raw/Anatomy/Inplane/');

[x,y,nSlices]=size(anat);

% Run through the anat matrix and do rotations
for t=1:nSlices
    anat(:,:,t)=rot90(anat(:,:,t),rotateInplanes);
end

save('Inplane/anat.mat','anat');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create dataTYPES structure

dataTYPES.name='Original';

for t=1:nFunctionals
    F.PfileName=['P_MPI_',int2str(sourceSubDirArray(t))];
    M.functionals(t)=F;

    % Also fill in the dataTYPES structure.
    dataTYPES.blockedAnalysisParams(t)=B;
    dataTYPES.eventAnalysisParams(t)=E;
    dataTYPES.scanParams(t)=S;
    dataTYPES.name='Original';

end

global mrSESSION;
global dataTYPES;
global HOMEDIR;

mrSESSION=M;

saveSession;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now we're ready to import and convert the functional data

disp ('Saved mrSESSION: Now converting tSeries data...');

for thisScan=1:nFunctionals

    % make the directory and name of the tSeries files to be created here
    thisTSerDir=fullfile(tSerDir,['Scan',int2str(thisScan+MLR_ScanOffset)])
    a=mkdir(thisTSerDir);

    % input path and name of input analyze files (2dseq_)
    thisFunc=int2str(sourceSubDirArray(thisScan));
    thisFunc02Padded=sprintf('%02d',sourceSubDirArray(thisScan));
    % sourceRoot=fullfile(sourceFileBaseDir,thisFunc,[M.subject,'_',thisFunc02Padded,'_EPI_']);
    sourceRoot=fullfile(sourceFileBaseDir,thisFunc,'2dseq_');

    % imStack=analyze2mrLoadRetTSeries(inFileRoot,outFileRoot,nVols,firstVolIndex,doRotate,scaleFact,flipudFlag,fliplrFlag)
    % where doRotate can be any integer. The images are rotated anticlockwise by doRotate*90degrees.
    % scaleFact is a 2*1 scale factor for scaling the x and y dimensions independently.
    % if flipudFlag or fliprlFlag is set, the images are flipped up/down or left/right after rotation
    imStack=analyze2mrLoadRet3TSeries(sourceRoot,thisTSerDir,F.nFrames,F.junkFirstFrames+1,1,1,0,0);

    fprintf('\nDone scan %d (directory %d)\n',thisScan,sourceSubDirArray(thisScan));

end


function [ tokens ] = strtokenize( str, delim )
%STRTOKENIZE Summary of this function goes here
%   Detailed explanation goes here

    tokens = cell(0);
    remain = str;

    while true
        [token remain] = strtok(remain, delim);
        if (isempty(token))
            break;
        end;
        tokens(end+1) = {token};
    end;

end


function obj = addConstraint(obj, label, nodes, cstr_array)
    % Add NLP constraints constraints
    %
    %
    % Parameters:
    % label: the label name (column) of the constraints @type char
    % nodes: the node list of the variable @type rowvec
    % cstr_array: an array of structures that could be used to construct
    % the NlpFunction object. @type struct
    %
    % @see NlpFunction, removeConstraint
    %
    % @note

    cstr_names = obj.ConstrTable.Properties.VariableNames;

%     if ismember(label,cstr_names)
%         warning('The NLP constraint (%s) already exist.\n Overwriting the existing constraint.', label);
%     end

    if ischar(nodes)
        switch nodes
            case 'first'
                node_list = 1;
            case 'last'
                node_list = obj.NumNode;
            case 'terminal'
                node_list = [1 obj.NumNode];
            case 'except-first'
                node_list = 2:obj.NumNode;
            case 'except-last'
                node_list = 1:obj.NumNode-1;
            case 'except-terminal'
                node_list = 2:obj.NumNode-1;
            case 'all'
                node_list = 1:obj.NumNode;
            case 'cardinal'
                node_list = 1:2:obj.NumNode;
            case 'interior'
                node_list = 2:2:obj.NumNode-1;
            otherwise
                error('Unknown node type.');
        end
    else
        if ~isnumeric(nodes)
            error(['The node must be specified as a list or following supported characters:\n',...
                '%s'],implode({'first','last','all','except-first','except-last','except-terminal', 'cardinal', 'interior'},','));
        else
            node_list = nodes;
        end
    end

    assert(length(node_list)==length(cstr_array),...
        'The length of the array (%d) of constraint structures must be the same as the number of nodes (%d) to be imposed.',...
        length(cstr_array),length(node_list));

    % create empty NlpVariable array
    if isa(cstr_array,'NlpFunction')
        constr = repmat(NlpFunction(),obj.NumNode,1);
        for j=1:numel(node_list)
            constr(node_list(j)) = cstr_array(j);
        end
    elseif isstruct(cstr_array)

        constr = repmat(NlpFunction(),obj.NumNode,1);
        for j=1:numel(node_list)
            constr(node_list(j)) = NlpFunction(cstr_array(j));
        end
    end

    % add to the constraints table
    if ismember(label,cstr_names)
        obj.ConstrTable.(label)(node_list) = constr(node_list);
    else
        obj.ConstrTable.(label) = constr;
    end
end


function imdb = setup_voc07_eb(varargin)
% cnn_voc07_eb_setup_data  Initialize PASCAL VOC2007 data with edge
% boxes

% Warning! boxes are in the format of ([y1 x1 y2 x2])

opts.dataDir = fullfile('data') ;
opts.proposalDir = fullfile(opts.dataDir,'EB');
opts.loadTest = 1;
opts = vl_argparse(opts, varargin) ;

% -------------------------------------------------------------------------
%                                                 Load selective search win
% -------------------------------------------------------------------------
%% Get selective search windows
files = {'EdgeBoxesVOC2007trainval.mat', ...
  'EdgeBoxesVOC2007test.mat'} ;

if ~exist(opts.proposalDir, 'dir')
  mkdir(opts.proposalDir) ;
end

for i=1:numel(files)
  outPath = fullfile(opts.proposalDir, files{i}) ;
  if ~exist(outPath, 'file')
    url = sprintf('http://groups.inf.ed.ac.uk/hbilen-data/data/WSDDN/%s',files{i}) ;
    fprintf('Downloading %s to %s\n', url, outPath) ;
    urlwrite(url,outPath) ;
  end
end

if ~isempty(opts.proposalDir)
  t1 = load([opts.proposalDir,filesep,files{1}]);
  if opts.loadTest
    t2 = load([opts.proposalDir,filesep,files{2}]);
    ssw.id = [str2double(t1.images) str2double(t2.images)];
    ssw.boxes = cat(2,t1.boxes,t2.boxes);
    ssw.boxScores = cat(2,t1.boxScores,t2.boxScores);
  else
    ssw.id = str2double(t1.images);
    ssw.boxes = t1.boxes;
    ssw.boxScores = t1.boxScores;
  end

  [~,si] = sort(ssw.id);
  ssw.id = ssw.id(si);
  ssw.boxes = ssw.boxes(si);
  ssw.boxScores = ssw.boxScores(si);
end

% -------------------------------------------------------------------------
%                                                  Load categories metadata
% -------------------------------------------------------------------------
cats = {'aeroplane','bicycle','bird','boat','bottle','bus','car',...
  'cat','chair','cow','diningtable','dog','horse','motorbike','person',...
  'pottedplant','sheep','sofa','train','tvmonitor'};

if ~exist(opts.dataDir,'dir')
  error('wrong data folder!');
end

% Download VOC Devkit and data
if ~exist(fullfile(opts.dataDir,'VOCdevkit'),'dir')
  files = {'VOCtest_06-Nov-2007.tar',...
           'VOCtrainval_06-Nov-2007.tar',...
           'VOCdevkit_08-Jun-2007.tar'} ;
  for i=1:numel(files)
    if ~exist(fullfile(opts.dataDir, files{i}), 'file')
      outPath = fullfile(opts.dataDir,files{i}) ;
      url = sprintf('http://host.robots.ox.ac.uk/pascal/VOC/voc2007/%s',files{i}) ;
      fprintf('Downloading %s to %s\n', url, outPath) ;
      urlwrite(url,outPath) ;
      untar(outPath,opts.dataDir);
    end
  end
end
addpath(fullfile(opts.dataDir, 'VOCdevkit', 'VOCcode'));

traindata = importdata(fullfile(opts.dataDir,'VOCdevkit','VOC2007','ImageSets','Main','train.txt'));
valdata = importdata(fullfile(opts.dataDir,'VOCdevkit','VOC2007','ImageSets','Main','val.txt'));
testdata = importdata(fullfile(opts.dataDir,'VOCdevkit','VOC2007','ImageSets','Main','test.txt'));

assert(numel(traindata)==2501);
assert(numel(valdata)==2510);
assert(numel(testdata)==4952);

imdb.classes.name = cats ;
imdb.classes.description = cats ;
imdb.imageDir = fullfile(opts.dataDir, fullfile('VOCdevkit','VOC2007','JPEGImages')) ;

% -------------------------------------------------------------------------
%                                                           Training images
% -------------------------------------------------------------------------%
names = cell(1,numel(traindata));
labels = zeros(numel(traindata),numel(cats));

% load image names
for t=1:numel(traindata)
  names{t} = sprintf('%06d.jpg',traindata(t));
  %   data{t} = imread(sprintf('%s/%s',imdb.imageDir,names{t}));
end

% load binary labels
for c=1:numel(cats)
  t = importdata(fullfile(opts.dataDir,'VOCdevkit','VOC2007','ImageSets','Main',[cats{c},'_train.txt']));
  labels(:,c) = t(:,2);
end

imdb.images.id = traindata';
imdb.images.name = names ;
imdb.images.set = ones(1, numel(names)) ;
imdb.images.label = labels' ;
% imdb.images.data = data;

% -------------------------------------------------------------------------
%                                                         Validation images
% -------------------------------------------------------------------------

names = cell(1,numel(valdata));
labels = zeros(numel(valdata),numel(cats));
% data = cell(1,numel(valdata));

% load image names
for t=1:numel(valdata)
  names{t} = sprintf('%06d.jpg',valdata(t));
  %   data{t} = imread(sprintf('%s/%s',imdb.imageDir,names{t}));
end

% load binary labels
for c=1:numel(cats)
  t = importdata(fullfile(opts.dataDir,'VOCdevkit','VOC2007','ImageSets','Main',[cats{c},'_val.txt']));
  labels(:,c) = t(:,2);
end

imdb.images.id = horzcat(imdb.images.id, valdata') ;
imdb.images.name = horzcat(imdb.images.name, names) ;
imdb.images.set = horzcat(imdb.images.set, 2*ones(1,numel(names))) ;
imdb.images.label = horzcat(imdb.images.label, labels') ;
% imdb.images.data = horzcat(imdb.images.data, data) ;

% % -------------------------------------------------------------------------
% %                                                               Test images
% % -------------------------------------------------------------------------
%
%
if opts.loadTest
  names = cell(1,numel(testdata));
  labels = zeros(numel(testdata),numel(cats));
  % data = cell(1,numel(testdata));

  % load image names
  for t=1:numel(testdata)
    names{t} = sprintf('%06d.jpg',testdata(t));
    %   data{t} = imread(sprintf('%s/%s',imdb.imageDir,names{t}));
  end

  % load binary labels
  for c=1:numel(cats)
    t = importdata(fullfile(opts.dataDir,'VOCdevkit','VOC2007','ImageSets','Main',[cats{c},'_test.txt']));
    labels(:,c) = t(:,2);
  end

  imdb.images.id = horzcat(imdb.images.id, testdata') ;
  imdb.images.name = horzcat(imdb.images.name, names) ;
  imdb.images.set = horzcat(imdb.images.set, 3 * ones(1,numel(names))) ;
  imdb.images.label = horzcat(imdb.images.label, labels') ;
  % imdb.images.data = horzcat(imdb.images.data, data) ;
end
% -------------------------------------------------------------------------
%                                                            Postprocessing
% -------------------------------------------------------------------------
[~,sorti] = sort(imdb.images.id);

imdb.images.id = imdb.images.id(sorti);
imdb.images.name = imdb.images.name(sorti) ;
imdb.images.set = imdb.images.set(sorti) ;
imdb.images.label = single(imdb.images.label(:,sorti)) ;
imdb.images.size = zeros(numel(imdb.images.name),2);

if ~isempty(opts.proposalDir)
  imdb.images.boxes = ssw.boxes;
  imdb.images.boxScores = ssw.boxScores;
  assert(all(ssw.id==imdb.images.id));
end

% this is zero as scores of selective search windows are not much
% informative
if ~isempty(opts.proposalDir)
  % imdb.images.boxScores = cell(size(imdb.images.boxes));
  for i=1:numel(imdb.images.boxes)
    imdb.images.boxes{i} = int16(imdb.images.boxes{i});
    imdb.images.boxScores{i} = single(imdb.images.boxScores{i});

    imf = imfinfo(fullfile(imdb.imageDir,imdb.images.name{i}));
    imdb.images.size(i,:) = [imf.Height,imf.Width];

    maxBoxes = max(imdb.images.boxes{i});
    if imdb.images.size(i,1)< max(maxBoxes([1,3]))
      error('Wrong box coordinates');
    end
    if imdb.images.size(i,2)< max(maxBoxes([2,4]))
      error('Wrong box coordinates');
    end

  end
end
end


% clc; clear all; close all;

%% hydro data
hydro = struct();
hydro = readWAMIT(hydro,'rm3.out',[]);
hydro = radiationIRF(hydro,60,[],[],[],[]);
hydro = radiationIRFSS(hydro,[],[]);
hydro = excitationIRF(hydro,157,[],[],[],[]);
writeBEMIOH5(hydro)

%% Plot hydro data
% plotBEMIO(hydro)


function excelrecord2fcn(T, n, endo, stringdates1, Y, Ytilde, pref, EPStilde)
% script excelrecord2
% records the information contained in the worksheets 'actual fitted' and 'resids' of the excel spreadsheet 'results.xls'

% first compute the cell for actual/ fitted

% create the cell that will be saved on excel
afcell={};

% build preliminary elements: space between the tables
vertspace=repmat({''},T+3,1);

% loop over variables (horizontal dimension)
for ii=1:n
% create cell of actual/fitted for variable ii
temp=['actual and fitted: ' endo{ii,1}];
af_i=[temp {''} {''};{''} {''} {''};{''} {'sample'} {'fitted'};stringdates1 num2cell(Y(:,ii)) num2cell(Ytilde(:,ii))];
afcell=[afcell af_i vertspace];
end

% trim
afcell=afcell(:,1:end-1);

% write in excel
if pref.results==1
    bear.xlswritegeneral(fullfile(pref.results_path, [pref.results_sub '.xlsx']),afcell,'actual fitted','B2');
end

% then compute the cell for the residuals

% create the cell that will be saved on excel
horzspace=repmat({''},1,n);
rescell=[{'residuals'} horzspace;{''} horzspace;{''} endo';stringdates1 num2cell(EPStilde)];

% write in excel
if pref.results==1
    bear.xlswritegeneral(fullfile(pref.results_path, [pref.results_sub '.xlsx']),rescell,'resids','B2');
end


function bookplot(fig, plotfile)
%bookplot   saves IFISS figure as postscript file
%   bookplot(fig, plotfile);
%   input
%          fig        figure number of figure to be saved
%          plotfile   character string naming the file
%
%   uses the MATLAB script exportfig
%   IFISS function: DJS; 28 February 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage
fprintf('\nCreating plotfiles ...')
gohome, cd plotfiles
figure(fig)
exportfig(gcf,[plotfile,'ef.eps'],'width',4.5,'fontmode','fixed',...
          'fontsize',8,'color','bw')
fprintf('\n%s',[plotfile,'ef.eps'])
exportfig(gcf,[plotfile,'ef.epsc'],'width',4.5,'fontmode','fixed',...
          'fontsize',8,'color','cmyk')
fprintf('\n%s\n',[plotfile,'ef.epsc'])
return


function [cumRet, cumProdRet, dailyRet, dailyPortfolio] ...
    = ubah(fid, data, varargins, opts)
% This file is an entry for the market strategy.
%
% function [cumRet, cumProdRet, dailyRet, dailyPortfolio] ...
%     = ubah(fid, data, varargins, opts)
% cumRet: cumulative wealth achived at the end of a period.
% cumProdRet: cumulative wealth achieved till the end each period.
% dailyRet: daily return achieved by a strategy.
% dailyPortfolio: daily portfolios
%
% data: market sequence vectors
% fid: handle for write log file
% varargins: variable parameters
% opts: option parameter for behvaioral control
%
% Example: [cumRet, cumProdRet, dailyRet, dailyPortfolio] ...
%          = market_start(fid, data, {0}, opts);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file is part of OLPS: http://OLPS.stevenhoi.org/
% Original authors: Bin LI, Steven C.H. Hoi
% Contributors:
% Change log:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Extract the parameters
tc = varargins{1};      % transaction cost fee rate

% Run the market algorithm
[cumRet, cumProdRet, dailyRet, dailyPortfolio] ...
    = ubah_run(fid, data, tc, opts);

end
%%%%%%%%%%%%%%End%%%%%%%%%%%%%%%%%%%%%%


function varargout = st_analyze(varargin)
% KJ_ANALYZE Application M-file for kj_analyze.fig
%    FIG = KJ_ANALYZE launch kj_analyze GUI.
%    KJ_ANALYZE('callback_name', ...) invoke the named callback.

% Last Modified by GUIDE v2.0 20-Aug-2003 09:47:18

if (nargin == 2) & ~ischar(varargin{1})  % LAUNCH GUI

  fig = openfig(mfilename);

  % Use system color scheme for figure:
  set(fig,'Color',get(groot,'defaultUicontrolBackgroundColor'));

  % Generate a structure of handles to pass to callbacks, and store it.
  handles = guihandles(fig);
  % Store the data
  handles.params = varargin{1};
  handles.hParentFigure = varargin{2};

  % Do a first plot with default values
  plotit(handles);

  guidata(fig, handles);

  if nargout > 0
    varargout{1} = fig;
  end

elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK

  try
    [varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
  catch
    disp(lasterr);
  end

end

% --------------------------------------------------------------------
function plotit(handles)

% Plot the frequency magnitude distribution
if get(handles.radEntireCatalog, 'Value') == 1
  mPlotCatalog = handles.params.mCatalog;
else
  mPlotCatalog = handles.mNodeCatalog;
end

axes(handles.axsFMD);
set(handles.axsFMD, 'NextPlot', 'replace');
set(handles.axsTimePlot, 'NextPlot', 'replace');
if get(handles.radEntireTime, 'Value') == 1
  % Plot the frequency magnitude distribution
  [hPlot, fBValue, fAValue, fStdDev, fMc] = plot_FMD(mPlotCatalog, 1, handles.axsFMD, 's', 'k', 1, handles.params.rOptions.nCalculateMC, handles.params.rOptions.fBinning);
  set(hPlot, 'MarkerSize', 10);
  sList = [cellstr('Entire time')];
  sList = [sList; cellstr(['     Mc: ' num2str(fMc)])];
  sList = [sList; cellstr(['b-value: ' num2str(fBValue)])];
  sList = [sList; cellstr(['a-value: ' num2str(fAValue)])];
  sList = [sList; cellstr(['std-dev: ' num2str(fStdDev)])];
  set(handles.lstValues, 'String', sList);
  % Plot the cumulative number
  [vDummy, vIndices] = sort(mPlotCatalog(:,3));
  mSortedCatalog = mPlotCatalog(vIndices(:,1),:) ;
  axes(handles.axsTimePlot)
  plot(mSortedCatalog(:,3),(1:length(mSortedCatalog(:,3))),'k-','era','xor');
else
  % Separate first catalog
  vSel_ = ((mPlotCatalog(:,3) >= handles.params.fStartFirstPeriod) & (mPlotCatalog(:,3) <= handles.params.fEndFirstPeriod));
  mFirst = mPlotCatalog(vSel_,:);

  % Separate second catalog
  vSel_ = ((mPlotCatalog(:,3) >= handles.params.fStartSecondPeriod) & (mPlotCatalog(:,3) <= handles.params.fEndSecondPeriod));
  mSecond = mPlotCatalog(vSel_,:);

  % Plot the frequency magnitude distribution for the first period
  [hPlot, fBValue1, fAValue, fStdDev, fMc] = plot_FMD(mFirst, 1, handles.axsFMD, 's', 'k', 1, handles.params.rOptions.nCalculateMC, handles.params.rOptions.fBinning);
  set(hPlot, 'MarkerSize', 3);
  sList = [cellstr('First period')];
  sList = [sList; cellstr(['     Mc: ' num2str(fMc)])];
  sList = [sList; cellstr(['b-value: ' num2str(fBValue1)])];
  sList = [sList; cellstr(['a-value: ' num2str(fAValue)])];
  sList = [sList; cellstr(['std-dev: ' num2str(fStdDev)])];
  sList = [sList; cellstr('')];
  % Plot the frequency magnitude distribution for the second period
  set(handles.axsFMD, 'NextPlot', 'add');
  [hPlot, fBValue2, fAValue, fStdDev, fMc] = plot_FMD(mSecond, 1, handles.axsFMD, '^', 'r', 1, handles.params.rOptions.nCalculateMC, handles.params.rOptions.fBinning);
  set(hPlot, 'MarkerSize', 3);
  sList = [sList; cellstr('Second period')];
  sList = [sList; cellstr(['     Mc: ' num2str(fMc)])];
  sList = [sList; cellstr(['b-value: ' num2str(fBValue2)])];
  sList = [sList; cellstr(['a-value: ' num2str(fAValue)])];
  sList = [sList; cellstr(['std-dev: ' num2str(fStdDev)])];
  sList = [sList; cellstr('')];
  sList = [sList; cellstr(['Delta-b: ' num2str(fBValue2-fBValue1)])];
  set(handles.lstValues, 'String', sList);

  % Normalize the two subcatalogs in time
  fMinTime = min(mFirst(:,3));
  mFirst(:,3) = mFirst(:,3) - fMinTime;
  fMinTime = min(mSecond(:,3));
  mSecond(:,3) = mSecond(:,3) - fMinTime;
  % Plot the cumulative number for the first period
  [vDummy, vIndices] = sort(mFirst(:,3));
  mSortedCatalog = mFirst(vIndices(:,1),:) ;
  axes(handles.axsTimePlot)
  plot(mSortedCatalog(:,3),(1:length(mSortedCatalog(:,3))),'k-','era','xor');
  % Plot the cumulative number for the second period
  [vDummy, vIndices] = sort(mSecond(:,3));
  mSortedCatalog = mSecond(vIndices(:,1),:) ;
  axes(handles.axsTimePlot)
  set(handles.axsTimePlot, 'NextPlot', 'add');
  plot(mSortedCatalog(:,3),(1:length(mSortedCatalog(:,3))),'r:','era','xor');
end

% --------------------------------------------------------------------
function varargout = radEntireCatalog_Callback(h, eventdata, handles, varargin)

if get(handles.radEntireCatalog, 'Value') == 1
  set(handles.radPickLocations, 'Value', 0);
  set(handles.btnPick, 'Enable', 'off');
else
  set(handles.radPickLocations, 'Value', 1);
  set(handles.btnPick, 'Enable', 'on');
end

% --------------------------------------------------------------------
function varargout = radPickLocations_Callback(h, eventdata, handles, varargin)

if get(handles.radPickLocations, 'Value') == 1
  set(handles.radEntireCatalog, 'Value', 0);
  set(handles.btnPick, 'Enable', 'on');
else
  set(handles.radEntireCatalog, 'Value', 1);
  set(handles.btnPick, 'Enable', 'off');
end

% --------------------------------------------------------------------
function varargout = radEntireTime_Callback(h, eventdata, handles, varargin)

if get(handles.radEntireTime, 'Value') == 1
  set(handles.radSplitPeriods, 'Value', 0);
else
  set(handles.radSplitPeriods, 'Value', 1);
end

% --------------------------------------------------------------------
function varargout = radSplitPeriods_Callback(h, eventdata, handles, varargin)

if get(handles.radSplitPeriods, 'Value') == 1
  set(handles.radEntireTime, 'Value', 0);
else
  set(handles.radEntireTime, 'Value', 1);
end

% --------------------------------------------------------------------
function varargout = btnRePlot_Callback(h, eventdata, handles, varargin)

plotit(handles);

% --------------------------------------------------------------------
function varargout = btnClose_Callback(h, eventdata, handles, varargin)

% Close the dialog
delete(handles.dlgAnalyze);

% --------------------------------------------------------------------
function varargout = btnPick_Callback(h, eventdata, handles, varargin)

% Get the axes handle of the plotwindow
axes(pf_result('GetAxesHandle', handles.hParentFigure, [], guidata(handles.hParentFigure)));

% Select a point in the plot window with the mouse
[fX, fY] = ginput(1);

pickit(handles, fX, fY);

% --------------------------------------------------------------------
function varargout = btnSelect_Callback(h, eventdata, handles, varargin)

fX = str2double(get(handles.txtXSelect, 'String'));
fY = str2double(get(handles.txtYSelect, 'String'));
pickit(handles, fX, fY);

% --------------------------------------------------------------------
function pickit(handles, fX, fY)

% Prepare the data
% If cross-section calculate the lenght along cross-section
if ~handles.params.bMap
  [nRow, nColumn] = size(handles.params.mCatalog);
  xsecx2 = handles.params.mCatalog(:,nColumn);  % length along x-section
  xsecy2 = handles.params.mCatalog(:,7);        % depth of hypocenters
end

% Calculate distance from center point and sort with distance
if handles.params.bMap
  vDistances = sqrt(((handles.params.mCatalog(:,1)-fX)*cos(pi/180*fY)*111).^2 + ((handles.params.mCatalog(:,2)-fY)*111).^2);
else
  vDistances = sqrt(((xsecx2 - fX)).^2 + ((xsecy2 + fY)).^2);
end

% Create the subcatalog
if handles.params.rOptions.nGriddingMode == 0
  % Use first nNumberEvents events
  [vTmp, vIndices] = sort(vDistances);
  mNodeCatalog = handles.params.mCatalog(vIndices,:);
  mNodeCatalog = mNodeCatalog(1:handles.params.nNumberEvents);
else
  % Use all events within fRadius
  vSelection = (vDistances <= handles.params.rOptions(1).fRadius);
  mNodeCatalog = handles.params.mCatalog(vSelection,:);
end

% Store the subcatalog for later use
handles.mNodeCatalog = mNodeCatalog;
guidata(handles.dlgAnalyze, handles);

% Export the node catalog
gui_export.mNodeCatalog = mNodeCatalog;
gui_export.fX = fX;
gui_export.fY = fY;
assignin('base', 'gui_export', gui_export);

% Replot the frequency magnitude distribution and cumulative number
plotit(handles);

% --------------------------------------------------------------------
function varargout = btnBWithTime_Callback(h, eventdata, handles, varargin)

axes(handles.axsBWithTime);
set(handles.axsBWithTime, 'NextPlot', 'replace');

%mCatalog = handles.mNodeCatalog;

fMcMin = str2double(get(handles.txtMcMin, 'String'));
fMcStep = str2double(get(handles.txtMcStep, 'String'));
fMcMax = str2double(get(handles.txtMcMax, 'String'));

nSteps = (fMcMax - fMcMin)/fMcStep + 1;
mColors = gui_Colormap_RedGrayBlue(nSteps);
nStep = 1;
for nMag = fMcMin:fMcStep:fMcMax
  vSel = handles.mNodeCatalog(:,6) >= nMag-0.0001;
  mCatalog = handles.mNodeCatalog(vSel,:);
% Defaults and inits
BV = [];
BV3 = [];
Nmin = 50;
nNumberEvents = str2double(get(handles.txtNumberEvents, 'String'));
nOverlap = str2double(get(handles.txtOverlap, 'String'));

for nCnt = 1:nNumberEvents/nOverlap:length(mCatalog) - nNumberEvents
    b = mCatalog(nCnt:nCnt + nNumberEvents,:);
    magco = min(b(:,6));
    l = b(:,6) >= magco-0.05;
    if length(b(l,:)) >= Nmin
        [uDummy bv stan,  uDummy] = bmemag(b(l,:));
    else
        bv = nan;
    end
    BV = [BV ; bv min(b(:,3)) ; bv max(b(:,3)) ; inf inf];
    BV3 = [BV3 ; bv mean(b(:,3)) stan ];
end

% Errorbar plot
hErrorbar = errorbar(BV3(:,2),BV3(:,1),BV3(:,3),BV3(:,3),'k');
set(hErrorbar(1), 'Color', [0.5 0.5 0.5], 'Linewidth', 1);
set(hErrorbar(2), 'Linewidth', 2, 'Color', mColors(nStep,:));
%
% % Timebar plot
% hTimebar = plot(BV(:,2),BV(:,1),'color',[0.5 0.5 0.5], 'Linewidth', 1);

% Values plot
%hValues = plot(BV3(:,2),BV3(:,1),'s');
%set(hValues,'LineWidth', 1, 'MarkerSize', 4,...
%    'MarkerFaceColor','w','MarkerEdgeColor','k','Marker','s');

  nStep = nStep + 1;
  set(handles.axsBWithTime, 'NextPlot', 'add');
end


function [gIX, numK] = SqueezeGroupIX(gIX)
U = unique(gIX);
numK = length(U);
for i = 1:numK
    old = U(i);
    gIX(gIX==old) = i;
end
end


function x = cvx_setdual( x, y )
x = cvx_setdual( cvx( x ), y );

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function filename = dtiWriteBrainVoyagerFibers(fiberGroups, filename, coordsType)
% Anyone use this for BV?  Or should we rename for Tal only?
%
% filename = dtiWriteBrainVoyagerFibers(fiberGroups, [filename], [coordsType])
%
% fiberGroups(grpNum).name = 'some text string'
% fiberGroups(grpNum).visible = 0 or 1 (boolean)
% fiberGroups(grpNum).thickness = fiber thickness (diameter? in mm?)
% fiberGroups(grpNum).colorRgb = [R G B] (0-255)
% fiberGroups(grpNum).fibers is a cell array of Nx3 lists of points (in
% XYZ Talairach space if coordsType=TAL)
%
% Writes the fibers (assumed to be in Talairach coords) to the specified
% file. Prompts the user for the file if none is given.
%
% coordsType should be 'TAL', 'SYS' or 'BVI'. Default is TAL.
%
% HISTORY:
%   2003.07.02 RFD (bob@white.stanford.edu) wrote it.
%
% Bob (c) Stanford VISTASOFT team.  Probably should be removed.

if(~exist('filename','var') | isempty(filename))
    [f, p] = uiputfile('fibers.fib', 'Save BrainVoyager fibers file...');
    if(isnumeric(f))
        disp('User cancelled.');
        filename = '';
        return;
    end
    filename = fullfile(p, f);
end
if(~exist('coordsType','var') | isempty(coordsType))
    coordsType = 'TAL';
end
numGroups = length(fiberGroups);
fid = fopen(filename, 'wt');
fprintf(fid, 'FileVersion: 1.0\n');
fprintf(fid, 'CoordsType:  %s\n', coordsType);
fprintf(fid, 'NrOfGroups:  %d\n\n', numGroups);
for(gNum=1:numGroups)
    fprintf(fid, 'Name:        %s\n', fiberGroups(gNum).name);
    fprintf(fid, 'Visible:     %d\n', fiberGroups(gNum).visible);
    fprintf(fid, 'Animate:     0\n');
    fprintf(fid, 'Thickness:   %6.2f\n', fiberGroups(gNum).thickness);
    fprintf(fid, 'Color:       %03d %03d %03d\n',  fiberGroups(gNum).colorRgb);
    numFibers = length(fiberGroups(gNum).fibers);
    fprintf(fid, 'NrOfFibers:  %d\n', numFibers);
    for(fNum=1:numFibers)
        numPoints = size(fiberGroups(gNum).fibers{fNum},1);
        fprintf(fid, 'NrOfPoints:  %d\n', numPoints);
        for(p=1:numPoints)
            fprintf(fid, '%7.3f %7.3f %7.3f\n', fiberGroups(gNum).fibers{fNum}(1,p), ...
                                                fiberGroups(gNum).fibers{fNum}(2,p), ...
                                                fiberGroups(gNum).fibers{fNum}(3,p));
        end
        fprintf(fid, '\n');
    end
    fprintf(fid, '\n\n');
end
fclose(fid);
return;

% Code from BrainVoyager:
%
% 	float pos_x, pos_y, pos_z, thickness;
% 	int n_groups, n_fibers, n_points, cr, cg, cb, FileVersion;
% 	bool SystemCoords;
% 	QString strTemp, strTemp2, CoordsType;
% 	// file header
% 	ar << "FileVersion: " << FibersFileVersion << "\n";
% 	if(FibersSystemCoords == 2)
% 		ar << "CoordsType:  BVI\n";
% 	else if(FibersSystemCoords == 1)
% 		ar << "CoordsType:  SYS\n";
% 	else
% 		ar << "CoordsType:  TAL\n";
% 	ar << "NrOfGroups:  " << NrOfFiberGroups << "\n\n";
% 	int g, i, p;
% 	for(g=0; g<NrOfFiberGroups; g++){
% 		ar << "Name:        " << QString(FiberGroups[g].Label) << "\n";
% 		ar << "Visible:     " << (int)FiberGroups[g].visible << "\n";
% 		ar << "Animate:     " << (int)FiberGroups[g].animate << "\n";
% 		ar << "Thickness:   " << FiberGroups[g].thickness << "\n";    // %6.2f
% 		ar << "Color:       " << FiberGroups[g].r << " " << FiberGroups[g].g << " " << FiberGroups[g].b << "\n"; // %3i  %3i  %3i
%
% 		n_fibers = FiberGroups[g].n_fibers;
%
% 		ar << "NrOfFibers:  " << n_fibers << "\n";
%
% 		for(i=0; i<n_fibers; i++)
% 		{
% 			n_points = FiberGroups[g].fibers[i].n_points;
%
% 			ar << "NrOfPoints:  " << n_points << "\n";
%
% 			for(p=0; p<n_points; p++)
% 			{
% 				ar << FiberGroups[g].fibers[i].pos_x[p] << " " << FiberGroups[g].fibers[i].pos_y[p] << " " << FiberGroups[g].fibers[i].pos_z[p] << "\n";
% 				// fprintf(fp_fbr, "%7.3f %7.3f %7.3f\n", Fibers[i].pos_x[p], Fibers[i].pos_y[p], Fibers[i].pos_z[p]);
% 			}
% 			ar << "\n";
% 		}
% 		ar << "\n\n";
% 	}
%
% 	f.close();


function [wave] = PL2Waves(filename, channel, unit)
% PL2Waves( filename, channel, unit ): read spike timestamps and waveforms from a .pl2 file
%                returns waveform values in millivolts
%
% wave = PL2Waves( filename, channel, unit )
% wave = PL2Waves( filename, 'SPK01', 1 );
% wave = PL2Waves( filename, 2, 3 );
%
% INPUT:
%   filename - if empty string, will use File Open dialog
%   channel - channel name or 1-based channel number
%           1-based channel number is the index of the spike channel in pl2.SpikeChannels cell array
%           shown in the Name column of the output produced by PL2Print(pl2.SpikeChannels)
%           To print the list of spike channels, use these commands:
%
%           pl2 = PL2GetFileIndex(filename);
%           PL2Print(pl2.SpikeChannels);
%
%   unit  - unit number (0 - unsorted, 1-254 sorted units, 255 - invalidated spikes)
%
% OUTPUT:
%   wave.NumPointsWave - number of points in each waveform
%   wave.Ts - array of timestamps (in seconds)
%   wave.Waves - matrix of waveforms, each row is a waveform in millivolts

wave = internalPL2Waves(filename, channel, unit);

end


function [hdr, nameFlag] = read_buffer_offline_header(headerfile)

% function [hdr, nameFlag] = read_buffer_offline_header(headerfile)
%
% This function reads a FCDC buffer header from a binary file or text file
%
% On return, nameFlag has one of the following values:
%   0 = No labels were generated (fMRI etc.)
%   1 = Fake labels were generated
%   2 = Got channel labels from chunk information

% (C) 2010 S. Klanke

type = {
  'char'
  'uint8'
  'uint16'
  'uint32'
  'uint64'
  'int8'
  'int16'
  'int32'
  'int64'
  'single'
  'double'
};

wordsize = {
  1 % 'char'
  1 % 'uint8'
  2 % 'uint16'
  4 % 'uint32'
  8 % 'uint64'
  1 % 'int8'
  2 % 'int16'
  4 % 'int32'
  8 % 'int64'
  4 % 'single'
  8 % 'double'
};

hdr = [];
hdr.nSamples    = 0;
%hdr.nEvents     = 0;
hdr.nSamplesPre = 0;
hdr.nTrials     = 1;
hdr.orig =[];

nameFlag = 0;

txt=[];
finfo=dir([headerfile '.txt']);
if ( isempty(finfo) || finfo.bytes==0 )
  ft_warning(sprintf('Could not open text header file : %s',headerfile));
else
  txt.nSamples=0;
  FA = fopen_or_error([headerfile '.txt'], 'r');
  while ~feof(FA)
    s = fgetl(FA);
    indEq = find(s=='=');
    if numel(indEq)==1
      key = s(1:(indEq-1));
      val = s((indEq+1):end);
      switch key
       case 'fSample'
        txt.Fs = str2num(val);
       case 'nSamples'
        txt.nSamples = str2num(val);
       case 'nEvents'
        %        txt.nEvents = str2num(val);
       case 'nChans'
        txt.nChans = str2num(val);
        txt.label = cell(txt.nChans,1);
       case 'dataType'
        if strcmp(val,'float32')
          txt.orig.data_type = 'single';
        elseif strcmp(val,'float64')
          txt.orig.data_type = 'double';
        else
          txt.orig.data_type = val;
        end
        txt.orig.wordsize = wordsize{strmatch(txt.orig.data_type,type)};
        txt.data_type = strmatch(txt.orig.data_type,type)-1;
        txt.wordsize  = txt.orig.wordsize;
       case 'version'
        txt.orig.version = str2num(val);
       case 'endian'
        if strcmp(val,'big')
          txt.orig.endianness='ieee-be';
        elseif strcmp(val,'little')
          txt.orig.endianness='ieee-le';
        else
          ft_error('Invalid value for key ''endian''.');
        end
      end
      continue;
    end
    indCol = find(s==':');
    if numel(indCol)>=1
      ind = str2num(s(1:(indCol-1)));
      name = s((indCol+1):end);
      if ~isempty(ind) && ind>=1 && ind<=txt.nChans
        txt.label{ind} = name;
        nameFlag = 2;
      else
        ft_error('Invalid channel name definition - broken header file?');
      end
    end
  end

  fclose(FA);
end

bin=[];
finfo=dir(headerfile);
if ( isempty(finfo) || finfo.bytes==0 )
  ft_warning(sprintf('Couldnt open binary header file : %s',headerfile));
  hdr = copyfields(txt, hdr, fieldnames(txt)); % ensure that the predefined stuff still exists
else
  if ( ~isfield(hdr.orig,'endianness') )
    hdr.orig.endianness='native';
  end
  F = fopen_or_error(headerfile,'rb',hdr.orig.endianness);
  hdr.nChans    = double(fread(F,1,'uint32'));
  hdr.nSamples  = double(fread(F,1,'uint32'));
  hdr.nEvents   = double(fread(F,1,'uint32'));
  hdr.Fs        = double(fread(F,1,'single'));
  hdr.data_type = fread(F,1,'uint32');
  hdr.bufsize   = fread(F,1,'uint32');

  if isfield(txt,'nChans') && ~isequal(hdr.nChans,txt.nChans)
    ft_error('Number of channels in binary header does not match ASCII definition');
  end
  if isfield(txt,'nChans') && ~isequal(hdr.nSamples,txt.nSamples)
    ft_warning('Number of samples in binary header does not match ASCII definition');
  end
  if isfield(txt,'nEvents') && ~isequal(hdr.nEvents,txt.nEvents)
    ft_error('Number of events in binary header does not match ASCII definition');
  end
  if isempty(hdr.data_type)
    hdr.data_type = strmatch(txt.orig.data_type,type)-1;
  end
  %if strcmp(hdr.data_type, type{hdr.data_type+1})
  hdr.orig.data_type = type{hdr.data_type+1};
  hdr.orig.wordsize = wordsize{hdr.data_type+1};
  %else
  %  ft_error('Data type in binary header does not match ASCII definition');
  %end

  % TODO: add chunk handling
  while ~feof(F)
    typeAndSize = fread(F, 2, 'uint32');
    if numel(typeAndSize) < 2
      break
    end
    switch typeAndSize(1)
     case 1 % channel names
            % already dealt with, TODO: maybe check consistency with ASCII stuff
      dummy = fread(F, typeAndSize(2), 'uint8=>uint8');
     case 2 % FT_CHUNK_CHANNEL_FLAGS
            % FIXME: ignored for now
      dummy = fread(F, typeAndSize(2), 'uint8=>uint8');
     case 3 % FT_CHUNK_RESOLUTIONS
      if typeAndSize(2) == 8*hdr.nChans
        hdr.resolutions = fread(F, [hdr.nChans, 1], 'double');
      else
        ft_warning('Invalid size of RESOLUTIONS chunk - skipping');
        dummy = fread(F, typeAndSize(2), 'uint8=>uint8');
      end
     case 4 % FT_CHUNK_ASCII_KEYVAL
      dummy = fread(F, typeAndSize(2), 'uint8');
      % FIXME: ignore for now
     case 5 % FT_CHUNK_NIFTI1
      hdr.orig.nifti_1 = fread(F, [1, typeAndSize(2)], 'uint8=>uint8');
      if typeAndSize(2) == 348
        hdr.nifti_1 = decode_nifti1(hdr.orig.nifti_1);
      else
        ft_warning('Invalid size of NIFTI_1 chunk - skipping');
      end
     case 6 % FT_CHUNK_SIEMENS_AP = 6
      hdr.orig.siemensap = fread(F, typeAndSize(2), 'uint8=>uint8');
      if exist('sap2matlab')==3
        hdr.siemensap = sap2matlab(hdr.orig.siemensap);
      end
     case 7 % FT_CHUNK_CTF_RES4 = 7
      hdr.orig.ctf_res4 = fread(F, typeAndSize(2), 'uint8=>uint8');
      tmp_name = tempname;
      FT = fopen_or_error(tmp_name, 'wb');
      fwrite(FT, orig.ctf_res4, 'uint8');
      fclose(FT);
      R4F = read_ctf_res4(tmp_name);
      delete(tmp_name);
      % copy over the labels
      hdr.label = R4F.label;
      % copy over the 'original' header
      hdr.orig = R4F;
    end
  end

  fclose(F);
end

% binary has invalid samples info (or isn't there), get from samples file instead..
if ~isfield(hdr,'nSamples') || hdr.nSamples == 0
  datafile = [headerfile(1:end-6) 'samples'];
  FD = fopen_or_error(datafile, 'rb');
  fseek(FD,0,'eof');
  fileSize = ftell(FD);
  fclose(FD);

  n = fileSize / hdr.orig.wordsize / hdr.nChans;
  hdr.nSamples = floor(n);
  if hdr.nSamples ~= n
    ft_warning('Size of ''samples'' is not a multiple of the size of one sample');
  end
end

if nameFlag < 2 && hdr.nChans < 2000
  nameFlag = 1; % fake labels generated - these are unique
  for i=1:hdr.nChans
    hdr.label{i} = sprintf('%d', i);
  end
end


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

%%
clear; close all; clc;

%% Syntax
% |Nn=vec_normalize(N);|

%% 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 aux_SmrCumT(params, hParentFigure)
    % Plots seismic moment release and number of events versus time
    % function aux_SmrCumT(params, hParentFigure)
    %
    %
    % Incoming variables:
    % params        : all variables
    % hParentFigure : Handle of the parent figure
    %
    % J.Woessner, jowoe@gps.caltech.edu
    % updated: 09.11.05

    % Get the axes handle of the plotwindow
    axes(sv_result('GetAxesHandle', hParentFigure, [], guidata(hParentFigure)));
    set(gca,'NextPlot','add');
    % Select a point in the plot window with the mouse
    [fX, fY] = ginput(1);
    fprintf('X: %g Y: %g\n', fX, fY);
    % Plot a small circle at the chosen place
    plot(fX,fY,'ok');

    % Get closest gridnode for the chosen point on the map
    [fXGridNode fYGridNode,  nNodeGridPoint] = calc_ClosestGridNode(params.mPolygon, fX, fY);
    plot(fXGridNode, fYGridNode, '*r');
    set(gca,'NextPlot','replace');

    % Get the data for the grid node
    mNodeCatalog_ = params.mCatalog(params.caNodeIndices{nNodeGridPoint}, :);

    if (params.nGriddingMode == 1 && params.bMap)
        vDistances_ = sqrt(((mNodeCatalog_(:,1)-fXGridNode)*cosd(fYGridNode)*111).^2 + ((mNodeCatalog_(:,2)-fYGridNode)*111).^2);
        vSel = (vDistances_ <= params.fRadius);
        fCheckDist = max(vDistances_(vSel, :));
        mNodeCatalog_=mNodeCatalog_(vSel,:);
    elseif (params.nGriddingMode == 1 && ~params.bMap)
        [nRow_, nColumn_] = size(mNodeCatalog_);
        vXSecX_ = mNodeCatalog_(:,nColumn_);  % length along x-section
        vXSecY_ = (-1) * mNodeCatalog_(:,7);
        vDistances_ = sqrt(((vXSecX_ - fXGridNode)).^2 + ((vXSecY_ - fYGridNode)).^2);
        vSel = (vDistances_ <= params.fRadius);
        mNodeCatalog_=mNodeCatalog_(vSel,:);
        fCheckDist = max(vDistances_);
    end

    % Sort the catalog according to time
    [s,is] = sort(mNodeCatalog_(:,3));
    mNodeCatalog_ = mNodeCatalog_(is(:,1),:);
    % Calculate moment release
    [fCumMoment, vCumMoment, vMoment] = calc_moment(mNodeCatalog_);

    if exist('new_fig','var') &&  ishandle(new_fig)
        set(0,'Currentfigure',new_fig);
        disp('Figure exists');
    else
        new_fig=figure_w_normalized_uicontrolunits('tag','bnew','Name','Cumulative FMD and b-value fit','Units','normalized','Nextplot','add','Numbertitle','off');
        new_axs=axes('tag','ax_bnew','Nextplot','add','box','on');
    end
    set(gca,'tag','ax_bnew','Nextplot','replace','box','on');
    axs5=findobj('tag','ax_bnew');
    axes(axs5(1));
    vTime = mNodeCatalog_(:,3);
    vCumNumber = (1:length(vTime));
    vCumNumber(length(vTime)) = length(vTime);
    %plot(mNodeCatalog_(:,3),vCumMoment,'Linewidth',2,'Color',[0.7 0.7 0.7])

    [AX,H1,H2] = plotyy(mNodeCatalog_(:,3),vCumNumber,mNodeCatalog_(:,3),vCumMoment,'plot');
    % Figure refinements
    set(gca,'LineWidth',2,'FontSize',12','FontWeight','bold')
    set(AX(2),'YColor','k','XTicklabel',[])
    set(get(AX(1),'Ylabel'),'String','Number of events','FontWeight','bold','FontSize',12,'Color',[0 0 0]);
    set(get(AX(2),'Ylabel'),'String','Cumulative Moment [Nm]','FontWeight','bold','FontSize',12,'Color',[0.8 0 0]);
    set(H1,'Color',[0 0 0],'Linewidth',2);
    set(H2,'Color',[0.8 0 0],'Linewidth',2);

    xlabel('Time [years] ','FontWeight','bold','FontSize',12);
    set(AX(2),'XColor','k','YColor',[0.8 0 0])
    set(AX(1),'YColor','k')
end


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

%%
clear; close all; clc;

%% Syntax
% |[Vs]=triSurfSmoothFourier(F,V,numFreq);|

%% 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 [hx, hy, hz] = ft_plot_ortho(dat, varargin)

% FT_PLOT_ORTHO plots 3 orthographic slices through a 3-D volume and interpolates if needed
%
% Use as
%   ft_plot_ortho(dat, ...)
% or
%   ft_plot_ortho(dat, mask, ...)
% where dat and mask are equal-sized 3-D arrays.
%
% Additional options should be specified in key-value pairs and can be
%   'style'        = string, 'subplot' or 'intersect' (default = 'subplot')
%   'orientation'  = 3x3 matrix specifying the directions orthogonal through the planes which will be plotted
%   'parents'      = (optional) 3-element vector containing the handles of the axes for the subplots (when style = 'subplot')
%   'surfhandle'   = (optional) 3-element vector containing the handles of the surfaces for each of the sublots (when style = 'subplot'). Parents and surfhandle are mutually exclusive
%   'update'       = (optional) 3-element boolean vector with the axes that should be updated (default = [true true true])
%
% The following options are supported and passed on to FT_PLOT_SLICE
%   'clim'                = [min max], lower and upper color limits
%   'transform'           = 4x4 homogeneous transformation matrix specifying the mapping from voxel space to the coordinate system in which the data are plotted
%   'location'            = 1x3 vector specifying the intersection point at which the three slices will be plotted. The coordinates should be expressed in the coordinate system of the data.
%   'datmask'             = 3D-matrix with the same size as the matrix dat, serving as opacitymap if the second input argument to the function contains a matrix, this will be used as the mask
%   'maskstyle'           = string, 'opacity' or 'colormix', defines the rendering
%   'background'          = needed when maskstyle is 'colormix', 3D-matrix with the same size as the data matrix, serving as grayscale image that provides the background
%   'interpmethod'        = string specifying the method for the interpolation, see INTERPN (default = 'nearest')
%   'colormap'            = string, see COLORMAP
%   'unit'                = string, can be 'm', 'cm' or 'mm (default is automatic)
%   'intersectmesh'       = triangulated mesh, see FT_PREPARE_MESH
%   'intersectcolor'      = string, color specification
%   'intersectlinestyle'  = string, line specification
%   'intersectlinewidth'  = number
%
% See also FT_PLOT_SLICE, FT_PLOT_MONTAGE, FT_SOURCEPLOT

% Copyrights (C) 2010, Jan-Mathijs Schoffelen
%
% 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$

% parse first input argument(s). it is either
% (dat, varargin)
% (dat, msk, varargin)
% (dat, [], varargin)
% this is done in ft_plot_slice

sellist = 1:numel(varargin);
if ~isempty(sellist)
  if isempty(varargin{1}) || isnumeric(varargin{1})
    sellist(1) = [];
  end
end

% get the optional input arguments
% other options such as location and transform are passed along to ft_plot_slice
style     = ft_getopt(varargin(sellist), 'style', 'subplot');
ori       = ft_getopt(varargin(sellist), 'orientation', eye(3));

if strcmp(style, 'subplot')
  parents    = ft_getopt(varargin(sellist), 'parents');
  surfhandle = ft_getopt(varargin(sellist), 'surfhandle');
  update     = ft_getopt(varargin(sellist), 'update', [true true true]);
  if ~isempty(surfhandle) && ~isempty(parents)
    ft_error('if specifying handles, you should either specify handles to the axes or to the surface objects, not both');
  end
end

if ~isa(dat, 'double')
  dat = cast(dat, 'double');
end

% determine the orientation key-value pair
keys = varargin(sellist(1:2:end));

sel  = find(strcmp('orientation', keys));
if isempty(sel)
  % add orientation key-value pair if it does not exist
  sel             = numel(keys)+1;
  varargin{2*sel-1} = 'orientation';
  varargin{2*sel} = [];
end

switch style
  case 'subplot'
    if isempty(parents) && isempty(surfhandle)
      Hx = subplot(2,2,1);
      Hy = subplot(2,2,2);
      Hz = subplot(2,2,4);
    elseif ~isempty(parents) && isempty(surfhandle)
      Hx = parents(1);
      Hy = parents(2);
      Hz = parents(3);
    elseif isempty(parents) && ~isempty(surfhandle)
      % determine the parents from the surface handle and use the
      % surfhandle for efficient visualization (overwriting existing data)
      if update(1), Hx = get(surfhandle(1), 'parent'); else Hx = []; end
      if update(2), Hy = get(surfhandle(2), 'parent'); else Hy = []; end
      if update(3), Hz = get(surfhandle(3), 'parent'); else Hz = []; end
    end

    if ~isempty(Hx)
      if ~isempty(surfhandle) && update(1)
        varargin(sellist) = ft_setopt(varargin(sellist), 'surfhandle', surfhandle(1));
      end
      % swap the first 2 dimensions because of meshgrid vs ndgrid issues
      varargin{2*sel} = ori(2,:);
      set(gcf,'currentaxes',Hx);
      hx = ft_plot_slice(dat, varargin{:});
      set(Hx, 'view', [0 0]); %, 'xlim', [0.5 size(dat,1)-0.5], 'zlim', [0.5 size(dat,3)-0.5]);
      if isempty(parents)
        % only change axis behavior if no parents are specified
        axis off
      end
    end

    if ~isempty(Hy)
      if ~isempty(surfhandle) && update(2)
        varargin(sellist) = ft_setopt(varargin(sellist), 'surfhandle', surfhandle(2));
      end
      varargin{2*sel} = ori(1,:);
      set(gcf,'currentaxes',Hy);
      hy = ft_plot_slice(dat, varargin{:});
      set(Hy, 'view', [90 0]); %, 'ylim', [0.5 size(dat,2)-0.5], 'zlim', [0.5 size(dat,3)-0.5]);
      if isempty(parents)
        % only change axis behavior if no parents are specified
        axis off
      end
    end

    if ~isempty(Hz)
      if ~isempty(surfhandle) && update(3)
        varargin(sellist) = ft_setopt(varargin(sellist), 'surfhandle', surfhandle(3));
      end
      varargin{2*sel} = ori(3,:);
      set(gcf,'currentaxes',Hz);
      hz = ft_plot_slice(dat, varargin{:});
      set(Hz, 'view', [0 90]); %, 'xlim', [0.5 size(dat,1)-0.5], 'ylim', [0.5 size(dat,2)-0.5]);
      if isempty(parents)
        % only change axis behavior if no parents are specified
        axis off
      end
    end

  case 'intersect'
    holdflag = ishold;
    if ~holdflag
      hold on
    end

    varargin{2*sel} = ori(1,:);
    hx = ft_plot_slice(dat, varargin{:});

    varargin{2*sel} = ori(2,:);
    hy = ft_plot_slice(dat, varargin{:});

    varargin{2*sel} = ori(3,:);
    hz = ft_plot_slice(dat, varargin{:});
    axis equal; axis tight; axis off;axis vis3d
    view(3);

    if ~holdflag
      hold off
    end

  otherwise
    ft_error('unsupported style %s', style);

end % switch style

% if strcmp(interactive, 'yes')
%   flag = 1;
%   while flag
%
%   end
% end


function write_rgbe_line(buffer_line, fid)
%
%       write_rgbe_line(buffer_line, file)
%
%       This function write an image line using RLE and RGBE encoding
%
%        Input:
%           -buffer_line: a color line of an image
%           -file: the outputting file
%
%     Copyright (C) 2014  Francesco Banterle
%
%     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/>.
%

n = length(buffer_line);

cur_pointer = 1;

while(cur_pointer <= n )
    run_length = 0;
    run_length_old = 0;

    run_start = cur_pointer;

    %we need to find a long run; length>3
    while((run_length<4) && (run_start <= n ))
        run_start = run_start + run_length;
        run_length_old = run_length;

        i_end = min([run_start + 127 - 1, n]);

        run_length = 1;

        %finding a run
        for i=(run_start + 1):i_end
            if(buffer_line(run_start) == buffer_line(i))
                run_length = run_length + 1;
            else
                break
            end
        end
    end

    %do we have a short run <4 before a long one?
    if((run_length_old > 1) && (run_length_old == (run_start - cur_pointer)))
        length_to_write = run_length_old + 128;
        value_to_write = buffer_line(cur_pointer);
        fwrite(fid, length_to_write, 'uint8');
        fwrite(fid, value_to_write, 'uint8');

        cur_pointer = run_start;
    end

    %writing non-runs
    while(cur_pointer < run_start)
        non_run_length = run_start - cur_pointer;

        if(non_run_length > 128)
            non_run_length = 128;
        end

        fwrite(fid, non_run_length, 'uint8');
        fwrite(fid, buffer_line(cur_pointer : (cur_pointer + non_run_length - 1)), 'uint8');

        cur_pointer = cur_pointer + non_run_length;
    end

    %writing the found long run
    if(run_length > 3)
        length_to_write = run_length + 128;
        value_to_write = buffer_line(run_start);
        fwrite(fid, length_to_write, 'uint8');
        fwrite(fid, value_to_write, 'uint8');

        cur_pointer = cur_pointer + run_length;
    end

end

end