function this = save(this)
%saves MrSeries in different file formats
%
%   MrSeries = save(MrSeries)
%
% This is a method of class MrSeries.
%
% IN
%   parameters.save.format
%
% OUT
%
% EXAMPLE
%   save
%
%   See also MrSeries

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

pathSave = this.parameters.save.path;

if ~exist(pathSave, 'dir')
    mkdir(pathSave)
end

% set save path of all objects to the one of the MrSeries
this.set_save_path();

% detect all image files from object and save as nifti-files in save-path
% of MrSeries
handleImageArray = this.get_all_image_objects();
for iImage = 1:numel(handleImageArray);
    handleImageArray{iImage}.save;
end

% strip data from object and save MrSeries itself
MrObject = this.copyobj('exclude', 'data'); % copies object without data
fileObject = fullfile(pathSave, 'MrObject.mat');
save(fileObject, 'MrObject')


function wb=writeSheet(wb,sheetName,sheetPosition,captions,units,raw,isIntegers)
% writeSheet
%   Writes a cell matrix to an Excel sheet into using the Java library Apache POI
%
%   workbook        Workbook object representing the Excel file
%   sheetName       name of the sheet
%   sheetPosition   0-based position of the sheet
%   captions        cell array of captions (opt)
%   units           WRITE INFO
%   raw             cell array with the data in the sheet
%   isIntegers      true if numeric values should be integers (opt, default
%                   true)
%
%   Usage: wb=writeSheet(wb,sheetName,sheetPosition,captions,units,raw)

if nargin<7
    isIntegers=true;
end

%Adds the required classes to the static Java path if not already added
addJavaPaths();

%Import required classes from Apache POI.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

%Set default style object and bold style object
defaultStyle = wb.createCellStyle();
if isIntegers
    idx = wb.getCreationHelper().createDataFormat().getFormat('0');
else
    idx = wb.getCreationHelper().createDataFormat().getFormat('##0.00');
end
defaultStyle.setDataFormat(idx);

boldFont=wb.createFont();
boldFont.setBoldweight(boldFont.BOLDWEIGHT_BOLD);
boldStyle=defaultStyle.clone();
boldStyle.setFont(boldFont);

s=wb.createSheet();
wb.setSheetName(sheetPosition, sheetName);

%Create the header row and units
counter=0;
if ~isempty(captions)
    r=s.createRow(counter);
    for i=0:numel(captions)-1
        c=r.createCell(i);
        c.setCellValue(captions{i+1});
        c.setCellStyle(boldStyle);
    end
    counter=counter+1;
end
if ~isempty(units)
    r=s.createRow(counter);
    for i=0:numel(units)-1
        c=r.createCell(i);
        content=units{i+1};
        if iscell(content) && numel(content)==2
            c.setCellValue(content{1});

            %This means that the cell should have a list of allowed values
            dvHelper=XSSFDataValidationHelper(s);

            cellRange=CellRangeAddressList(1,1,i,i); %Units are on the second line
            dvConstraint=dvHelper.createExplicitListConstraint(toValid(content{2}));
            validation=dvHelper.createValidation(dvConstraint, cellRange);
            validation.setShowErrorBox(true);
            s.addValidationData(validation);
        else
            c.setCellValue(content{1});
        end
        c.setCellStyle(boldStyle);
    end
    counter=counter+1;
end

%Loop through and fill in the values
for i=0:size(raw,1)-1
    r=s.createRow(i+counter);

    for j=0:size(raw,2)-1
        if ~isempty(raw{i+1,j+1})
            c=r.createCell(j);
            content=raw{i+1,j+1};
            if iscell(content) && numel(content)==2
                c.setCellValue(content{1});

                %This means that the cell should have a list of allowed
                %values
                dvHelper=XSSFDataValidationHelper(s);
                cellRange=CellRangeAddressList(i+1,i+1,j,j);
                dvConstraint=dvHelper.createExplicitListConstraint(toValid(content{2}));
                validation=dvHelper.createValidation(dvConstraint, cellRange);
                validation.setShowErrorBox(true);
                s.addValidationData(validation);
            else
                c.setCellValue(content);
            end
            c.setCellStyle(defaultStyle);
        end
    end
end

%Pre-determine column widths for each sheet
if strcmp(sheetName,'RXNS')
    widths=[786;2358;7860;15719;3406;7860;3406;3406;2358;3406;7860;7860;3668;7860;7860;4192];
elseif strcmp(sheetName,'METS')
    widths=[786;7860;7860;3668;7860;7860;7860;3406;3668;1834];
elseif strcmp(sheetName,'COMPS')
    widths=[786;3144;7860;3144;7860];
elseif strcmp(sheetName,'GENES')
    widths=[786;3144;7860;3144;3406];
elseif strcmp(sheetName,'MODEL')
    widths=[786;3144;7860;3668;3668;5240;5240;7860;7860;2620;7860];
end;

%Resize columns
for i=0:size(raw,2)-1
    s.setColumnWidth(i,widths(i+1));
end

%Add freeze panes
if counter>0
    s.createFreezePane(0,counter,0,counter);
end
end

function I=toValid(J)
I=cell(numel(J),1);
for i=1:numel(J)
    if ischar(J{i})
        I(i)=J(i);
    else
        if islogical(J{i})
            if J{i}==true
                I{i}='TRUE';
            else
                I{i}='FALSE';
            end
        else
            %Other, most likely numbers
            I{i}=num2str(J{i});
        end
    end
end
end


%kiopaque 'Opaquens image '
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros iopaque.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% OutputFile: o 'Output', required: 'Resulting output data object'
% Double: scale 'Scaling Factor', default: 1: 'float'
%
% Example: o = kiopaque(i, {'i','';'o','';'scale',1})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% iopaque - no short description specified
%
%  DESCRIPTION
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kiopaque(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kiopaque(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'o', '__output';'scale', 1};
maxval={0,0,2};
minval={0,0,2};
istoggle=[0,0,0];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile','Double'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'iopaque"  '],Inputs,narglist);


function d=subdir(rootpath)
% SUBDIR    Returns the paths of all subdirectories of the rootpath
%   d=subdir(rootpath)
%
%   Input:
%       rootpath,   directory to be searched. All subdirectories in the
%                   rootpath are returned
%
%   Output:
%       d,          cell array containing all subdirectories of rootpath
%
%   author:   Tim Myers [myers@metronaviation.com]
%   version:  1.0
%   date:     20-May-2005
%
%   Requires dirdir from P. Macey on Matlab Central File Exchange:
%   http://www.mathworks.com/matlabcentral/files/1570/dirdir.m
%

d=[];
dnew=dirdir(rootpath);

%append subdirectories of root path
for i=1:numel(dnew)
    d=[d; {[rootpath '\' dnew(i).name]}];
end

%initialize search array. 1=directory has been searched.
s=zeros(length(d),1);
while 1
    %find index of subdirectories yet to be searched
    index=find(s==0);
    if isempty(index)
        %all subdirectories have been searched
        return
    else
        %path of subdirectory to be searched
        dtemp=char(d(index(1)));
        %new subdirectories to add to the list
        dnew=dirdir(dtemp);
        %current directory has been searched
        s(index(1))=1;
    end
    %append new directories
    for i=1:numel(dnew)
        d=[d; {[dtemp '\' dnew(i).name]}];
    end
    s=[s; zeros(numel(dnew),1)];
end


function unannotatedRxns = getUnannotatedReactionsFromPubSeedSpreadsheets(infoFilePath,inputDataFolder,spreadsheetFolder)
% Part of the DEMETER pipeline. Prepares input file for the refinement
% based on comparative genomics analyses.
% Gets all the reactions that were not found in the respective organism
% through comparative genomics to remove them from the draft
% reconstructions.
%
% USAGE:
%   unannotatedRxns = getUnannotatedReactionsFromPubSeedSpreadsheets(infoFilePath,inputDataFolder,spreadsheetFolder)
%
% INPUTS
% infoFilePath          File with information on reconstructions to refine
% inputDataFolder       Folder to save propagated data to (default: folder
%                       in current path called "InputData")
% spreadsheetFolder     Folder with comparative genomics data retrieved
%                       from PubSEED in spreadsheet format if available.
%                       For an example of the required format, see
%                       cobratoolbox/papers/2021_demeter/exampleSpreadsheets.
%
% .. Authors:
%       - Almut Heinken, 06/2020

% get PubSEED IDs of new organisms to reconstruct
infoFile = readInputTableForPipeline(infoFilePath);

% load reactions
reactions = readInputTableForPipeline('InReactions.txt');

% get all spreadsheets
dInfo = dir(spreadsheetFolder);
fileList={dInfo.name};
fileList=fileList';
fileList(find(strcmp(fileList(:,1),'.')),:)=[];
fileList(find(strcmp(fileList(:,1),'..')),:)=[];

unannotatedRxns={};
cnt=1;

for i=1:length(fileList)
    i
    % read spreadsheets
    spreadsheet = readInputTableForPipeline([spreadsheetFolder filesep fileList{i}]);

    for j=2:size(spreadsheet,1)
        % replace PubSeed with AGORA Model IDs
        % some entries in the comparative genomics spreadsheet have no
        % reconstruction -> skip
        if ~isempty(find(strcmp(infoFile(:,2),spreadsheet{j,1})))
            spreadsheet{j,1}=infoFile{find(strcmp(infoFile(:,2),spreadsheet{j,1})),1};
            for k=2:size(spreadsheet,2)
                % get the ones that are empty so genoem annotation was not
                % found
                % no drug genes with many associated reactions
                if isempty(spreadsheet{j,k}) && ~any(strcmp(spreadsheet{1,k},{'eUidA','cUidA','UidB','UidP','UidABC'}))
                    getRxns=reactions(find(strcmp(reactions(:,1),spreadsheet{1,k})),2);
                    for r=1:length(getRxns)
                        unannotatedRxns{cnt,1}=spreadsheet{j,1};
                        unannotatedRxns{cnt,2}=getRxns{r};
                        cnt=cnt+1;
                    end
                end
            end
        end
    end
end

% read comparative genomics data
genomeAnnotation = readInputTableForPipeline([inputDataFolder filesep 'gapfilledGenomeAnnotation.txt']);

% read translated SEED reactions
translateRxns = readInputTableForPipeline('ReactionTranslationTable.txt');

% remove duplicate reactions for organisms, gap-filled reactions present in
% comparative genomics spreadsheets
delArray=[];
cnt=1;
orgs=unique(unannotatedRxns(:,1));
for i=1:length(orgs)
    i
    getRxns=unannotatedRxns(find(strcmp(unannotatedRxns(:,1),orgs{i})),2);
    getRxnInds=find(strcmp(unannotatedRxns(:,1),orgs{i}));
    [uniqueRxns, ~, J]=unique(getRxns);
    cntRxns = histc(J, 1:numel(uniqueRxns));
    duplRxns=uniqueRxns(cntRxns>1);
    if ~isempty(duplRxns)
        for j=1:length(duplRxns)
            findInds=getRxnInds(find(strcmp(getRxns(:,1),duplRxns{j})),1);
            for k=2:length(findInds)
                delArray(cnt,1)=findInds(k);
                cnt=cnt+1;
            end
        end
    end
    annRxns=genomeAnnotation(find(strcmp(orgs{i},genomeAnnotation(:,1))),2);
    [~,keptRxnInd]=intersect(getRxns,annRxns);
    for j=1:length(keptRxnInd)
        delArray(cnt,1)=getRxnInds(keptRxnInd(j));
        cnt=cnt+1;
    end

    % remove reactions not present in KBase translation table
    [~,notTranslated]=setdiff(getRxns,translateRxns(:,2));
    for j=1:length(notTranslated)
        delArray(cnt,1)=getRxnInds(notTranslated(j));
        cnt=cnt+1;
    end
end
unannotatedRxns(delArray,:)=[];

end


function results = eq(A, B)
   % when using wildcards, use ismember
   switch class(B)
      case 'scnlobject'
         results = [A.tag] == [B.tag];
      case 'ChannelTag'
         results = [A.tag] == [B];
      otherwise
         error('scnlobject:eq:UnrecognizedComparison',...
            'Don''t know how to compare scnlobject with %s\n',class(B));
   end
end


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

%%
clear; close all; clc;

%% Syntax
% |varargout=patchEdges(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 r = checkTimingReport(varargin)
% Find timing report
if isempty(varargin)
    hdl_prj = 'hdl_prj';
else
    hdl_prj = varargin{1};
end
path = [hdl_prj,'/vivado_ip_prj/vivado_prj.runs/impl_1'];
filename = 'system_wrapper_timing_summary_routed.rpt';
full = [path,'/',filename];

if ~isfile(full)
    full1 = full;
    % Try ZYNQMP naming
    path = [hdl_prj,'/vivado_ip_prj/vivado_prj.runs/impl_1'];
    filename = 'system_top_timing_summary_routed.rpt';
    full = [path,'/',filename];
    if ~isfile(full)
        error(['No timing report found under: ',full,' or ',full1]);
    end
end

fid = fopen(full);
str = textscan(fid, '%s');
str = strcat(str{1}{:});
%%
if ~contains(str,'(VIOLATED)')
    disp('Passed Timing');
    r = true;
else
    disp('Failed Timing');
    r = false;
end


function varargout = lvd_editNonSeqEventGUI(varargin)
% LVD_EDITNONSEQEVENTGUI MATLAB code for lvd_editNonSeqEventGUI.fig
%      LVD_EDITNONSEQEVENTGUI, by itself, creates a new LVD_EDITNONSEQEVENTGUI or raises the existing
%      singleton*.
%
%      H = LVD_EDITNONSEQEVENTGUI returns the handle to a new LVD_EDITNONSEQEVENTGUI or the handle to
%      the existing singleton*.
%
%      LVD_EDITNONSEQEVENTGUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in LVD_EDITNONSEQEVENTGUI.M with the given input arguments.
%
%      LVD_EDITNONSEQEVENTGUI('Property','Value',...) creates a new LVD_EDITNONSEQEVENTGUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before lvd_editNonSeqEventGUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to lvd_editNonSeqEventGUI_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help lvd_editNonSeqEventGUI

% Last Modified by GUIDE v2.5 05-Dec-2018 14:25:39

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @lvd_editNonSeqEventGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @lvd_editNonSeqEventGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before lvd_editNonSeqEventGUI is made visible.
function lvd_editNonSeqEventGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to lvd_editNonSeqEventGUI (see VARARGIN)

    % Choose default command line output for lvd_editNonSeqEventGUI
    handles.output = hObject;

    nonSeqEvt = varargin{1};
    setappdata(hObject, 'nonSeqEvt', nonSeqEvt);

    lvdData = varargin{2};
    setappdata(hObject, 'lvdData', lvdData);

    populateGUI(nonSeqEvt, lvdData, handles);

    % Update handles structure
    guidata(hObject, handles);

    % UIWAIT makes lvd_editNonSeqEventGUI wait for user response (see UIRESUME)
    uiwait(handles.lvd_editNonSeqEventGUI);

function populateGUI(nonSeqEvt, lvdData, handles)
    handles.eventNameLabel.String = nonSeqEvt.evt.name;

    listBoxStr = vertcat(' ',lvdData.script.getListboxStr());
    handles.lwrBndEvtCombo.String = listBoxStr;

    if(not(isempty(nonSeqEvt.lwrBndEvt)))
        handles.lwrBndEvtCombo.Value = lvdData.script.getNumOfEvent(nonSeqEvt.lwrBndEvt) + 1;
    else
        handles.lwrBndEvtCombo.Value = 1;
    end

    listBoxStr = vertcat(' ',lvdData.script.getListboxStr());
    handles.uprBndEvtCombo.String = listBoxStr;

    if(not(isempty(nonSeqEvt.uprBndEvt)))
        handles.uprBndEvtCombo.Value = lvdData.script.getNumOfEvent(nonSeqEvt.uprBndEvt) + 1;
    else
        handles.uprBndEvtCombo.Value = 1;
    end

    handles.maxExecsText.String = num2str(nonSeqEvt.maxNumExecs);

% --- Outputs from this function are returned to the command line.
function varargout = lvd_editNonSeqEventGUI_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
    if(isempty(handles))
        varargout{1} = [];
    else
        lvdData = getappdata(handles.lvd_editNonSeqEventGUI, 'lvdData');
        nonSeqEvt = getappdata(handles.lvd_editNonSeqEventGUI, 'nonSeqEvt');

        lwrBndValue = handles.lwrBndEvtCombo.Value;
        if(lwrBndValue == 1)
            lwrBndEvt = LaunchVehicleEvent.empty(1,0);
        else
            lwrBndEvtNum = lwrBndValue - 1;
            lwrBndEvt = lvdData.script.getEventForInd(lwrBndEvtNum);
        end
        nonSeqEvt.lwrBndEvt = lwrBndEvt;

        uprBndValue = handles.uprBndEvtCombo.Value;
        if(uprBndValue == 1)
            uprBndEvt = LaunchVehicleEvent.empty(1,0);
        else
            uprBndEvtNum = uprBndValue - 1;
            uprBndEvt = lvdData.script.getEventForInd(uprBndEvtNum);
        end
        nonSeqEvt.uprBndEvt = uprBndEvt;

        nonSeqEvt.maxNumExecs = str2double(handles.maxExecsText.String);
        nonSeqEvt.numExecsRemaining = str2double(handles.maxExecsText.String);

        close(handles.lvd_editNonSeqEventGUI);
    end

% --- Executes on button press in saveAndCloseButton.
function saveAndCloseButton_Callback(hObject, eventdata, handles)
% hObject    handle to saveAndCloseButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    errMsg = validateInputs(handles);

    if(isempty(errMsg))
       uiresume(handles.lvd_editNonSeqEventGUI);
    else
        msgbox(errMsg,'Errors were found while editing the non-sequential event.','error');
    end

function errMsg = validateInputs(handles)
    errMsg = {};

    value = str2double(get(handles.maxExecsText,'String'));
    enteredStr = get(handles.maxExecsText,'String');
    numberName = 'Max. Number of Executions';
    lb = 1;
    ub = Inf;
    isInt = true;
    errMsg = validateNumber(value, numberName, lb, ub, isInt, errMsg, enteredStr);

% --- Executes on selection change in lwrBndEvtCombo.
function lwrBndEvtCombo_Callback(hObject, eventdata, handles)
% hObject    handle to lwrBndEvtCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns lwrBndEvtCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from lwrBndEvtCombo

% --- Executes during object creation, after setting all properties.
function lwrBndEvtCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to lwrBndEvtCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in uprBndEvtCombo.
function uprBndEvtCombo_Callback(hObject, eventdata, handles)
% hObject    handle to uprBndEvtCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns uprBndEvtCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from uprBndEvtCombo

% --- Executes during object creation, after setting all properties.
function uprBndEvtCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to uprBndEvtCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function maxExecsText_Callback(hObject, eventdata, handles)
% hObject    handle to maxExecsText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of maxExecsText as text
%        str2double(get(hObject,'String')) returns contents of maxExecsText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function maxExecsText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to maxExecsText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in editEventButton.
function editEventButton_Callback(hObject, eventdata, handles)
% hObject    handle to editEventButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    nonSeqEvt = getappdata(handles.lvd_editNonSeqEventGUI, 'nonSeqEvt');
    event = nonSeqEvt.evt;

%     lvd_editEventGUI(event, true);
    output = AppDesignerGUIOutput({false});
    lvd_editEventGUI_App(event, true, output);

    handles.eventNameLabel.String = nonSeqEvt.evt.name;


classdef MimMain < CoreBaseClass
    % MimMain. Imports and provides access to data from the TD MIM Toolkit
    %
    %     MimMain provides access to data from the TD MIM Toolkit, and allows
    %     you to import new data. Data is accessed through one or more MimDataset
    %     objects. Your code should create a single MimMain object, and then ask
    %     it to create a MimDataset object for each dataset you wish to access.
    %
    %     MimMain is essentially a class factory for MimDatasets, but shares the
    %     MimReportingInterface (error/progress reporting) objects between all
    %     datasets, so you have a single error/progress reporting pipeline for
    %     your use of the TD MIM Toolkit.
    %
    %     To import a new dataset, construct a PTKImageInfo object with the file
    %     path and file name set to the image file. For DICOM files it is only
    %     necessary to specify the path since all image files in that directory
    %     will be imported. Then call CreateDatasetFromInfo. MimMain will import
    %     the data (if it has not already been imported) and return a new
    %     MimDataset object for that dataset.
    %
    %     To access an existing dataset you can use CreateDatasetFromInfo as
    %     above, or you can use CreateDatasetFromUid to retrieve a dataset which
    %     has peviously been imported, using the UID that was associated with
    %     that dataset.
    %
    %     Example
    %     -------
    %     Replace <image path> and <filenames> with the path and filenames
    %     to your image data.
    %
    %         image_info = PTKImageInfo( <image path>, <filenames>, [], [], [], []);
    %         mim = MimMain();
    %         dataset = mim.CreateDatasetFromInfo(image_info);
    %
    %     You can then obtain results from this dataset, e.g.
    %
    %         results = dataset.GetResult('PluginName');
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (SetAccess = private)
        FrameworkAppDef
        FrameworkSingleton
        Reporting          % Object for error and progress reporting
        ReportingWithCache % For the dataset, uses the same object, but warnings and messages are cached so multiple warnings can be displayed together
    end

    methods

        function obj = MimMain(framework_app_def, reporting)
            % Creates a new main MIM object using the configuration
            % specified by the supplied framework_app_def object
            obj.FrameworkAppDef = framework_app_def;
            obj.Reporting = reporting;
            obj.ReportingWithCache = MimReportingWithCache(obj.Reporting);
            obj.FrameworkSingleton = MimFrameworkSingleton.GetFrameworkSingleton(framework_app_def, obj.Reporting);

            bin_directory = framework_app_def.GetBinDirectory();
            CoreDiskUtilities.CreateDirectoryAndAddPathIfNotExisting(bin_directory);
            files_to_compile = framework_app_def.GetFilesToCompile(reporting);
            obj.FrameworkSingleton.CompileMexFileIfRequired(files_to_compile, bin_directory, obj.Reporting);
        end

        function Recompile(obj)
            % Forces recompilation of mex files

            bin_directory = obj.FrameworkAppDef.GetBinDirectory();
            files_to_compile = obj.FrameworkAppDef.GetFilesToCompile(obj.Reporting);
            obj.FrameworkSingleton.Recompile(files_to_compile, bin_directory, obj.Reporting);
        end

        function RebuildDatabase(obj)
            % Forces rebuilding of the image database

            obj.FrameworkSingleton.RebuildDatabase(obj.Reporting);
        end

        function DeleteCacheForAllDatasets(obj)
            % Delete automatic plugin results cache files on disk and in memory. Does not remove manually genereted files (edits, markers etc.)

            % Remove memory and disk results cache files for known datasets
            obj.FrameworkSingleton.GetDatasetApiCache().RemoveAllCachedFiles(obj.Reporting);

            % Do a hard clearout of the results cache to get rid of
            % anything else that's left
            obj.FrameworkAppDef.GetFrameworkDirectories.DeleteCacheForAllDatasets();
        end

        function ReloadPlugins(obj)
            % Forces a reload of plugin classes to pick up changes in properties etc.

            obj.FrameworkSingleton.GetPluginInfoMemoryCache.Clear();
        end

        function dataset_uids = FindDataset(obj, dataset_uid_prefix)
            % Searches for the dataset with this uid. If a dataset exactly
            % matches, this will be returned.
            % Otherwise, the specified string prefix will be matched
            % against all dataset uids in the cache, and if there is a
            % single match then this will be returned.
            %
            % Note: it is possible for datasets to exist in
            % the cache but not in the database; this can be fixed by
            % rebuilding the database

            if iscell(dataset_uid_prefix)
                dataset_uid_prefix = dataset_uid_prefix{1};
            end
            dataset_exists = (7 == exist(fullfile(obj.FrameworkAppDef.GetFrameworkDirectories.GetFrameworkDatasetCacheDirectory, dataset_uid_prefix), 'dir')) || (7 == exist(fullfile(obj.FrameworkAppDef.GetFrameworkDirectories.GetCacheDirectory, dataset_uid_prefix), 'dir'));

            if dataset_exists
                dataset_uids = {dataset_uid_prefix};
            else
                all_uids = obj.FrameworkAppDef.GetFrameworkDirectories().GetUidsOfAllDatasetsInCache();
                matches = strncmp(all_uids, dataset_uid_prefix, length(dataset_uid_prefix));
                dataset_uids = all_uids(matches);
            end
        end

        function dataset = Load(obj, filename)
            % Helper method to import the data from the specified file path and create a MimDataset for the first series found

            [uids, ~] = obj.ImportData(filename);
            if isempty(uids)
                dataset = [];
            else
                dataset = obj.CreateDatasetFromUid(uids{1});
            end
        end

        function dataset = CreateDatasetFromUid(obj, dataset_uid_prefix)
            % Creates a MimDataset object for a dataset specified by the uid. The
            % dataset must already be imported.

            dataset_uid = obj.FindDataset(dataset_uid_prefix);
            if isempty(dataset_uid)
                obj.Reporting.Error(MimErrors.UidNotFoundErrorId, 'Cannot find the dataset for this UID. Try importing the image using CreateDatasetFromInfo.');
            elseif numel(dataset_uid) > 1
                obj.Reporting.Error(MimErrors.UidNotFoundErrorId, 'More than one dataset for this UID prefix. Try specifying the complete uid.');
            else
                dataset_uid = dataset_uid{1};
            end

            dataset_disk_cache = obj.FrameworkSingleton.GetDatasetApiCache.GetDatasetDiskCache(dataset_uid, obj.Reporting);

            image_info = dataset_disk_cache.LoadData(obj.FrameworkAppDef.GetFrameworkConfig.ImageInfoCacheName, obj.Reporting);
            if isempty(image_info)
                obj.Reporting.Error(MimErrors.UidNotFoundErrorId, 'Cannot find the dataset for this UID. Try importing the image using CreateDatasetFromInfo.');
            end

            dataset = MimDataset(image_info, dataset_disk_cache, obj.FrameworkSingleton.GetLinkedDatasetChooserMemoryCache, obj.FrameworkSingleton.GetClassFactory, obj.ReportingWithCache);

            obj.AutoLinkDatasets(dataset);

            obj.RunCustomPostLoadFunction(dataset_uid, dataset);
        end

        function dataset = CreateDatasetFromInfo(obj, new_image_info)
            % Creates a MimDataset object for a dataset specified by the path,
            % filenames and/or uid specified in a PTKImageInfo object. The dataset is
            % imported from the specified path if it does not already exist.
            [image_info, dataset_disk_cache] = obj.ImportDataFromInfo(new_image_info, obj.Reporting);

            obj.FrameworkSingleton.AddToDatabase(image_info.ImageUid, obj.Reporting)

            dataset = MimDataset(image_info, dataset_disk_cache, obj.FrameworkSingleton.GetLinkedDatasetChooserMemoryCache, obj.FrameworkSingleton.GetClassFactory, obj.ReportingWithCache);

            obj.AutoLinkDatasets(dataset);

            obj.RunCustomPostLoadFunction(dataset.GetImageInfo.ImageUid, dataset);
        end

        function [uids, patient_ids] = ImportDataRecursive(obj, filename)
            % Identical to ImportData()
            [uids, patient_ids] = obj.ImportData(filename);
        end

        function [uids, patient_ids] = ImportData(obj, filename)
            % Imports data into the TD MIM Toolkit so that it can be accessed
            % from the CreateDatasetFromUid() method. The input argument is a string
            % containing the path to the data file to import. If the path points to
            % a single (non-DICOM) file, then only the file will be imported. If the
            % path points to a directory, or to a DICOM file, then all image files in
            % the directory and its subdirectories will be imported.

            % Only support a string input
            if ~ischar(filename)
                obj.Reporting.Error('MimMain:FileNotAsExpected', 'The file or directory passed to MimMain.ImportData() is not of the expected type.');
            end

            % Adds the files to the image database, which groups them into
            % series
            [uids, patient_ids] = obj.FrameworkSingleton.ImportData(filename, obj.ReportingWithCache);

            % Add the necessary files to the cache
            obj.ImportSeries(uids);

            % Save changes to the database
            obj.FrameworkSingleton.SaveImageDatabase(obj.Reporting);

            % Tell the image database to fire a database changed event. We do this here
            % rather than during the import to prevent multiple events being fired
            obj.FrameworkSingleton.ReportChangesToDatabase();
        end

        function RunCustomPostLoadFunction(obj, dataset_uid, dataset)
            % This method is called to run a user-defined function for linking
            % datasets

            obj.FrameworkAppDef.NewDatasetLoaded(dataset_uid, dataset, obj.Reporting);
        end

        function image_database = GetImageDatabase(obj)
            % Returns the Framework's image database
            image_database = obj.FrameworkSingleton.GetImageDatabase;
        end

        function directories = GetDirectories(obj)
            % Returns a MimDirectories object which can be used to query and create framework directories
            directories = obj.FrameworkAppDef.GetFrameworkDirectories;
        end

        function DeleteDatasets(obj, series_uids)
            % Deletes the datasets specified by a uid or a cell array of uids
            if isempty(series_uids)
                return;
            end

            if ~iscell(series_uids)
                series_uids = {series_uids};
            end

            for series_uid_cell = series_uids
                series_uid = series_uid_cell{1};

                dataset_to_delete = [];
                try
                    dataset_to_delete = obj.CreateDatasetFromUid(series_uid);
                catch exc
                    %
                    if MimErrors.IsErrorUidNotFound(exc.identifier)
                        obj.Reporting.ShowMessage('MimMain:UidNotFound', ['Failed to delete dataset because its UID could not be found']);
                    else
                        rethrow exc
                    end
                end

                if ~isempty(dataset_to_delete)
                    dataset_to_delete.DeleteCacheForThisDataset();
                    delete(dataset_to_delete);
                end
            end

            obj.FrameworkSingleton.GetDatasetApiCache.DeleteSeries(series_uids, obj.Reporting);
            obj.FrameworkSingleton.GetLinkedDatasetChooserMemoryCache.DeleteSeries(series_uids, obj.Reporting);
            obj.GetImageDatabase.DeleteSeries(series_uids, obj.Reporting);
        end

        function output = RunScript(obj, script_name, varargin)
            if nargin < 3
                parameters = [];
            end
            try
                script_class = feval(script_name);
                output = script_class.RunScript(obj, obj.Reporting, varargin{:});
            catch ex
                obj.Reporting.ErrorFromException('MimMain:ScriptFailure', ['The script ' script_name ' failed with the following error: ' ex.message], ex);
                output = [];
            end
        end

        function AutoLinkDatasets(obj, primary_dataset)
            linked_recorder = obj.FrameworkSingleton.GetLinkedDatasetRecorder();
            link_map = linked_recorder.LinkMap;
            primary_uid = primary_dataset.GetPrimaryDatasetUid();
            if link_map.isKey(primary_uid)
               link_record = link_map(primary_uid);
               link_map = link_record.LinkMap;
               for uid = link_map.keys
                   name = link_map(uid{1});
                   dataset_to_link = obj.CreateDatasetFromUid(uid{1});
                   primary_dataset.LinkDataset(name, dataset_to_link)
               end
            end
        end
    end

    methods (Access = private)

        function ImportSeries(obj, uids)
            if ~isempty(uids)
                for series_uid = uids
                    series_info = obj.FrameworkSingleton.GetSeriesInfo(series_uid{1});
                    image_info = series_info.GetImageInfo;
                    obj.ImportDataFromInfo(image_info, obj.Reporting);
                end
            end
        end

        function [image_info, dataset_disk_cache] = ImportDataFromInfo(obj, new_image_info, reporting)
            % Imports data into the TD MIM Toolkit so that it can be accessed
            % from the CreateDatasetFromUid() method. The input argument is a
            % PTKImageInfo object containing the path, filenames and file type of
            % the data to import. If you do not know the file type, use the
            % ImportData() method instead.

            if isempty(new_image_info.ImageUid)
                [series_uid, study_uid, modality] = MimMain.GetImageUID(new_image_info, reporting);
                new_image_info.ImageUid = series_uid;
                new_image_info.StudyUid = study_uid;
                new_image_info.Modality = modality;
            end

            dataset_disk_cache = obj.FrameworkSingleton.GetDatasetApiCache.GetDatasetDiskCache(new_image_info.ImageUid, reporting);
            image_info = dataset_disk_cache.LoadData(obj.FrameworkAppDef.GetFrameworkConfig.ImageInfoCacheName, reporting);
            if isempty(image_info)
                image_info = PTKImageInfo;
            end

            [image_info, anything_changed] = image_info.CopyNonEmptyFields(image_info, new_image_info);
            if (anything_changed)
                dataset_disk_cache.SaveData(obj.FrameworkAppDef.GetFrameworkConfig.ImageInfoCacheName, image_info, reporting);
            end
        end
    end

    methods (Static, Access = private)

        function [image_uid, study_uid, modality] = GetImageUID(image_info, reporting)
            % We need a unique identifier for each dataset. For DICOM files we use
            % the series instance UID. For other files we hash the full file path.

            if ~isempty(image_info.ImageFilenames) && isa(image_info.ImageFilenames{1}, 'CoreFilename')
                first_path = image_info.ImageFilenames{1}.Path;
                first_filename = image_info.ImageFilenames{1}.Name;
            else
                filenames = CoreDiskUtilities.GetDirectoryFileList(image_info.ImagePath, '*');
                first_filename = filenames{1};
                first_path = image_info.ImagePath;
            end

            single_image_info = MimGetSingleImageInfo(first_path, first_filename, image_info.ImageFileFormat, DMDicomDictionary.GroupingDictionary, reporting);
            image_uid = single_image_info.ImageUid;
            study_uid = single_image_info.StudyUid;
            modality = single_image_info.Modality;
        end
    end
end


%YUV Class to read YUV4MPEG file
%
% A concrete subclass of ImageSource that returns images from a YUV4MPEG format
% uncompressed video file.
%
% Methods::
% grab    Aquire and return the next image
% size    Size of image
% close   Close the image source
% char    Convert the object parameters to human readable string
%
% Properties::
% curFrame        The index of the frame just read
%
% See also ImageSource, Video.
%
%
% SEE ALSO: Video

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB.  If not, see <http://www.gnu.org/licenses/>.

classdef YUV < ImageSource

    properties

        rate            % frame rate at which movie was capture

        skippedFrames

        curFrame
        skip

        fp
        hdr

    end

    methods

        function yuv = YUV(filename, varargin)
        %YUV.YUV YUV4MPEG sequence constructor
        %
        % Y = YUV(FILE, OPTIONS) is a YUV4MPEG object that returns frames
        % from the yuv4mpeg format file FILE.  This file contains uncompressed
        % color images in 4:2:0 format, with a full resolution luminance plane
        % followed by U and V planes at half resolution both directions.
        %
        % Options::
        % 'uint8'     Return image with uint8 pixels (default)
        % 'float'     Return image with float pixels
        % 'double'    Return image with double precision pixels
        % 'grey'      Return greyscale image
        % 'gamma',G   Apply gamma correction with gamma=G
        % 'scale',S   Subsample the image by S in both directions
        % 'skip',S    Read every S'th frame from the movie

            % invoke the superclass constructor and process common arguments
            yuv = yuv@ImageSource(varargin{:});

            yuvm.curFrame = 1;
            yuv.skip = 1;

            yuv.fp = fopen(filename, 'r');

            hdr = fgets(yuv.fp);
            yuv.hdr = hdr;
            while length(hdr) > 1,
                [s, hdr] = strtok(hdr);
                switch s(1),
                case {'Y'}
                    if strcmp(s, 'YUV4MPEG2') == 0,
                        fclose(yuv.fp);
                        error('not a YUV4MPEG stream');
                    end
                case {'W'}
                    yuv.width = str2num(s(2:end));
                case {'H'}
                    yuv.height = str2num(s(2:end));
                otherwise
                    fprintf('found <%s>\n', s);
                end
            end
            yuv.curFrame = 0;
        end

        % destructor
        function delete(m)
            close(yuv.fp);
        end

        function close(m)
        %Movie.close Close the image source
        %
        % M.close() closes the connection to the movie.

            delete(m.movie);
        end

        function sz = size(yuv)
            sz = [yuv.width yuv.height];
        end

        function [o1,o2,o3] = grab(yuv, varargin)
        %Movie.grab Acquire next frame from movie
        %
        % IM = Y.grab(OPTIONS) is the next frame from the file.
        %
        % [Y,U,V] = Y.grab(OPTIONS) is the next frame from the file
        %
        % Options::
        % 'skip',S    Skip frames, and return current+S frame (default 1)
        % 'rgb'       Return as an RGB image, Y image is downsized by two (default).
        % 'rgb2'      Return as an RGB image, U and V images are upsized by two.
        % 'yuv'       Return Y, U and V images.
        %
        % Notes::
        % - If no output argument given the image is displayed using IDISP.
        % - For the 'yuv' option three output arguments must be given.

            opt.skip = yuv.skip;
            opt.mode = {'rgb', 'rgb2', 'yuv'};

            opt = tb_optparse(opt, varargin);

            % read next frame from the file
            [Y,U,V] = yuv.yuvread(opt.skip);
            if isempty(Y)
                out = [];
                return;
            end

            yuv.curFrame = yuv.curFrame + opt.skip;

            % apply options specified at construction time
            Y = yuv.convert(Y);
            U = yuv.convert(U);
            V = yuv.convert(V);

            % convert to RGB if required
            switch opt.mode
            case 'rgb'
                [R,G,B] = yuv2rgb(Y,U,V);
                o1 = cat(3, R, G, B);
            case 'rgb2'
                [R,G,B] = yuv2rgb2(Y,U,V);
                o1 = cat(3, R, G, B);
            case 'yuv'
                o1 = Y;
                o2 = U;
                o3 = V;
            end

        end

        function s = char(yuv)
        %Movie.char Convert to string
        %
        % M.char() is a string representing the state of the movie object in
        % human readable form.

            s = '';
            s = strvcat(s, sprintf('YUV file: %d x %d', yuv.width, yuv.height));
            s = strvcat(s, sprintf('cur frame %d (skip=%d)', yuv.curFrame, yuv.skip));
        end

        function paramSet(m, varargin)
            opt.skip = 1;

            disp(varargin)
            opt = tb_optparse(opt, varargin);
            m.skip = opt.skip;
        end

    end % methods

    methods(Access=protected)

        %YUVREAD	Read frame from a YUV4MPEG file
        %
        %	[y,u,v] = yuvread(yuv, skip)
        %	[y,u,v, h] = yuvread(yuv, skip)
        %
        %	Returns the Y, U and V components from the specified frame of
        %	YUV file.  Optionally returns the frame header h.

        function [Y,U,V, h] = yuvread(yuv, skip)

            while skip > 0
                % read and display the header
                hdr = fgets(yuv.fp);
                if isempty(hdr)
                    Y = [];
                    return;
                end
                fprintf('header: %s', hdr);

                % read the YUV data
                [Y,count] = fread(yuv.fp, yuv.width*yuv.height, 'uchar');
                if count ~= yuv.width*yuv.height
                    Y = [];
                    return;
                end
                [V,count] = fread(yuv.fp, yuv.width*yuv.height/4, 'uchar');
                if count ~= yuv.width*yuv.height/4
                    Y = [];
                    return;
                end
                [U,count] = fread(yuv.fp, yuv.width*yuv.height/4, 'uchar');
                if count ~= yuv.width*yuv.height/4
                    Y = [];
                    return;
                end

                skip = skip - 1;
            end

            Y = reshape(Y, yuv.width, yuv.height)';
            U = reshape(U, yuv.width/2, yuv.height/2)';
            V = reshape(V, yuv.width/2, yuv.height/2)';

            if nargout == 4
                h = hdr;
            end
        end

        %YUV2RGB	Convert YUV format to RGB
        %
        %	[r,g,b] = yuvread(y, u, v)
        %	rgb = yuvread(y, u, v)
        %
        %	Returns the equivalent RGB image from YUV components.  The Y image is
        %	halved in resolution.
        function [R,G,B] = yuv2rgb(y, u, v)

            % subsample, probably should smooth first...
            y = y(1:2:end, 1:2:end);

            Cr = u - 128;
            Cb = v - 128;

            % convert to RGB
            r = (y + 1.366*Cr - 0.002*Cb);
            g = (y - 0.700*Cr - 0.334*Cb);
            b = (y - 0.006*Cr + 1.732*Cb);

            % clip the values into range [0, 255]
            r = max(0, min(r, 255));
            g = max(0, min(g, 255));
            b = max(0, min(b, 255));

            if nargout == 1,
                R(:,:,1) = r;
                R(:,:,2) = g;
                R(:,:,3) = b;
            else
                R = r;
                G = g;
                B = b;
            end
        end

        %YUV2RGB	Convert YUV format to RGB
        %
        %	[r,g,b] = yuvread2(y, u, v)
        %	rgb = yuvread(y, u, v)
        %
        %	Returns the equivalent RGB image from YUV components.  The UV images are
        %	doubled in resolution so the resulting color image is original size.
        %
        function [R,G,B] = yuv2rgb2(y, u2, v2)

            % subsample, probably should smooth first...
            u = zeros(2*size(u2));
            v = zeros(2*size(v2));

            for i=1:4,
                u(1:2:end,1:2:end) = u2;
                v(1:2:end,1:2:end) = v2;

                u(2:2:end,1:2:end) = u2;
                v(2:2:end,1:2:end) = v2;

                u(1:2:end,2:2:end) = u2;
                v(1:2:end,2:2:end) = v2;

                u(2:2:end,2:2:end) = u2;
                v(2:2:end,2:2:end) = v2;
            end

            Cr = u - 128;
            Cb = v - 128;

            % convert to RGB
            r = (y + 1.366*Cr - 0.002*Cb);
            g = (y - 0.700*Cr - 0.334*Cb);
            b = (y - 0.006*Cr + 1.732*Cb);

            % clip the values into range [0, 255]
            r = max(0, min(r, 255));
            g = max(0, min(g, 255));
            b = max(0, min(b, 255));

            if nargout == 1,
                R(:,:,1) = r;
                R(:,:,2) = g;
                R(:,:,3) = b;
            else
                R = r;
                G = g;
                B = b;
            end
        end
    end % protected methods
end


function val = viewGetUI(vw,param,varargin)
% Get data from various view structures
%
% This function is wrapped by viewGet. It should not be called by anything
% else other than viewGet.
%
% This function retrieves information from the view that relates to a
% specific component of the application.
%
% We assume that input comes to us already fixed and does not need to be
% formatted again.

if notDefined('vw'), vw = getCurView; end
if notDefined('param'), error('No parameter defined'); end

mrGlobals;
val = [];

switch param

    case 'ishidden'
        val = strcmp(viewGet(vw, 'name'), 'hidden');
    case 'ui'
        if (checkfields(vw, 'ui'))
            val = vw.ui;
        else
            warning('vista:viewError','No user interface found. Returning empty...');
        end
    case 'fignum'
        if (checkfields(vw, 'ui', 'figNum'))
            if isnumeric(vw.ui.figNum), val = vw.ui.figNum;
            else                           val = vw.ui.figNum.Number; end
        else
            warning('vista:viewError','No figure number found. Returning empty...');
        end
    case 'windowhandle'
        if (checkfields(vw, 'ui', 'windowHandle'))
            val = vw.ui.windowHandle;
        else
            warning('vista:viewError','No window handle found. Returning empty...');
        end
    case 'displaymode'
        if (checkfields(vw, 'ui', 'displayMode'))
            val = vw.ui.displayMode;
        else
            warning('vista:viewError', 'No display mode found. Returning empty...');
        end
    case 'anatomymode'
        if (checkfields(vw, 'ui', 'anatMode'))
            val = vw.ui.anatMode;
        else
            warning('vista:viewError', 'No anatomy mode found. Returning empty...');
        end
    case 'coherencemode'
        if (checkfields(vw, 'ui', 'coMode'))
            val = vw.ui.coMode;
        else
            warning('vista:viewError', 'No coherence mode found. Returning empty...');
        end
    case 'correlationmode'
        if (checkfields(vw, 'ui', 'corMode'))
            val = vw.ui.corMode;
        else
            warning('vista:viewError', 'No correlation mode found. Returning empty...');
        end
    case 'phasemode'
        if (checkfields(vw, 'ui', 'phMode'))
            val = vw.ui.phMode;
        else
            warning('vista:viewError', 'No phase mode found. Returning empty...');
        end
    case 'amplitudemode'
        if (checkfields(vw, 'ui', 'ampMode'))
            val = vw.ui.ampMode;
        else
            warning('vista:viewError', 'No amplitude mode found. Returning empty...');
        end
    case 'projectedamplitudemode'
        if (checkfields(vw, 'ui', 'projampMode'))
            val = vw.ui.projampMode;
        else
            warning('vista:viewError', 'No projected amplitude mode found. Returning empty...');
        end
    case 'mapmode'
        if (checkfields(vw, 'ui', 'mapMode'))
            val = vw.ui.mapMode;
        else
            warning('vista:viewError', 'No map mode found. Returning empty...');
        end
    case 'zoom'
        if checkfields(vw, 'ui', 'zoom')
            val = vw.ui.zoom;
        else
            warning('vista:viewError', 'No UI zoom setting found. Returning empty...');
        end
    case 'crosshairs'
        if checkfields(vw, 'ui', 'crosshairs')
            val = vw.ui.crosshairs;
        else
            warning('vista:viewError', 'No crosshairs found. Returning empty...');
        end
    case 'locs'
        if ~isfield(vw, 'loc')
            if checkfields(vw, 'ui', 'sliceNumFields')
                % single-orientation vw: get from slice # fields
                str = (get(vw.ui.sliceNumFields, 'String'))';
                for n=1:3, val(n) = str2num(str{n}); end %#ok<ST2NM>
            else
                warning('vista:viewError', 'No cursor location found. Returning empty...');
            end
        else
            val = vw.loc;
        end

    case 'phasecma'
        % This returns only the color part of the map
        nGrays = viewGet(vw, 'curnumgrays');
        if (isempty(nGrays)),
            warning('vista:viewError', 'Number of grays necessary to retrieve phase color map. Returning empty...');
            return;
        end
        if (checkfields(vw, 'ui', 'phMode', 'cmap'))
            val = round(vw.ui.phMode.cmap(nGrays+1:end,:) * 255)';
        else
            warning('vista:viewError', 'No phase color map found. Returning empty...');
        end
    case 'cmapcurrent'
        nGrays = viewGet(vw, 'curnumgrays');
        displayMode = viewGet(vw, 'displayMode');
        if (isempty(displayMode) || isempty(nGrays)),
            warning('vista:viewError', 'Display mode/number of grays necessary to retrieve color map. Returning empty...');
            return;
        end

        displayMode = [displayMode 'Mode'];
        if (checkfields(vw, 'ui', displayMode, 'cmap'))
            val = round(vw.ui.(displayMode).cmap(nGrays+1:end,:) * 255)';
        else
            warning('vista:viewError', 'No color map found for display mode ''%s''. Returning empty...', displayMode);
        end

    case 'cmapcurmodeclip'
        displayMode = viewGet(vw, 'displayMode');
        if (isempty(displayMode)),
            warning('vista:viewError', 'Display mode necessary to retrieve clip mode. Returning empty...');
            return;
        end

        displayMode = [displayMode 'Mode'];
        if (checkfields(vw, 'ui', displayMode, 'clipMode'))
            val = vw.ui.(displayMode).clipMode;
        else
            warning('vista:viewError', 'No clip mode found for display mode ''%s''. Returning empty...', displayMode);
        end
    case 'cmapcurnumgrays'
        displayMode = viewGet(vw, 'displayMode');
        if (isempty(displayMode)),
            warning('vista:viewError', 'Display mode necessary to retrieve number of grays. Returning empty...');
            return;
        end

        displayMode = [displayMode 'Mode'];
        if (checkfields(vw, 'ui', displayMode, 'numGrays'))
            val = vw.ui.(displayMode).numGrays;
        else
            warning('vista:viewError', 'No number of grays found for display mode ''%s''. Returning empty...', displayMode);
        end
    case 'cmapcurnumcolors'
        displayMode = viewGet(vw, 'displayMode');
        if (isempty(displayMode)),
            warning('vista:viewError', 'Display mode necessary to retrieve number of colors. Returning empty...');
            return;
        end

        displayMode = [displayMode 'Mode'];
        if (checkfields(vw, 'ui', displayMode, 'numColors'))
            val = vw.ui.(displayMode).numColors;
        else
            warning('vista:viewError', 'No number of grays found for display mode ''%s''. Returning empty...', displayMode);
        end
    case 'flipud'
        % Return the boolean indicating whether to invert the image u/d in
        % the graphical user interface.  It is sometimes convenient to do
        % this in the Inplane view if the top of the slice corresponds to
        % the bottom of the brain.
        % Example:
        %   flipud = viewGet(vw, 'flip updown');
        if checkfields(vw, 'ui', 'flipUD'), val = vw.ui.flipUD;
        else                                val = 0; end

    otherwise
        error('Unknown viewGet parameter');

end

return


function tf = isTestString(str)
%isTestString True if string looks like the name of a test
%   tf = isTestString(str) returns true if the string str looks like the name of
%   a test.  If str is a cell array of strings, then isTestString tests each
%   string in the cell array, returning the results in a logical array with the
%   same size as str.

%   Steven L. Eddins
%   Copyright 2008-2009 The MathWorks, Inc.

test_exp = '^[tT]est';
tf = mtest.utils.containsRegexp(str, test_exp);


%SETTARGETS Reset targets or soft labels of datafile
%
%     A = SETTARGETS(A,TARGETS)
%
% TARGETS should be a datafile with feature labels
% (FEATLAB) used for the desired LABLIST.


function rcnn_exp_cache_features(chunk)

% -------------------- CONFIG --------------------
net_file     = './data/caffe_nets/finetune_voc_2007_trainval_iter_70k';
cache_name   = 'v1_finetune_voc_2007_trainval_iter_70k';
crop_mode    = 'warp';
crop_padding = 16;

% change to point to your VOCdevkit install
VOCdevkit = './datasets/VOCdevkit2007';
% ------------------------------------------------

imdb_train = imdb_from_voc(VOCdevkit, 'train', '2007');
imdb_val   = imdb_from_voc(VOCdevkit, 'val', '2007');
imdb_test  = imdb_from_voc(VOCdevkit, 'test', '2007');
imdb_trainval = imdb_from_voc(VOCdevkit, 'trainval', '2007');

switch chunk
  case 'train'
    rcnn_cache_pool5_features(imdb_train, ...
        'crop_mode', crop_mode, ...
        'crop_padding', crop_padding, ...
        'net_file', net_file, ...
        'cache_name', cache_name);
    link_up_trainval(cache_name, imdb_train, imdb_trainval);
  case 'val'
    rcnn_cache_pool5_features(imdb_val, ...
        'crop_mode', crop_mode, ...
        'crop_padding', crop_padding, ...
        'net_file', net_file, ...
        'cache_name', cache_name);
    link_up_trainval(cache_name, imdb_val, imdb_trainval);
  case 'test_1'
    end_at = ceil(length(imdb_test.image_ids)/2);
    rcnn_cache_pool5_features(imdb_test, ...
        'start', 1, 'end', end_at, ...
        'crop_mode', crop_mode, ...
        'crop_padding', crop_padding, ...
        'net_file', net_file, ...
        'cache_name', cache_name);
  case 'test_2'
    start_at = ceil(length(imdb_test.image_ids)/2)+1;
    rcnn_cache_pool5_features(imdb_test, ...
        'start', start_at, ...
        'crop_mode', crop_mode, ...
        'crop_padding', crop_padding, ...
        'net_file', net_file, ...
        'cache_name', cache_name);
end

% ------------------------------------------------------------------------
function link_up_trainval(cache_name, imdb_split, imdb_trainval)
% ------------------------------------------------------------------------
cmd = {['mkdir -p ./feat_cache/' cache_name '/' imdb_trainval.name '; '], ...
    ['cd ./feat_cache/' cache_name '/' imdb_trainval.name '/; '], ...
    ['for i in `ls -1 ../' imdb_split.name '`; '], ...
    ['do ln -s ../' imdb_split.name '/$i $i; '], ...
    ['done;']};
cmd = [cmd{:}];
fprintf('running:\n%s\n', cmd);
system(cmd);
fprintf('done\n');


classdef DMUtilities
    % DMUtilities. Utility functions related to Dicom files
    %
    %
    %     Licence
    %     -------
    %     Part of DicoMat. https://github.com/tomdoel/dicomat
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the BSD 3-Clause license. Please see the file LICENSE for details.
    %

    methods (Static)

        function is_dicom = IsDicom(file_path, file_name)
            % Returns true if this is a Dicom file

            if strcmp(file_name, 'DICOMDIR')
                is_dicom = false;
                return
            end

            full_file_name = [file_path, filesep, file_name];

            is_dicom = DMFallbackDicomLibrary.getLibrary.isdicom(full_file_name);
        end

        function dicom_series_uid = GetDicomSeriesUid(fileName, dictionary)
            % Gets the series UID for a Dicom file

            if isempty(dictionary)
                dictionary = DMDicomDictionary.GroupingDictionary;
            end

            header = DMFallbackDicomLibrary.getLibrary.dicominfo(fileName, dictionary);

            if isempty(header)
                dicom_series_uid = [];
            else
                % If no SeriesInstanceUID tag then this is not a valid Dicom image (it
                % might be a DICOMDIR)
                if isfield(header, 'SeriesInstanceUID')
                    dicom_series_uid = header.SeriesInstanceUID;
                else
                    dicom_series_uid = [];
                end
            end
        end

        function metadata = ReadMetadata(fileName, dictionary, reporting)
            % Reads in Dicom metadata from the specified file
            try
                metadata = DMFallbackDicomLibrary.getLibrary.dicominfo(fileName, dictionary);
            catch exception
                reporting.Error('DMUtilities:MetaDataReadFail', ['Could not read metadata from the Dicom file ' file_name '. Error:' exception.message]);
            end
        end

        function metadata = ReadGroupingMetadata(fileName, reporting)
            % Reads in Dicom metadata from the specified file
            try
                metadata = DMFallbackDicomLibrary.getLibrary.dicominfo(fileName, DMDicomDictionary.GroupingDictionary);
            catch exception
                reporting.Error('DMUtilities:MetaDataReadFail', ['Could not read metadata from the Dicom file ' file_name '. Error:' exception.message]);
            end
        end

        function metadata = ReadEssentialMetadata(fileName, reporting)
            % Reads in Dicom metadata from the specified file
            try
                metadata = DMFallbackDicomLibrary.getLibrary.dicominfo(fileName);
            catch exception
                reporting.Error('DMUtilities:MetaDataReadFail', ['Could not read metadata from the Dicom file ' file_name '. Error:' exception.message]);
            end
        end

        function image_data = ReadDicomImageFromMetadata(metadata, reporting)
            % Reads in Dicom image data from the specified metadata

            try
                image_data = DMFallbackDicomLibrary.getLibrary.dicomread(metadata);
            catch exception
                reporting.Error('DMUtilities:DicomReadError', ['Error while reading the Dicom file. Error:' exception.message]);
            end
        end

        function ReadDicomImageIntoWrapperFromMetadata(metadata, image_wrapper, slice_index, reporting)
            % Reads in Dicom image data from the specified metadata. The image data
            % is stored directly into the RawImage matrix of a CoreWrapper object
            try
                image_wrapper.RawImage(:, :, slice_index, :) = DMFallbackDicomLibrary.getLibrary.dicomread(metadata);

            catch exception
                reporting.Error('DMUtilities:DicomReadError', ['Error while reading the Dicom file. Error:' exception.message]);
            end
        end

        function [name, short_name] = PatientNameToString(patient_name)
            if ischar(patient_name)
                name = patient_name;
            else
                name = '';
                short_name = '';
                if isstruct(patient_name)
                    name = DMUtilities.AddOptionalField(name, patient_name, 'FamilyName', false);
                    name = DMUtilities.AddOptionalField(name, patient_name, 'GivenName', false);
                    name = DMUtilities.AddOptionalField(name, patient_name, 'MiddleName', false);
                    name = DMUtilities.AddOptionalField(name, patient_name, 'NamePrefix', false);
                    name = DMUtilities.AddOptionalField(name, patient_name, 'NameSuffix', false);

                    short_name = DMUtilities.AddOptionalField(short_name, patient_name, 'FamilyName', true);
                    short_name = DMUtilities.AddOptionalField(short_name, patient_name, 'GivenName', true);
                    short_name = DMUtilities.AddOptionalField(short_name, patient_name, 'MiddleName', true);
                    short_name = DMUtilities.AddOptionalField(short_name, patient_name, 'NamePrefix', true);
                    short_name = DMUtilities.AddOptionalField(short_name, patient_name, 'NameSuffix', true);
                end
            end
        end

        function new_text = AddOptionalField(text, struct_name, field_name, only_if_nonempty)
            if isempty(text) || ~only_if_nonempty
                new_text = text;
                if isfield(struct_name, field_name) && ~isempty(struct_name.(field_name))
                    if isempty(text)
                        prefix = '';
                    else
                        prefix = ', ';
                    end
                    new_text = [text, prefix, struct_name.(field_name)];
                end
            else
                new_text = text;
            end
        end

        function uid = GetIdentifierFromFilename(file_name)
            [~, uid, ~] = fileparts(file_name);
        end

        function dicom_filenames = RemoveNonDicomFiles(image_path, filenames)
            dicom_filenames = [];
            for index = 1 : length(filenames)
                if (DMUtilities.IsDicom(image_path, filenames{index}))
                    dicom_filenames{end + 1} = filenames{index};
                end
            end
        end

        function tag_string = ConvertTag32ToString(tag_32)
            group_value = floor(tag_32/65536);
            tag_value = mod(tag_32, 65536);
            tag_string = ['(' dec2hex(group_value, 4) ',' dec2hex(tag_value, 4) ')'];
        end

        function tag_32 = ConvertStringToTag32(tag_string)
            group = tag_string(2:5);
            elem = tag_string(7:10);
            tag_32 = 65536*hex2dec(group) + hex2dec(elem);
        end
    end
end


function onl_sendLSL(data,outlet)
% send a data structure over an LSL outlet

str = hlp_serialize(data);
outlet.push_sample({str});


function varargout = brainstorm( varargin )
% BRAINSTORM Brainstorm startup function.
%
% USAGE: brainstorm                 : Start Brainstorm
%        brainstorm start           : Start Brainstorm
%        brainstorm nogui           : Start Brainstorm with hidden interface (for scripts)
%        brainstorm server          : Start Brainstorm on a distant server (completely headless)
%        brainstorm [script] [args] : Start Brainstorm in server mode and execute the input script
%        brainstorm ... local       : Start Brainstorm with a local database (in .brainstorm folder)
%        brainstorm stop            : Quit Brainstorm
%        brainstorm reset           : Re-inialize Brainstorm (delete preferences and database)
%        brainstorm digitize        : Digitize points using a Polhemus system
%        brainstorm update          : Download and install latest Brainstorm update
%        brainstorm autopilot ...   : Call bst_autopilot with the following arguments
%        brainstorm setpath         : Add Brainstorm subdirectories to current path
%        brainstorm startjava       : Add Brainstorm Java classes to dynamic classpath
%        brainstorm info            : Open Brainstorm website
%        brainstorm license         : Displays license agreement window
%        brainstorm tutorial name   : Run the validation script attached to a tutorial (ctf, neuromag, raw, resting, yokogawa
%        brainstorm tutorial all    : Run all the validation scripts
%        brainstorm test            : Run a coverage test
%        brainstorm deploy          : Cleanup files and copy to git repository
%        brainstorm compile         : Compile Brainstorm with Matlab mcc compiler, including all plugins
%        brainstorm compile noplugs : Compile Brainstorm with Matlab mcc compiler, without the plugins
%        brainstorm workshop        : Download OpenMEEG and the SPM atlases, and run some small tests
%  res = brainstorm('status')       : Return brainstorm status (1=running, 0=stopped)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2008-2022

% Make sure that "more" is off
more off

% Compiled version
isCompiled = exist('isdeployed', 'builtin') && isdeployed;
if isCompiled
    BrainstormHomeDir = fileparts(fileparts(which(mfilename)));
    % Some versions of the compiler use different subfolders: search for the doc folder
    if ~exist(bst_fullfile(BrainstormHomeDir, 'doc'), 'file')
        docDir = file_find(BrainstormHomeDir, 'doc', 4, 1);
        if ~isempty(docDir)
            BrainstormHomeDir = fileparts(docDir);
        end
    end
else
    % Assume we are in the Brainstorm folder
    BrainstormHomeDir = fileparts(which(mfilename));
    % Add path to the core subfolders, used in this function
    corePath = fullfile(BrainstormHomeDir, 'toolbox', 'core');
    if ~exist(corePath, 'dir')
        error(['Unable to find ' corePath ' directory.']);
    end
    % Test if the folders are already in the path first
    p = path();
    if isempty(strfind(p, corePath))
        addpath(corePath, '-BEGIN');
        addpath(fullfile(BrainstormHomeDir, 'toolbox', 'io'), '-BEGIN');
        addpath(fullfile(BrainstormHomeDir, 'toolbox', 'misc'), '-BEGIN');
    end
end

% Set dynamic JAVA CLASS PATH
if ~exist('org.brainstorm.tree.BstNode', 'class')
    % Brainstorm jar file
    BstJar = fullfile(BrainstormHomeDir, 'java', 'brainstorm.jar');
    UpdateFile = fullfile(BrainstormHomeDir, 'java', 'outdated_jar.txt');
    % If there is a flag file indicating that brainstorm.jar should be deleted (see bst_update.m)
    if exist(UpdateFile, 'file')
        delete(BstJar);
        delete(UpdateFile);
        if exist(UpdateFile, 'file') || exist(BstJar, 'file')
            errordlg(['The following files could not be deleted automatically:' 10 BstJar 10 UpdateFile 10 10 ...
                      'An error occurred during the Brainstorm update.' 10 ...
                      'Delete this brainstorm3 folder and download manually' 10 ...
                      'a new one from the Brainstorm website.']);
        end
    end
    % Download brainstorm.jar if missing
    if ~exist(BstJar, 'file')
        disp('BST> Downloading brainstorm.jar...');
        bst_webread('https://github.com/brainstorm-tools/bst-java/raw/master/brainstorm/dist/brainstorm.jar', BstJar);
    end
    % Add Brainstorm JARs to classpath
    javaaddpath(fullfile(BrainstormHomeDir, 'java', 'RiverLayout.jar'));
    javaaddpath(BstJar);
end

% Default action : start
if (nargin == 0)
    action = 'start';
    BrainstormDbDir = [];
else
    action = lower(varargin{1});
    % Local start
    if ismember(action, {'start', 'nogui', 'server'}) && (nargin == 2) && strcmpi(varargin{2}, 'local')
        BrainstormDbDir = 'local';
    else
        BrainstormDbDir = [];
    end
end

res = 1;
switch action
    case 'start'
        bst_set_path(BrainstormHomeDir);
        bst_startup(BrainstormHomeDir, 1, BrainstormDbDir);
    case 'nogui'
        bst_set_path(BrainstormHomeDir);
        bst_startup(BrainstormHomeDir, 0, BrainstormDbDir);
    case 'server'
        bst_set_path(BrainstormHomeDir);
        bst_startup(BrainstormHomeDir, -1, BrainstormDbDir);
    case 'autopilot'
        if ~isappdata(0, 'BrainstormRunning')
            bst_set_path(BrainstormHomeDir);
            bst_startup(BrainstormHomeDir, 2, BrainstormDbDir);
        end
        res = bst_autopilot(varargin{2:end});
    case 'digitize'
        brainstorm nogui
        panel_digitize('Start');
    case {'status', 'isstarted', 'isrunning'}
        res = isappdata(0, 'BrainstormRunning');
    case {'exit', 'stop', 'quit'}
        bst_exit();
    case 'reset'
        bst_reset();
    case 'setpath'
        disp('Adding all Brainstorm directories to local path...');
        bst_set_path(BrainstormHomeDir);
    case 'startjava'
        disp('Starting Java...');
    case {'info', 'website'}
        web('https://neuroimage.usc.edu/brainstorm/', '-browser');
    case 'forum'
        web('https://neuroimage.usc.edu/forums/', '-browser');
    case 'license'
        bst_set_path(BrainstormHomeDir);
        bst_set('BrainstormHomeDir', BrainstormHomeDir);
        bst_license();
    case 'update'
        % Add path to java_dialog function
        addpath(fullfile(BrainstormHomeDir, 'toolbox', 'gui'));
        % Update
        bst_update(0);
    case 'tutorial'
        bst_set_path(BrainstormHomeDir);
        tutonames = varargin{2};
        % Tutorial folder
        if (nargin < 3)
            tutorial_dir = 'C:\Work\RawData\Tutorials';
        else
            tutorial_dir = varargin{3};
        end
        % Run all the tutorial scripts
        if isequal(tutonames, 'all')
            tutonames = {'ctf', 'raw', 'epilepsy', 'resting', 'neuromag', 'yokogawa', 'auditory'};
        elseif ischar(tutonames)
            tutonames = {tutonames};
        elseif ~iscell(tutonames)
            error('Invalid call.');
        end
        % Run all the requested validation scripts
        for i = 1:length(tutonames)
            disp([10 '===== TUTORIAL: ' upper(tutonames{i}) ' =====']);
            startTime = tic;
            if (length(varargin) == 4)
                eval(['tutorial_' lower(tutonames{i}) '(''' tutorial_dir ''', ''' varargin{4} ''');']);
            else
                eval(['tutorial_' lower(tutonames{i}) '(''' tutorial_dir ''');']);
            end
            % Done
            stopTime = toc(startTime);
            if (stopTime > 60)
                disp(sprintf('BST> Done in %dmin\n', round(stopTime/60)));
            else
                disp(sprintf('BST> Done in %ds\n', round(stopTime)));
            end
            % Close report viewer if it is not the last tutorial to run
            if (i < length(tutonames))
                bst_report('Close');
            end
        end

    case 'test'
        bst_set_path(BrainstormHomeDir);
        if (nargin < 2)
            error(['You must specify an empty test folder.' 10 'Usage: brainstorm test test_dir']);
        end
        test_dir = varargin{2};
        test_all(test_dir);

    case 'workshop'
        % Runs Brainstorm normally (asks for brainstorm_db)
        if ~isappdata(0, 'BrainstormRunning')
            bst_set_path(BrainstormHomeDir);
            bst_startup(BrainstormHomeDir, 1, BrainstormDbDir);
        end
        % Message
        java_dialog('msgbox', 'Brainstorm will now download additional files needed for the workshop.', 'Workshop');
        % Downloads OpenMEEG
        bst_plugin('Install', 'openmeeg', 1);
        % Downloads the TMP.nii SPM atlas
        bst_normalize_mni('install');
        % Message
        java_dialog('msgbox', ['Brainstorm will now test your display and open a 3D figure:' 10 10 ...
                               ' - You should see two surfaces: a brain surface and a transparent head.' 10 ...
                               ' - Make sure you can rotate the brain with your mouse, ' 10 ...
                               ' - Then close the figure.' 10 10], 'Workshop');
        % Creates an empty test protocol
        ProtocolName = 'TestWorkshop';
        gui_brainstorm('DeleteProtocol', ProtocolName);
        gui_brainstorm('CreateProtocol', ProtocolName, 0, 0);
        % Display the default anatomy cortex and head
        hFig = view_surface('@default_subject/tess_cortex_pial_low.mat');
        hFig = view_surface('@default_subject/tess_head.mat', [], [], hFig);
        waitfor(hFig);
        % Delete test protocol
        gui_brainstorm('DeleteProtocol', ProtocolName);
        % Confirmation message
        java_dialog('msgbox', 'You computer is ready for the workshop.', 'Workshop');

    case 'deploy'
        % Add path to deploy function
        bst_set_path(BrainstormHomeDir);
        addpath(fullfile(BrainstormHomeDir, 'deploy'));
        bst_set('BrainstormHomeDir', BrainstormHomeDir);
        % Deploy Braintorm
        bst_deploy();

    case 'compile'
        % Add path to deploy function
        bst_set_path(BrainstormHomeDir);
        addpath(fullfile(BrainstormHomeDir, 'deploy'));
        % Options
        if (nargin > 1)
            if strcmpi(varargin{2}, 'noplugs')
                isPlugs = 0;
            else
                error('Usage: brainstorm compile [noplugs]');
            end
        else
            isPlugs = 1;
        end
        % Matlab < 2020a: Old compilation function using deploytool
        if (bst_get('MatlabVersion') < 908)
            addpath(fullfile(BrainstormHomeDir, 'deploy', 'deprecated'));
            if isPlugs
                bst_deploy_java('2');
            else
                bst_deploy_java('1');
            end
        else
            bst_compile(isPlugs);
        end

    otherwise
        % Check if trying to execute a script
        if file_exist(varargin{1})
            ScriptFile = varargin{1};
        elseif file_exist(fullfile(pwd, varargin{1}))
            ScriptFile = fullfile(pwd, varargin{1});
        else
            ScriptFile = [];
        end
        % Execute script
        if ~isempty(ScriptFile)
            % Start brainstorm in server mode (local database or not)
            % With extra parameters
            if (length(varargin) > 1)
                params = varargin(2:end);
                if any(cellfun(@(c)isequal(c,'local'), varargin(2:end)))
                    brainstorm server local;
                    params(cellfun(@(c)isequal(c,'local'), params)) = [];
                else
                    brainstorm server;
                end
            % Without extra parameters
            else
                brainstorm server;
                params = [];
            end
            % Execute script
            if ~isempty(params)
                bst_call(@panel_command, 'ExecuteScript', ScriptFile, params{:});
            else
                bst_call(@panel_command, 'ExecuteScript', ScriptFile);
            end
            % Quit
            brainstorm stop;

        % Display usage
        else
            disp(' ');
            disp('Usage : brainstorm start           : Start Brainstorm');
            disp('        brainstorm nogui           : Start Brainstorm with hidden interface (for scripts)');
            disp('        brainstorm server          : Start Brainstorm on a distant server (completely headless)');
            disp('        brainstorm <script> <args> : Start Brainstorm in server mode, execute the input script and quit');
            disp('        brainstorm ... local       : Start Brainstorm with a local database (in .brainstorm folder)');
            disp('        brainstorm stop            : Quit Brainstorm');
            disp('        brainstorm update          : Download and install latest Brainstorm update (see bst_update)');
            disp('        brainstorm reset           : Re-initialize Brainstorm database and preferences');
            disp('        brainstorm digitize        : Digitize electrodes positions and head shape using a Polhemus system');
            disp('        brainstorm setpath         : Add Brainstorm subdirectories to current path');
            disp('        brainstorm startjava       : Add Brainstorm Java classes to dynamic classpath');
            disp('        brainstorm info            : Open Brainstorm website');
            disp('        brainstorm forum           : Open Brainstorm forum');
            disp('        brainstorm license         : Display license');
            disp('        brainstorm tutorial name   : Run the validation script attached to a tutorial (ctf, neuromag, raw, resting, yokogawa)');
            disp('        brainstorm tutorial all    : Run all the validation scripts');
            disp('        brainstorm packagebin      : Create separate zip files for all the currently available binary distributions');
            disp('  res = brainstorm(''status'')     : Return brainstorm status (1=running, 0=stopped)');
            disp(' ');
        end
end

% Return value
if (nargout >= 1)
    varargout{1} = res;
end

end

%% ===== SET PATH =====
function bst_set_path(BrainstormHomeDir)
    % Cancel add path in case of deployed application
    if bst_iscompiled()
        return
    end
    % Brainstorm folder itself
    addpath(BrainstormHomeDir, '-BEGIN'); % make sure the main brainstorm folder is in the path
    % List of folders to add
    NEXTDIR = {'external','toolbox'}; % in reverse order of priority
    for i = 1:length(NEXTDIR)
        nextdir = fullfile(BrainstormHomeDir,NEXTDIR{i});
        % Reset the last warning to blank
        lastwarn('');
        % Check that directory exist
        if ~isdir(nextdir)
            error(['Directory "' NEXTDIR{i} '" does not exist in Brainstorm path.' 10 ...
                   'Please re-install Brainstorm.']);
        end
        % Recursive search for subfolders in each main folder
        P = genpath(nextdir);
        % Add directory and subdirectories
        addpath(P, '-BEGIN');
    end
    % Adding user's mex path
    userMexDir = bst_get('UserMexDir');
    addpath(userMexDir, '-BEGIN');
    % Adding user's custom process path
    userProcessDir = bst_get('UserProcessDir');
    addpath(userProcessDir, '-BEGIN');
end


function tagS = ROI_contour_module_tags
%"ROI_contour_module_tags"
%   Return the tags used to represent a ROI contour specified by
%   C.8.8.6 in PS3.3 of 2006 DICOM specification. Tags are returned in a
%   struct array with 3 fields:
%
%   Tag: String containing hex DICOM tag of a field.
%  Type: String describing type of field, with 5 options:
%         '1' Field must exist, data must exist and be valid.
%         '2' Field must exist, data can exist and be valid, or be NULL.
%         '3' Field is optional, if the field exists data can exist and be
%             valid or be NULL.
%         '1C' Field must exist under certain conditions and contain valid
%             data.
%         '2C' Field must exist under certain conditions and can contain
%             valid data or be NULL.
%Children: For sequences, a tagS with the same format as this struct array
%          containing the tags of child fields.
%
%JRA 06/06/06
%
%Usage:
%   tagS = ROI_contour_module_tags
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

%Initialize the tagS structure.
tagS = struct('tag', {}, 'tagdec', {}, 'type', {}, 'children', {});

%Create an empty tagS template for sequence creation.
template = tagS;

%Add tags based on PS3.3 attribute lists.

%ROI Contour Sequence
tagS(end+1) = struct('tag', '30060039', 'tagdec', 805699641, 'type', '1', 'children', []);
child_1     = template;

    %Referenced ROI Number
    child_1(end+1) = struct('tag', '30060084', 'tagdec', 805699716, 'type', '1', 'children', []);

    %ROI Display Color
    child_1(end+1) = struct('tag', '3006002A', 'tagdec', 805699626, 'type', '3', 'children', []);

    %Contour Sequence
    child_1(end+1) = struct('tag', '30060040', 'tagdec', 805699648, 'type', '3', 'children', []);
    child_2        = template;

        %Contour Number
        child_2(end+1) = struct('tag', '30060048', 'tagdec', 805699656, 'type', '3', 'children', []);

        %Attached Contours
        child_2(end+1) = struct('tag', '30060049', 'tagdec', 805699657, 'type', '3', 'children', []);

        %Contour Image Sequence
        child_2(end+1) = struct('tag', '30060016', 'tagdec', 805699606, 'type', '3', 'children', []);
        child_3        = template;

            %Image SOP Instance Reference Macro
            child_3 = image_SOP_instance_reference_macro_tags;
            child_2(end).children = child_3;

        %Contour Geometric Type
        child_2(end+1) = struct('tag', '30060042', 'tagdec', 805699650, 'type', '1C', 'children', []);

        %Contour Slab Thickness
        child_2(end+1) = struct('tag', '30060044', 'tagdec', 805699652, 'type', '3', 'children', []);

        %Contour Offset Vector
        child_2(end+1) = struct('tag', '30060045', 'tagdec', 805699653, 'type', '3', 'children', []);

        %Number of Contour Points
        child_2(end+1) = struct('tag', '30060046', 'tagdec', 805699654, 'type', '1C', 'children', []);

        %Contour Data
        child_2(end+1) = struct('tag', '30060050', 'tagdec', 805699664, 'type', '1C', 'children', []);

        child_1(end).children = child_2;

   tagS(end).children = child_1;


function renamefolder(HOMEANNOTATIONS, annotationfolder)
%
% Writes in the folder field of the xml file the nane of the folder in
% which the annotation files are.
%
% This script is useful when moving annotation files into other folders
% manually. This function guaratees consistency.

files = dir(fullfile(HOMEANNOTATIONS, annotationfolder, '*.xml'));

Nfiles = length(files);
for i = 1:Nfiles
    v = loadXML(fullfile(HOMEANNOTATIONS, annotationfolder, files(i).name));
    v.annotation.folder = annotationfolder;
    writeXML(fullfile(HOMEANNOTATIONS, annotationfolder, files(i).name), v);
end


function DBListFigures(query)

%DBListFigures - List figures matching certain criteria.
%
%  USAGE
%
%    DBListFigures(query)
%
%    query          optional database query (WHERE clause)
%
%  EXAMPLE
%
%    DBListFigures('name="Spectrogram"');
%
%  SEE
%
%    See also DBGetVariables, DBGetFigures.
%

% Copyright (C) 2013 by Michaël Zugaro
%
% 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.

% Make sure MyM is installed and functional
CheckMyM;

if nargin < 1,
	query = '';
end

DBDisplay(DBGetFigures(query,'output','keys'));