%%
% MetaboRePort:

%% correct CheBI ID's in rBionet metabolite_structure
if 0
    load('C:\Users\0123322S\Desktop\X\met_strc_rBioNet_new_30_06_2022.mat')
    F = fieldnames(metabolite_structure_rBioNet);
    % reset chebiid
    for i = 1 : length(F)
        if strcmp(metabolite_structure_rBioNet.(F{i}).cheBIId,'1')
            metabolite_structure_rBioNet.(F{i}).cheBIId = NaN;
        end
    end
    % search hmdb for all chebi ids missing
    metabolite_structure_rBioNet2 = metabolite_structure_rBioNet;
    for i = 1 : length(F)
        if isnan(metabolite_structure_rBioNet2.(F{i}).cheBIId)
            [metabolite_structure_rBioNet2,IDsAddedHMDB,IDsMismatchHMDB] = parseHmdbWebPage(metabolite_structure_rBioNet2,i,i);
            i
            metabolite_structure_rBioNet2.(F{i}).cheBIId
        end
    end
    metabolite_structure_rBioNet = metabolite_structure_rBioNet2;
    save('C:\Users\0123322S\Desktop\X\met_strc_rBioNet_new_18_10_22.mat','metabolite_structure_rBioNet')
end

%% creating the files from scratch
load('C:\Users\0123322S\Desktop\X\met_strc_rBioNet_new_18_10_22.mat')
%folder = 'C:\Users\0123322S\Downloads\AGORA2_mat_files\AGORA2_mat_files\AGORA2_mat_files_1\';
folder = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\';
%folderUpdated = 'C:\Users\0123322S\Downloads\AGORA2_mat_files\AGORA2_mat_files\AGORA2_mat_files_1\';
folderUpdated = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\AGORA2_annotated\';
%reportDir = 'C:\Users\0123322S\Documents\GitHub\MetaboRePort\reports';
reportDir = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\AGORA2_annotated\metaboRePorts\';

dInfo=dir(folder);
modelList={dInfo.name};
modelList=modelList';
modelList(~contains(modelList(:,1),'.mat'),:)=[];

dInfoUpdated=dir(folderUpdated);
modelListUpdated={dInfoUpdated.name};
modelListUpdated=modelListUpdated';

dInfoReport=dir(reportDir);
modelListReport={dInfoReport.name};
modelListReport=modelListReport';

if 0
    tic;
    cnt = 1
    for i = s : e%length(modelList)
        i
        if isempty(find(ismember(modelListUpdated,modelList{i})))
            load(strcat(folder, modelList{i}));
            %[modelProp1,ScoresOverall1] = generateMemoteLikeScore(model);
            [modelUpdated] = populateModelMetStr(model, metabolite_structure_rBioNet,1);
            [modelUpdated] = annotateSBOTerms(modelUpdated);
            modelUpdated = rmfield(modelUpdated,'metInChIString'); % wrongly in microbe models

            [modelUpdated] = populateModelwithRxnIDs(modelUpdated);
            try
                [modelProp2,ScoresOverall2] = generateMetaboScore(modelUpdated);

                modelProperties.(regexprep(modelList{i},'.mat','')).ScoresOverall = ScoresOverall2;
                modelProperties.(regexprep(modelList{i},'.mat','')).modelUpdated = modelUpdated;
                modelProperties.(regexprep(modelList{i},'.mat','')).modelProp2 = modelProp2;
                ScoresOverall{i,1} = regexprep(modelList{i},'.mat','');
                ScoresOverall{i,2} = num2str(ScoresOverall2);
                % if mod(i,10)
                save(strcat(reportDir,'AGORA2_MetaboRePorts_',modelList{i}),'modelProperties','ScoresOverall');
                clear modelProperties
                %  end
                %% save updated mat file
            catch
                modelList{i}
                missing{cnt,1} = modelList{i};
                cnt = cnt + 1;
            end
            model =modelUpdated;
            save(strcat(folderUpdated,modelList{i}),'model');
            %     %%generate sbml file
            %     %remove description from model structure as this causes issues
            %
            %     modelUpdated = rmfield(modelUpdated,'description');
            %     fileName = regexprep(modelList{i},'.mat','');
            %     if isempty(find(ismember(modelListUpdated,strcat(fileName,'.xml'))))
            %         outmodel = writeCbModel(modelUpdated, 'format','sbml', 'fileName', strcat(folderUpdated,'',fileName));
            %     end
        end
    end
    toc;
    save('AGORA2_MetaboRePorts_ScoresOverall.mat','ScoresOverall');

end

%% generate missing metaboReports for existing updated annotated models
if 0
    tic;
    cnt = 1
    for i = s : e%length(modelList)
        i
        modelListReport = regexprep(modelListReport,'AGORA2_MetaboRePorts_','');
        if isempty(find(ismember(modelListReport,modelList{i})))
            load(strcat(folderUpdated, modelList{i}));
            try
                [modelProp2,ScoresOverall2] = generateMetaboScore(model);

                modelProperties.(regexprep(modelList{i},'.mat','')).ScoresOverall = ScoresOverall2;
                modelProperties.(regexprep(modelList{i},'.mat','')).modelUpdated = model;
                modelProperties.(regexprep(modelList{i},'.mat','')).modelProp2 = modelProp2;
                ScoresOverall{i,1} = regexprep(modelList{i},'.mat','');
                ScoresOverall{i,2} = num2str(ScoresOverall2);
                % if mod(i,10)
                save(strcat(reportDir,'AGORA2_MetaboRePorts_',modelList{i}),'modelProperties','ScoresOverall');
                clear modelProperties
                %  end
                %% save updated mat file
            catch
                modelList{i}
                missing{cnt,1} = modelList{i};
                cnt = cnt + 1;
            end

            %     %%generate sbml file
            %     %remove description from model structure as this causes issues
            %
            %     modelUpdated = rmfield(modelUpdated,'description');
            %     fileName = regexprep(modelList{i},'.mat','');
            %     if isempty(find(ismember(modelListUpdated,strcat(fileName,'.xml'))))
            %         outmodel = writeCbModel(modelUpdated, 'format','sbml', 'fileName', strcat(folderUpdated,'',fileName));
            %     end
        end
    end
    toc;
end

if 0
    % get all the report m files
    dInfoReport=dir(reportDir);
    modelListReport={dInfoReport.name};
    modelListReport=modelListReport';

    cnt = 1;
    for i = s :e% length(modelListReport)
        report = regexprep(modelListReport{i},'\.mat','\.html');
        report = regexprep(report,'AGORA2_MetaboRePorts_','modelreport_');
        i
        if ~isempty(strfind(modelListReport{i},'.mat')) && isempty(find(ismember(modelListReport,report)))
            load(strcat(reportDir,filesep,modelListReport{i}))
            orgName{1} = regexprep(modelListReport{i},'\.html','');
            orgName{1} = regexprep(orgName{1},'AGORA2_MetaboRePorts_','');
            evalc('generateMetaboReport(modelProperties,reportDir,orgName)');
            % get scores
            report
            F = fieldnames(modelProperties);
            ScoresAll(cnt,1) = modelProperties.(F{1}).modelProp2.Scores.Consistency;
            ScoresAll(cnt,2) = modelProperties.(F{1}).modelProp2.Scores.AnnotationMetabolites;
            ScoresAll(cnt,3) = modelProperties.(F{1}).modelProp2.Scores.AnnotationReactions;
            ScoresAll(cnt,4) = modelProperties.(F{1}).modelProp2.Scores.AnnotationGenes;
            ScoresAll(cnt,5) = modelProperties.(F{1}).modelProp2.Scores.AnnotationSBO;
            ScoresAll(cnt,6) = modelProperties.(F{1}).modelProp2.Scores.Overall;
            cnt = cnt +1;
        end
    end
end
%% updating only Chebii id's in the files
load('C:\Users\0123322S\Desktop\X\met_strc_rBioNet_new_18_10_22.mat')

folder = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\';
%folderUpdated = 'C:\Users\0123322S\Downloads\AGORA2_mat_files\AGORA2_mat_files\AGORA2_mat_files_1\';
folderUpdated = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\AGORA2_annotated\';
folderUpdatedNew = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\AGORA2_annotatedNew\';
folderUpdatedNewSBML = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\AGORA2_annotatedNewSBML\';

%reportDir = 'C:\Users\0123322S\Documents\GitHub\MetaboRePort\reports';
reportDir = 'C:\Users\0123322S\Dropbox\MY PAPERS\SUBMITTED\Submitted\AGORA2\NatureBiotech\resubmission\AGORA2_recreated\AGORA2_annotated\metaboRePorts\';

dInfo=dir(folder);
modelList={dInfo.name};
modelList=modelList';
modelList(~contains(modelList(:,1),'.mat'),:)=[];

dInfoUpdated=dir(folderUpdated);
modelListUpdated={dInfoUpdated.name};
modelListUpdated=modelListUpdated';

dInfoUpdatedSBML=dir(folderUpdatedNewSBML);
modelListUpdatedSBML={dInfoUpdatedSBML.name};
modelListUpdatedSBML=modelListUpdatedSBML';

dInfoReport=dir(reportDir);
modelListReport={dInfoReport.name};
modelListReport=modelListReport';

if 1
    tic;
    Fori = fieldnames(metabolite_structure_rBioNet);
    F = regexprep(Fori,'VMH_','');
    for i =  s: e%length(modelListUpdated)
        i

        dInfoUpdatedSBML=dir(folderUpdatedNewSBML);
        modelListUpdatedSBML={dInfoUpdatedSBML.name};
        modelListUpdatedSBML=modelListUpdatedSBML';
        modelName = regexprep(modelListUpdated{i},'.mat','');

        if ~isempty(strfind(strcat(folderUpdated, modelListUpdated{i}),'.mat')) && isempty(strmatch(strcat(modelName,'.xml'),modelListUpdatedSBML))
            i
            % load annotated model
            load(strcat(folderUpdated, modelListUpdated{i}));
            for k = 1 : length(model.mets)
                % replace metChEBIID
                met = split(model.mets{k},'[');
                if strcmp('sertrna(sec)',met{1}) % replace the abbr of this metabolite
                    met{1} = 'sertrna';
                end
                match = strmatch(met{1},F,'exact');
                if length(find(isnan(metabolite_structure_rBioNet.(Fori{match}).cheBIId)))==0 && ~isempty(metabolite_structure_rBioNet.(Fori{match}).cheBIId)
                    model.metChEBIID{k} = strcat('CHEBI:',metabolite_structure_rBioNet.(Fori{match}).cheBIId);
                end
            end
            % annotate model properties correctly

            model.modelName = regexprep(modelName,'_',' ');
            model.modelID = modelName;
            model.modelAnnotation = {model.modelID;...
                'version 2.0';...
                strcat('Created: ',model.description.date)
                'Molecular Systems Physiology Group, University of Galway, Ireland. https://thielelab.eu';...
                strcat('This is a metabolism reconstruction of:', model.modelName);...
                'The draft reconstruction was created using Kbase/ModelSeed and refined with the DEMETER pipeline from the COBRA toolbox v3';...
                'When using or adapting this reconstruction, please cite:';...
                'Heinken, A., Hertel, J., Acharya, G., Ravcheev, D.A., Nyga, M., Okpala, O.E., Hogan, M., Magnusdottir, S., Martinelli, F., Nap, B., Preciat, G., Edirisinghe, J.N., Henry, C.S., Fleming, R.M.T., Thiele, I., "AGORA2: Knowledge-driven genome-scale reconstruction of 7,302 human microbes for personalised medicine", Nat Biotech, accepted (2022), https://doi.org/10.1101/2020.11.09.375451.';...
                'Obtained from https://vmh.life/';...
                };
            model = rmfield(model,'description');
            model.description = modelName;

            save(strcat(folderUpdatedNew, modelListUpdated{i}),'model');

            %%generate sbml file
            %remove description from model structure as this causes issues

            if isempty(find(ismember(modelListUpdatedSBML,strcat(modelName,'.xml'))))
                outmodel = writeCbModel(model, 'format','sbml', 'fileName', strcat(folderUpdatedNewSBML,'',modelName));
            end
            clear outmodel model
        end
    end
end


function setcustompath(option_path)

% SETCUSTOMPATH is a helper function that updates the path to contain all the
% custom directories, while keeping the peer or qsub path untouched.

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

% these are for remembering the path on subsequent calls with the same input arguments
persistent previous_argin previous_path

% the following pertains to path settings, which does not apply in case
% this code is included in a compiled MATLAB application
if ~isdeployed

  if isequal(previous_argin, option_path) && isequal(previous_path, path)
    % no reason to change the path again
    return
  end

  if ~isempty(option_path)
    f = mfilename('fullpath'); % this is .../peer/private/getcustompath.m
    f = fileparts(f);          % this is .../peer/private
    f = fileparts(f);          % this is .../peer
    [p, d] = getcustompath;
    % ensure that the default path is maintained
    path(d);
    % add the custom path
    path(option_path, path);
    % ensure that the peer functions are maintained on the path
    path(f, path);
  end

  % remember the current settings for the next call
  previous_argin = option_path;
  previous_path  = path;

end


%% script demoing how to run JLabel

clear classes;
%% set up path

[~,computername] = system('hostname');
computername = strtrim(computername);

switch computername,

  case 'bransonk-lw1',

    JCtrax_path = 'E:\Code\JCtrax';
    %FlyBowlAnalysis_path = 'E:\Code\FlyBowlAnalysis';
    %rootdatadir = 'E:\Code\Jdetect\larva\fly_data\TrainingData';
    %settingsdir = 'E:\Code\FlyBowlAnalysis\settings';
    configfilename = 'params\JLabelParams.xml';
    npool = 4;

  case 'bransonk-lw2',

    JCtrax_path = 'C:\Code\JCtrax';
    %FlyBowlAnalysis_path = 'C:\Code\FlyBowlAnalysis';
    %rootdatadir = 'C:\Code\Jdetect\larva\fly_data\TrainingData';
    %settingsdir = 'C:\Code\FlyBowlAnalysis\settings';
    configfilename = 'params\JLabelParamsKristinChase.xml';
    npool = 4;

  case 'bransonk-desktop',

    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/larva/fly_data/TrainingData/';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = 'params/JLabelParams_bransonk-desktop.xml';
    npool = 8;

  case 'kabram-ws.janelia.priv',

    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/larva/fly_data/TrainingData/';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = 'params/JLabelParamsMayank.xml';
    npool = 8;

  case 'robiea-ws'
    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/sciserv/flyolympiad/Olympiad_Screen/fly_bowl/bowl_data';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = '/groups/branson/home/robiea/Projects_data/JLabel/JLabelParams.xml';
    npool = 8;

  otherwise

    warning('Unknown computer %s. Paths may not be setup correctly',computername);
    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/larva/fly_data/TrainingData/';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = 'params/JLabelParams_bransonk-desktop.xml';
    npool = 1;

end

addpath(fullfile(JCtrax_path,'misc'));
addpath(fullfile(JCtrax_path,'filehandling'));
jlabelpath = fileparts(which('JLabel'));
addpath(fullfile(jlabelpath,'compute_perframe_features'));
%addpath(FlyBowlAnalysis_path);

%%
try
  if npool > 1,
    matlabpool(npool);
  end
catch %#ok<CTCH>
end
%% start JLabel

hfig = JLabel('configfilename',configfilename); handles = guidata(hfig);


function [propValue, srcObj] = get(obj, propName)
% Accessor for reading BstPanel attributes.

% @=============================================================================
% 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

% Check if the field propName exists in the object
if (ismember(propName, fields(obj)))
    % If it exists, try to return its value
    if (length(obj) == 1)
        propValue = obj.(propName);
        srcObj    = obj;
    else
        propValue = {obj.(propName)};
        srcObj    = obj;
    end

else
    %iPanel = find(cellfun(@(f)isfield(f, propName), obj.sControls), 1);
    if isfield(obj.sControls, propName)
        propValue = obj.sControls.(propName);
        srcObj    = obj;
    else
        propValue = [];
        srcObj    = [];
    end
end

end


function str = opti_PreReqCheck(mode,verb)
%Check for VC++ 2010 / VC++ 2012 on x86 and x64 systems

if(nargin < 2), verb = 1; end
if(nargin < 1), mode = 'VS2012'; end

ROOTKEY = 'HKEY_LOCAL_MACHINE';
switch(lower(mode))
    case {'2012','vs2012'}
        %VC++ 2012 Keys
        KEY32 = 'SOFTWARE\Wow6432Node\Microsoft\DevDiv\VC\Servicing\11.0\RuntimeMinimum';
        KEY64 = 'SOFTWARE\Microsoft\DevDiv\VC\Servicing\11.0\RuntimeMinimum1';
        rtstr = 'VC++ 2012';
        rtredist86 = '';
        rtrunt86 = '';
        rtredist64 = '';
        rtrunt64 = '';
        instkey = 'Install';
    case {'2010','vs2010'}
        %VC++ 2010 Keys
        KEY32 = 'SOFTWARE\Microsoft\VisualStudio\10.0\VC\';
        KEY64 = 'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\VC\';
        rtstr = 'VC++ 2010';
        rtredist86 = 'VCRedist\x86';
        rtrunt86 = 'Runtimes\x86';
        rtredist64 = 'VCRedist\x64';
        rtrunt64 = 'Runtimes\x64';
        instkey = 'Installed';
    otherwise
        error('Unknown Visual C++ / Intel C++ Version to check for! Only VC++ 2010 and 2012 supported');
end

mver = ver('MATLAB');
if(verb), fprintf('- Checking operating system...\n'); end
switch(mexext)
    case 'mexw32'
        if(verb), fprintf('MATLAB %s 32bit (Windows x86) detected\n',mver.Release); end
    case 'mexw64'
        if(verb), fprintf('MATLAB %s 64bit (Windows x64) detected\n',mver.Release); end
    otherwise
        error('OPTI Toolbox is compiled only for Windows systems - sorry!');
end

if(verb), fprintf('\n- Checking for required pre-requisites...\n'); end

str = [];
switch(mexext)
    %If mexw32 - could be 32bit windows or 64bit windows with 32bit matlab, must check both!
    case 'mexw32'
        %Check 32bit Location, Redist
        try
            if(winqueryreg(ROOTKEY,[KEY32 rtredist86],instkey))
                str = [rtstr ' x86 Redistributable (Win32) Found'];
            end
        catch %#ok<*CTCH>
            %Check 32bit Location, Runtime
            try
                if(winqueryreg(ROOTKEY,[KEY32 rtrunt86],instkey))
                    str = [rtstr ' x86 Runtime (Win32) Found'];
                end
            catch
                %Check 64bit Location, Redist
                try
                    if(winqueryreg(ROOTKEY,[KEY64 rtredist86],instkey))
                        str = [rtstr ' x86 Redistributable (Win64) Found'];
                    end
                catch
                    %Check 64bit Location, Runtime
                    try
                        if(winqueryreg(ROOTKEY,[KEY64 rtrunt86],instkey))
                            str = [rtstr ' x86 Redistributable (Win64) Found'];
                        end
                    catch
                        error(prereqerror('x86',rtstr));
                    end
                end
            end
        end
    case 'mexw64'
        %Check Redist
        try
            if(winqueryreg(ROOTKEY,[KEY64 rtredist64],instkey))
                str = [rtstr ' x64 Redistributable Found'];
            end
        catch
            %Check Runtime
            try
                if(winqueryreg(ROOTKEY,[KEY64 rtrunt64],instkey))
                    str = [rtstr ' x64 Runtime Found'];
                end
            catch
                error(prereqerror('x64',rtstr));
            end
        end
end

if(isempty(str))
    error('Could not determine the required pre-requisites, ensure you are running Windows x86 or x64!');
else
    if(verb), fprintf('%s\n',str); end
end

function str = prereqerror(build,rtstr)

switch(rtstr)
    case 'VC++ 2012'
        l = 'http://www.microsoft.com/en-us/download/details.aspx?id=30679';
        m = 'Microsoft';
    case 'VC++ 2010'
        switch(build)
            case 'x64'
                l = 'http://www.microsoft.com/download/en/details.aspx?id=14632';
            otherwise
                l = 'http://www.microsoft.com/download/en/details.aspx?id=5555';
        end
        m = 'Microsoft';
    case 'Intel C++ XE 2013'
        l = 'http://software.intel.com/en-us/articles/redistributable-libraries-for-intel-c-and-visual-fortran-composer-xe-2013-for-windows';
        m = 'Intel';
end

str = [sprintf(['Cannot find the %s ' rtstr ' ' build ' Redistributable!\n\n'],m)...
	   sprintf('Please close MATLAB and download the redistributable from %s:\n',m)...
       l...
       sprintf('\n\nThen reinstall OPTI Toolbox.')];


mcc -m computeFeaturesCompiled ...
  -R -singleCompThread ...
  -a filehandling/ ...
  -a misc/ ...
  -a toolbox/ ...
  -a optflow_deqing/ ...
  -a deepmatching/deepmex_cluster.mexa64
if exist('readme.txt','file'),
  delete('readme.txt');
end
if exist('mccExcludedFiles.log','file'),
  delete('mccExcludedFiles.log');
end
if exist('requiredMCRProducts.txt','file'),
  delete('requiredMCRProducts.txt');
end


function ROIInterpretedType = initROIInterpretedType
% ROIInterpretedType
%       Written DK Sept-2009
%
%
% This function lists in alphabetical order ROIInterpretedType as per DICOM PS 3.3 - 2008
% Page 519.
%
% 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/>.

ROIInterpretedType = struct(...
    'AVOIDANCE'                                  ,  'region in which dose is to be minimized',...
    'BOLUS'                                          ,  'patient bolus to be used for external beam therapy',...
    'BRACHY_ACCESSORY'                    ,  'brachytherapy accessory device',...
    'BRACHY_CHANNEL'                       ,  'brachytherapy channel',...
    'BRACHY_CHNL_SHLD'                   ,  'brachytherapy channel shield',...
    'BRACHY_SRC_APP'                        ,  'brachytherapy source applicator',...
    'CAVITY'                                         ,  'patient anatomical cavity',...
    'CONTRAST_AGENT'                       ,  'volume into which a contrast agent has been injected',...
    'CONTROL'                                     ,  'ROI to be used in control of dose optimization and calculation',...
    'CTV'                                              ,  'Clinical Target Volume (as defined in ICRU50)',...
    'DOSE_REGION'                             ,  'ROI to be used as a dose reference',...
    'EXTERNAL'                                    ,  'external patient contour',...
    'FIXATION'                                     ,  'external patient fixation or immobilisation device',...
    'GTV'                                              ,  'Gross Tumor Volume (as defined in ICRU50)',...
    'IRRAD_VOLUME'                            ,  'Irradiated Volume (as defined in ICRU50)',...
    'ISOCENTER'                                  ,  'treatment isocenter to be used for external beam therapy',...
    'MARKER'                                       ,  'patient marker or marker on a localizer',...
    'ORGAN'                                         ,  'patient organ',...
    'PTV'                                               ,  'Planning Target Volume (as defined in ICRU50)',...
    'REGISTRATION'                             ,  'registration ROI',...
    'SUPPORT'                                      ,  'external patient support device',...
    'TREATED_VOLUME'                        ,  'Treated Volume (as defined in ICRU50)'...
);


classdef MrCopyData < handle
    % Provides a common clone-method for all object classes, plus
    % generalized find, compare and print-capabilities
    %
    % based on a posting by Volkmar Glauche
    % http://www.mathworks.com/matlabcentral/fileexchange/22965-clone-handle-object-using-matlab-oop
    %
    % heavily modified and extended by Lars Kasper and Saskia Klein

    % Author:   Saskia Klein & Lars Kasper
    % Created:  2010-04-15
    % 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/>.
    %

    properties
    end
    methods
        function [this, unusedArgs] = MrCopyData(varargin)
            % Constructor for MrCopyData
            % either
            %
            %   this = MrCopyData for object with default values
            %
            %   OR
            %
            %   this = MrCopyData('empty') to create an object with all
            %   values set to [];
            %
            %   OR
            %   this = MrCopyData('param_name1', param_value1, 'param_name2', param_value2 )
            %          set of parameter names and values given, e.g.
            %          MrCopyData('dyn', 1)
            unusedArgs = {};
            if nargin
                if strcmpi(varargin{1}, 'empty')
                    this.clear();
                else
                    for cnt = 1:nargin/2 % save them to object properties
                        if isprop(this, varargin{2*cnt-1})
                        this.(varargin{2*cnt-1}) = varargin{2*cnt};
                        else % return unused props in a struct
                            unusedArgs = [unusedArgs, varargin(2*cnt-1:2*cnt)];
                        end
                    end
                end
            end
        end
    end
end


function num = cpu_cores()
    num = feature('numcores');
end


function loadDirs()
	% Forces all directories to be loaded, including external programs normally not loaded.
	% Biafra Ahanonu
	% started: 2020.05.09 [18:39:52]
	% inputs
		%
	% outputs
		%

	% changelog
		%
	% TODO
		%

	%========================
	% DESCRIPTION
	% options.exampleOption = '';
	% get options
	% options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	try
		ciapkg.loadBatchFxns;
	catch err
		disp(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		disp(repmat('@',1,7))
	end
end


function [success] = example_downloadTestData(varargin)
	% Downloads CIAtah example test data from online into data folder.
	% Biafra Ahanonu
	% started: September 2018
	% inputs
		%
	% outputs
		%

	% changelog
		% 2019.09.16 [13:03:33] - Added three new imaging sessions to use for cross-day alignment and made downloading more generalized.
		% 2020.09.14 [13:17:57] - Added example two-photon dataset.
		% 2021.02.02 [11:25:34] - Function now calls data directory via standardized ciapkg.getDirPkg('data') to avoid placing data in incorrect folder.
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
		% 2022.11.07 [19:09:38] - Update links from Stanford to UCSF box (Stanford migrating away from Box, links are dead).
	% TODO
		% Switch Box downloads to Google Drive due to Stanford phase out.

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	%========================
	options.downloadPreprocessed = 0;
	% Download extra files
	options.downloadExtraFiles = 1;
	% Binary: 1 = download meta data files.
	options.downloadMeta = 0;
	% Directory where download folder goes
	options.dataDir = ciapkg.getDirPkg('data');
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	try
		success = 0;
		downloadList = {};
			% downloadList{end+1}.folderName
			% downloadList{end}.fileName
			% downloadList{end}.fileUrl
			% downloadList{end}.metaFile

		downloadList{end+1}.folderName = '2014_04_01_p203_m19_check01';
		downloadList{end}.fileName = 'concat_recording_20140401_180333.h5';
			% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/jmld9o9s0oemvn6oionr3lf9lwobqk9l.h5';
		downloadList{end}.fileUrl = 'https://ucsf.box.com/shared/static/dtdwpr4xjs1u67dv30qnhu7arf889ysr.h5';

		if options.downloadExtraFiles==1
			[downloadList] = localfxn_downloadExtra(downloadList);
		end

		nFiles = length(downloadList);

		for fileNo = 1:nFiles
			fileInfo = downloadList{fileNo};
			rawSavePathDownload = [options.dataDir filesep fileInfo.folderName];
			if ~exist(rawSavePathDownload,'dir');mkdir(rawSavePathDownload);fprintf('Made folder: %s\n',rawSavePathDownload);end

			rawSavePathDownload = [rawSavePathDownload filesep fileInfo.fileName];
			if exist(rawSavePathDownload,'file')~=2
				fprintf('Downloading file to %s\n',rawSavePathDownload)
				websave(rawSavePathDownload,fileInfo.fileUrl);
			else
				fprintf('Already downloaded %s\n',rawSavePathDownload)
			end

			if options.downloadMeta==1
				rawSavePathDownload = [rawSavePathDownload filesep fileInfo.metaFile];
				if exist(rawSavePathDownload,'file')~=2
					fprintf('Downloading file to %s\n',rawSavePathDownload)
					websave(rawSavePathDownload,fileInfo.metaFile);
				else
					fprintf('Already downloaded %s\n',rawSavePathDownload)
				end
			end
		end

		if options.downloadPreprocessed==1
			rawSavePathDownload = [options.dataDir filesep '2014_04_01_p203_m19_check01']
			if ~exist(rawSavePathDownload,'dir');mkdir(rawSavePathDownload);fprintf('Made folder: %s',rawSavePathDownload);end

			rawSavePathDownload = [rawSavePathDownload filesep '2014_04_01_p203_m19_check01_turboreg_crop_dfof_downsampleTime_1.h5'];
			if exist(rawSavePathDownload,'file')~=2
				fprintf('Downloading file to %s\n',rawSavePathDownload)
				websave(rawSavePathDownload,'https://stanford.box.com/shared/static/0zasceqd7b9ea6pa4rsgx1ag1mpjwmrf.h5');
			end

			rawSavePathDownload = [options.dataDir filesep '2014_04_01_p203_m19_check01' filesep '2014_04_01_p203_m19_check01_turboreg_crop_dfof_1.h5'];
			if exist(rawSavePathDownload,'file')~=2
				fprintf('Downloading file to %s\n',rawSavePathDownload)
				websave(rawSavePathDownload,'https://stanford.box.com/shared/static/azabf70oky7vriek48pb98jt2c5upj5i.h5');
			end
		end

		success = 1;
	catch err
		success = 0;
		disp('Check internet connection or download files manually, see *data* folder.')
		display(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		display(repmat('@',1,7))
	end
end

function [downloadList] = localfxn_downloadExtra(downloadList)
	% Download additional files

	downloadList{end+1}.folderName = ['batch' filesep '2014_08_05_p104_m19_PAV08'];
	downloadList{end}.fileName = 'concat_recording_20140805_162046.h5';
		% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/iv3v3iqmji7fd5lvdcere8q6tlb008vb.h5';
	downloadList{end}.fileUrl = 'https://ucsf.box.com/shared/static/6uhqtff2qlgsrjqpt81iz5i7xbu5hfkv.h5';

	downloadList{end+1}.folderName = ['batch' filesep '2014_08_06_p104_m19_PAV09'];
	downloadList{end}.fileName = 'concat_recording_20140806_103546.h5';
		% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/vyj69a7u2ay9uva9fbsyp34d8kvcvclw.h5';
	downloadList{end}.fileUrl = 'https://ucsf.box.com/shared/static/dh13zgf3ecsd5weolfuln4as09f6v4dg.h5';

	downloadList{end+1}.folderName = ['batch' filesep '2014_08_07_p104_m19_PAV10'];
	downloadList{end}.fileName = 'concat_recording_20140807_102507.h5';
		% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/xmhgqx3atceq8f0zwqdctegiqo2d71su.h5';
	downloadList{end}.fileUrl = 'https://ucsf.box.com/shared/static/m2wvus76erqrng7bp13q7s3tlr727dgy.h5';

	downloadList{end+1}.folderName = ['twoPhoton' filesep '2017_04_16_p485_m487_runningWheel02'];
	downloadList{end}.fileName = 'concat_recording_20140807_102507.h5';
		% downloadList{end}.fileUrl = 'https://ucsf.box.com/shared/static/y71zhjejy7k90ov2o8wnbupi20o4q0nq.h5';
	downloadList{end}.fileUrl = 'https://ucsf.box.com/shared/static/y71zhjejy7k90ov2o8wnbupi20o4q0nq.h5';

	% downloadList{end+1}.folderName = ['batch' filesep '2014_07_31_p104_m80_PAV03'];
	% downloadList{end}.fileName = 'concat_recording_20140731_105559.h5';
	% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/ddgy2zq3as9l3paifd1hltpojk93x9oa.h5';
	% % downloadList{end}.metaFile = 'https://stanford.box.com/shared/static/6qs3dt593uud314ins8qnxrnuj9sdm87.txt';

	% downloadList{end+1}.folderName = ['batch' filesep '2014_08_05_p104_m80_PAV04'];
	% downloadList{end}.fileName = 'concat_recording_20140805_180816.h5';
	% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/psm56avve4gt3tquc88r7fri2xda9woe.h5';
	% % downloadList{end}.metaFile = 'https://stanford.box.com/shared/static/gf7agxqvp3ks0mr0ovy54t067agdp4tf.txt';

	% downloadList{end+1}.folderName = ['batch' filesep '2014_08_06_p104_m80_PAV05'];
	% downloadList{end}.fileName = 'concat_recording_20140806_104210.h5';
	% downloadList{end}.fileUrl = 'https://stanford.box.com/shared/static/ae8qcmkxcv8ax7g1yfs9qjp010gqyip3.h5';
	% % downloadList{end}.metaFile = 'https://stanford.box.com/shared/static/ja18hyade4jmh6czw0vxpxosiu3i9j9e.txt';
end


%   CLASS File_Rinex
% =========================================================================
%
% DESCRIPTION
%   Class to store file_paths for RINEX files
%
% EXAMPLE
%   fr = File_Rinex(file_name, verbosity_lev);
%
% FOR A LIST OF CONSTANTS and METHODS use doc File_Rinex

%--------------------------------------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:        Andrea Gatti
%  Contributors:      Andrea Gatti, Giulio Tagliaferro
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%    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/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

classdef File_Rinex < Exportable

    properties (SetAccess = protected, GetAccess = protected)
        log = Logger.getInstance(); % Handler to the log object
    end

    properties (SetAccess = protected, GetAccess = public)
        is_valid = false;                            % flag, if true it means that the object contains at least one valid rinex file
        base_dir = {'../data/project/default_DD/RINEX/'};           % directory containing all the files
        file_name_list = {'yamatogawa_rover', 'yamatogawa_master'}; % file names (they can be multiple files for different days)
        ext = {'.obs', '.obs'};                                     % file names extension (they can be multiple files for different days)
        is_valid_list = false(1, 2);                 % for each element of file_name_list check the validity of the file

        is_composed = false;                         % when this flag is set, it means that the file_name depends on variables such as DOY DOW YYYY SSSS MM ecc...

        trck_availability                            % boolean to get tracking availabilty the tracking are in Core_sky.group_delays_flags

        marker_name = {};                            % marker name of the files
        coo = Coordinates.fromXYZ([0 0 0])           % receiver coordinates
        first_epoch = GPS_Time();                    % first epoch stored in the RINEX (updated after checkValidity)
        last_epoch = GPS_Time();                     % last epoch stored in the RINEX (updated after checkValidity)

        verbosity_lev = 0;                           % Level of verbosity  0 = all messages, see Logger for more information (if negative) no messages at all

        eoh = 0;                                     % end of header line - store the last line of the header
    end

    properties (SetAccess = private, GetAccess = private)
        id_date = 2:28;                              % Last character containing the 6 fields of the date (in case of 4digits year), it the pends on the type of rinex files (28 -> OBS RINEX 3)
    end

    methods
        function this = File_Rinex(file_name, verbosity_lev, flag_header_only)
            % Creator of file_rinex simple parser
            %
            % INPUT
            %   file_name        file path (can be a cell array)
            %   verbosity_lev    verbosity level for logging purposes
            %                    (default = 100)
            %   flag_header_only if true and first/last epochs are not found
            %                    in header do not search them in the file
            %                    (default = false)
            %                    this option may leave the obj corrupted (use with care)
            %
            % SYNTAX
            %   File_Rinex (file_name , verbosity_level, flag_header_only)
            %
            if nargin < 3 || isempty(flag_header_only)
                flag_header_only = false;
            end

            if nargin == 0
                % Empty File_Rinex;
            else
                % fill the path with the imported file names
                if ~iscellstr(file_name)
                    file_name = {file_name};
                end
                this.file_name_list = {};
                this.ext = {};
                if nargin == 1 || isempty(verbosity_lev)
                    verbosity_lev = 100;
                end

                if verbosity_lev < 50 && numel(file_name) > 20
                    w_bar = Go_Wait_Bar.getInstance(numel(file_name), 'Checking rinex files');
                    w_bar.createNewBar
                    for f = 1 : numel(file_name)
                        [this.base_dir{f}, this.file_name_list{f}, this.ext{f}] = fileparts(checkPath(file_name{f}));
                        w_bar.go();
                    end
                    w_bar.close();
                else
                    for f = 1 : numel(file_name)
                        [this.base_dir{f}, this.file_name_list{f}, this.ext{f}] = fileparts(checkPath(file_name{f}));
                    end
                end

                if nargin >= 2
                    this.verbosity_lev = verbosity_lev;
                end

                this.checkValidity(flag_header_only);
            end
        end

        function copy = getCopy(this)
            for r = numel(this):-1:1
                copy(r) = File_Rinex();
                copy(r).copyFrom(this(r));
            end
        end

        function copyFrom(this, file_rinex, id)
            % Copy from an object of the same type
            %
            % SYNTAX
            %   this.copyFrom(time)
            if nargin < 3 || isempty(id)
                id = 1 : numel(file_rinex.file_name_list);
            end
            % Get id within coo and time limits objects
            valid_lid = false(size(file_rinex.is_valid_list));
            valid_lid(id) = true;
            valid_lid = valid_lid & file_rinex.is_valid_list;
            valid_id = cumsum(file_rinex.is_valid_list);
            valid_id = valid_id(valid_lid);
            % Extract fields to copy
            this.is_valid       = all(file_rinex.is_valid_list(id));
            this.base_dir       = file_rinex.base_dir(id);
            this.file_name_list = file_rinex.file_name_list(id);
            this.ext            = file_rinex.ext(id);
            this.is_valid_list  = file_rinex.is_valid_list(id);
            this.is_composed    = file_rinex.is_composed;
            this.first_epoch    = file_rinex.first_epoch.getEpoch(valid_id);
            this.last_epoch     = file_rinex.last_epoch.getEpoch(valid_id);
            this.verbosity_lev  = file_rinex.verbosity_lev;
            this.eoh            = file_rinex.eoh(id);
            this.coo            = file_rinex.coo.getCopy();
        end
    end

    methods
        function checkValidity(this, flag_header_only)
            % Update the status of validity of the files here pointed
            % Buffered read
            %
            % SYNTAX
            %   this.checkValidity();

            % pre allocate
            this.is_valid_list = false(1, numel(this.file_name_list));
            this.eoh = zeros(1, numel(this.file_name_list));
            this.first_epoch = GPS_Time();
            this.last_epoch = GPS_Time();
            this.coo = Coordinates;           % receiver coordinates
            log = Core.getLogger;
            % for each file present in the list
            for f = 1 : numel(this.file_name_list)
                marker_name = '';
                full_path = fullfile(this.base_dir{f}, [this.file_name_list{f} this.ext{f}]);

                % try to find the first and the last epoch stored in the file
                try
                    %%
                    this.is_valid_list(f) = true;
                    fid = fopen(full_path, 'rt');
                    if fid < 0
                        log.addError(['"' this.file_name_list{f} this.ext{f} '" appears to be missing'], this.verbosity_lev);
                        this.is_valid_list(f) = false;
                    else
                        buf = fread(fid, 1e4, '*char')';
                        if length(buf) > 65 && strcmp(buf(61:64), 'CRIN')
                            log.addError(sprintf('Check the following file, it seems to be hatanaka compressed\nDecompress "%s"', full_path));
                            this.is_valid_list(f) = false;
                            fclose(fid);
                        else
                            l = 1;
                            % read by buffer 10k char at a time
                            % fseek(fid, 0, 'bof'); buf = fread(fid, 1e4, '*char')';

                            % detect windows carriage return
                            if ~isempty(find(buf(1:min(1000,numel(buf))) == 13, 1, 'first'))
                                has_cr = true;  % The file has carriage return - I hate you Bill!
                            else
                                has_cr = false;  % The file is UNIX standard
                            end

                            % get new line separators
                            nl = regexp(buf, '\n')';
                            if nl(end) <  (numel(buf) - double(has_cr))
                                nl = [nl; numel(buf)];
                            end
                            lim = [[1; nl(1 : end - 1) + 1] (nl - 1 - double(has_cr))];
                            lim = [lim lim(:,2) - lim(:,1)];
                            while lim(end,3) < 3
                                lim(end,:) = [];
                            end

                            % Check for meteo rinex
                            flag_met = buf(21) == 'M';

                            line = buf(lim(l,1) : lim(l,2));
                            date_start = '';
                            trck_name = Core_Sky.group_delays_flags;
                            trck_availability = false(size(trck_name,1),1);
                            cur_trck_sys = '';
                            date_stop = '';
                            coo = '';
                            eof = false;
                            par_to_find = 4;
                            %while (par_to_find > 0) && isempty(strfind(line,'END OF HEADER')) && not(eof)
                            while ~((length(line) > 61) && (line(61) == 'E')) && not(eof)
                                l = l + 1;
                                if l >= size(lim, 1)
                                    % out of buffer
                                    % read block:
                                    buf = [buf char(fread(fid, 1e4))'];

                                    % get new line separators
                                    nl = regexp(buf, '\n')';
                                    if nl(end) <  (numel(buf) - double(has_cr))
                                        nl = [nl; numel(buf)];
                                    end
                                    lim = [[1; nl(1 : end - 1) + 1] (nl - 1 - double(has_cr))];
                                    lim = [lim lim(:,2) - lim(:,1)];
                                    while lim(end,3) < 3
                                        lim(end,:) = [];
                                    end
                                end
                                if l > size(lim, 1)
                                    eof = true;
                                else
                                    line = buf(lim(l,1) : lim(l,2));
                                    if par_to_find > 0
                                        if numel(line) >= 70 && isempty(marker_name) && line(64) == 'K' % read marker_name
                                            marker_name = strtrim(regexp(line, '.*(?=MARKER NAME)', 'match', 'once'));
                                            par_to_find = par_to_find - 1;
                                        end
                                        if numel(line) >= 76
                                            if line(61) == 'T'
                                                %tmp = regexp(line, '.*(?=GPS         TIME OF FIRST OBS)', 'match', 'once');
                                                if line(69) == 'F'
                                                    date_start = strtrim(line(1:48));
                                                    par_to_find = par_to_find - 1;
                                                elseif line(69) == 'L'
                                                    %tmp = regexp(line, '.*(?=GPS         TIME OF LAST OBS)', 'match', 'once');
                                                    date_stop = strtrim(line(1:48));
                                                    par_to_find = par_to_find - 1;
                                                end
                                            elseif line(76) == 'Y' || (numel(line) >= 79 && line(79) == 'V') %  SYS / # / OBS TYPES || # / TYPES OF OBSERV
                                                if line(1) ~= ' '
                                                    cur_trck_sys = line(1);
                                                else
                                                    cur_trck_sys = ' ';
                                                end
                                                trcks = strsplit(line(8:60),' ');
                                                for t = trcks
                                                    if ~isempty(t{1})
                                                        t = t{1};
                                                        t = [t repmat(' ',1,3-length(t))];
                                                        idx = trck_name(:,1) == cur_trck_sys & trck_name(:,2) == t(1) & trck_name(:,3) == t(2) & trck_name(:,4) == t(3);
                                                        trck_availability(idx) = true;
                                                        if strcmp(t,'P1 ')% rinex 2 codes does not specify contellation, assuming GPS
                                                            trck_availability(strLineMatch(trck_name,'GC1W')) = true;
                                                        elseif strcmp(t,'P2 ')
                                                            trck_availability(strLineMatch(trck_name,'GC2W')) = true;
                                                        elseif strcmp(t,'C1 ')
                                                            trck_availability(strLineMatch(trck_name,'GC1C')) = true;
                                                        elseif strcmp(t,'C2 ')
                                                            trck_availability(strLineMatch(trck_name,'GC2C')) = true;
                                                        end
                                                    end
                                                end
                                            elseif line(66) == 'Y' % "# / TYPES OF OBSERV"
                                                % temporary solution for RINEX 2
                                                % to be improved
                                                trcks = strsplit(line(8:60),' ');
                                                for cur_trck_sys = Core.getConstellationCollector.getActiveSysChar
                                                    for t = trcks
                                                        if ~isempty(t{1})
                                                            t = t{1};
                                                            if numel(t) == 2 % correct missing character for RINEX 2
                                                                % It should be done multi constellation
                                                                % GPS C1 -> C1C
                                                                % GPS C2 -> C2C
                                                                t = [t 'C'];
                                                            end
                                                            idx = trck_name(:,1) == cur_trck_sys & trck_name(:,2) == t(1) & trck_name(:,3) == t(2) & trck_name(:,4) == t(3);
                                                            trck_availability(idx) = true;
                                                        end
                                                    end
                                                end
                                            else
                                                %tmp = regexp(line, '.*(?=APPROX POSITION XYZ)', 'match', 'once');
                                                % character to recognize approximate position for met file: 'E' => sensor pos
                                                % character to recognize approximate position for met file: 'P' => approx position
                                                pos_char = iif(flag_met, 'E', 'P');
                                                if line(62) == pos_char % APPROXIMATE POSITION
                                                    coo = strtrim(line(1:43));
                                                    par_to_find = par_to_find - 1;
                                                end
                                            end
                                        end
                                    end
                                end
                            end

                            eoh = l; %end of header
                            if ~isempty(trck_availability)
                                this.trck_availability = trck_availability;
                            end

                            % If I did not found date of start and date of end in the file header
                            % Try to read them
                            if ~isempty(date_start)
                                this.first_epoch.addEpoch(date_start, [], true);
                            else
                                l = l + 1;
                                if l > size(lim, 1)
                                    % out of buffer
                                    % read block:
                                    buf = [buf char(fread(fid, 1e4))'];

                                    % get new line separators
                                    nl = regexp(buf, '\n')';
                                    if nl(end) <  (numel(buf) - double(has_cr))
                                        nl = [nl; numel(buf)];
                                    end
                                    lim = [[1; nl(1 : end - 1) + 1] (nl - 1 - double(has_cr))];
                                    lim = [lim lim(:,2) - lim(:,1)];
                                    while lim(end,3) < 3
                                        lim(end,:) = [];
                                    end
                                end
                                if l <= size(lim,1)
                                    epoch_line = buf(lim(l,1) : lim(l,2));
                                    % try to guess the time format
                                    [id_start, id_stop] = regexp(epoch_line, '[.0-9]*');
                                    this.id_date = id_start(1) : id_stop(6); % save first and last char limits of the date in the line -> suppose it composed by 6 fields
                                    this.first_epoch.addEpoch(epoch_line(this.id_date), [], true);
                                else
                                    error(sprintf('"%s" seems corrupted', full_path));
                                end
                            end
                            log.addStatusOk(['"' this.file_name_list{f} this.ext{f} '" appears to be a valid RINEX'], this.verbosity_lev);
                            log.addMessage(sprintf('        first epoch found at: %s', this.first_epoch.last.toString()), this.verbosity_lev);

                            if ~isempty(date_stop)
                                this.last_epoch.addEpoch(date_stop, [], true);
                                log.addMessage(sprintf('        last  epoch found at: %s', this.last_epoch.last.toString()), this.verbosity_lev);
                            else
                                if flag_header_only
                                    log.addWarning('Last epoch not found in header, search in file is not enabled\nThe last epoch has not been saved within the object', this.verbosity_lev);
                                    if ~isempty(this.first_epoch.last.getMatlabTime)
                                        this.last_epoch.addEpoch(this.first_epoch.last.getMatlabTime, [], true);
                                    end
                                else
                                    % go to the end of the file to search for the last epoch
                                    % to be sure to find at least one line containing a valid epoch, go to the end of the file minus 10000 characters
                                    fseek(fid, 0, 'eof');
                                    f_size = ftell(fid);
                                    fseek(fid, - min(1e4, f_size - 1), 'eof');
                                    buf = fread(fid, min(1e4, f_size - 1),'*char')';

                                    % Start searching for a valid epoch
                                    time = [];
                                    loop_n = 1;
                                    file_ko = false;
                                    while isempty(time) && ~isempty(buf) && ~file_ko
                                        if ~isempty(find(buf(1:min(1000,numel(buf))) == 13, 1, 'first'))
                                            has_cr = true;  % The file has carriage return - I hate you Bill!
                                        else
                                            has_cr = false;  % The file is UNIX standard
                                        end

                                        % get new line separators
                                        nl = regexp(buf, '\n')';
                                        if isempty(nl)
                                            file_ko = true;
                                        else
                                            if nl(end) <  (numel(buf) - double(has_cr))
                                                nl = [nl; numel(buf)];
                                            end
                                            lim = [[1; nl(1 : end - 1) + 1] (nl - 1 - double(has_cr))];
                                            lim = [lim lim(:,2) - lim(:,1)];
                                            lim(lim(:,3) < this.id_date(end), :) = [];

                                            l = size(lim, 1);
                                            while (l >= 1) && isempty(time)
                                                line = buf(lim(l,1) : lim(l,2));
                                                if ~isempty(regexp(line(1:15),'( [0-9]{1,4} [ 0-9]{1}[0-9]{1} [ 0-9]{1}[0-9]{1})', 'once'))
                                                    % Check that the read epoch is within 30 days from the first epoch
                                                    % (if it's further in time it's probably a misleading false epoch line)
                                                    time = GPS_Time(line(this.id_date), [], true);
                                                end
                                                l = l - 1;
                                            end
                                            if ~file_ko
                                                if isempty(time) || time.isEmpty()
                                                    loop_n = loop_n + 1;
                                                    fseek(fid, loop_n * -10000, 'eof'); % If no valid time have been found try to go back more...
                                                    buf = fread(fid, 10000, '*char')';
                                                end
                                            end
                                        end
                                    end
                                    if file_ko
                                        log.addError(sprintf('Check the following file, it seems to be corrupted\nPath: "%s"', full_path));
                                        this.first_epoch = this.first_epoch.getEpoch(1 : this.last_epoch.length);
                                        this.is_valid_list(f) = false;
                                    elseif isempty(time)
                                        log.addError(sprintf('Check the following file, it seems to be empty\nPath: "%s"', full_path));
                                        this.first_epoch = this.first_epoch.getEpoch(1 : this.last_epoch.length);
                                        this.is_valid_list(f) = false;
                                    else
                                        this.last_epoch.append(time);
                                        log.addMessage(sprintf('        last  epoch found at: %s', this.last_epoch.last.toString()), this.verbosity_lev);
                                    end
                                end
                            end

                            if this.is_valid_list(f)
                                if ~isempty(coo)
                                    this.coo.append(Coordinates.fromStringXYZ(coo));
                                else
                                    this.coo.append(Coordinates.fromXYZ([0 0 0]));
                                end
                                this.eoh(f) = eoh;
                            end

                            fclose(fid);
                        end
                    end
                catch ex
                    log.addWarning(['"' this.file_name_list{f} this.ext{f} '" appears to be a corrupted RINEX file or missing'], this.verbosity_lev);
                    %Core_Utils.printEx(ex);
                    this.is_valid_list(f) = false;
                    fclose(fid);
                end
                % store marker_name
                if isempty(marker_name)
                    this.marker_name{f} = upper(this.file_name_list{f}(1:min(4, numel(this.file_name_list{f}))));
                else
                    this.marker_name{f} = marker_name;
                end
            end
            this.is_valid = all(this.is_valid_list);
            if (~this.is_valid)
                log.addWarning('Some or all the RINEX files are corrupted or missing!!!', this.verbosity_lev);
            end
        end

        function checkValidityUnbuffered(this, flag_header_only)
            % Update the status of validity of the files here pointed
            % Unbuffered read => read line by line (old approach)
            %
            % SYNTAX
            %   this.checkValidity();

            % pre allocate
            this.is_valid_list = false(1, numel(this.file_name_list));
            this.eoh = zeros(1, numel(this.file_name_list));
            this.first_epoch = GPS_Time();
            this.last_epoch = GPS_Time();
            this.coo = Coordinates;           % receiver coordinates
            % for each file present in the list
            for f = 1 : numel(this.file_name_list)
                marker_name = '';

                % try to find the first and the last epoch stored in the file
                try
                    %%
                    fid = fopen(fullfile(this.base_dir{f}, [this.file_name_list{f} this.ext{f}]));
                    if fid < 0
                        this.log.addError(['"' this.file_name_list{f} this.ext{f} '" appears to be missing'], this.verbosity_lev);
                        this.is_valid_list(f) = false;
                    else
                        l = 1;
                        line = fgetl(fid);
                        date_start = '';
                        date_stop = '';
                        coo = '';
                        par_to_find = 4;
                        while par_to_find > 0 && isempty(strfind(line,'END OF HEADER')) && ischar(line) %#ok<*STREMP>
                            l = l + 1;
                            line = fgetl(fid);
                            if numel(line) > 70 && isempty(marker_name) && line(64) == 'K' % read marker_name
                                marker_name = strtrim(regexp(line, '.*(?=MARKER NAME)', 'match', 'once'));
                                par_to_find = par_to_find - 1;
                            end
                            if numel(line) > 76
                                if line(61) == 'T'
                                    %tmp = regexp(line, '.*(?=GPS         TIME OF FIRST OBS)', 'match', 'once');
                                    if line(69) == 'F'
                                        date_start = strtrim(line(1:48));
                                        par_to_find = par_to_find - 1;
                                    elseif line(69) == 'L'
                                        %tmp = regexp(line, '.*(?=GPS         TIME OF LAST OBS)', 'match', 'once');
                                        date_stop = strtrim(line(1:48));
                                        par_to_find = par_to_find - 1;
                                    end
                                else
                                    %tmp = regexp(line, '.*(?=APPROX POSITION XYZ)', 'match', 'once');
                                    if line(62) == 'P' % APPROXIMATE POSITION
                                        coo = strtrim(line(1:60));
                                        par_to_find = par_to_find - 1;
                                    end
                                end
                            end
                        end

                        if ~isempty(coo)
                            this.coo.append(Coordinates.fromStringXYZ(coo));
                        else
                            this.coo.append(Coordinates.fromXYZ([0 0 0]));
                        end
                        this.eoh(f) = l;

                        % If I did not found date of start and date of end in the file header
                        % Try to read them
                        if ~isempty(date_start)
                            this.first_epoch.addEpoch(date_start, [], true);
                        else
                            epoch_line = fgetl(fid);
                            if epoch_line == -1
                                error('Empty file');
                            end
                            % try to guess the time format
                            [id_start, id_stop] = regexp(epoch_line, '[.0-9]*');
                            this.id_date = id_start(1) : id_stop(6); % save first and last char limits of the date in the line -> suppose it composed by 6 fields

                            this.first_epoch.addEpoch(epoch_line(this.id_date), [], true);
                        end
                        this.log.addStatusOk(['"' this.file_name_list{f} this.ext{f} '" appears to be a valid RINEX'], this.verbosity_lev);
                        this.log.addMessage(sprintf('        first epoch found at: %s', this.first_epoch.last.toString()), this.verbosity_lev);

                        if ~isempty(date_stop)
                            this.last_epoch.addEpoch(date_stop, [], true);
                            this.log.addMessage(sprintf('        last  epoch found at: %s', this.last_epoch.last.toString()), this.verbosity_lev);
                        else
                            if flag_header_only
                                this.log.addWarning('Last epoch not found in header, search in file is not enabled\nThe last epoch has not been saved within the  object', this.verbosity_lev);
                            else
                                % go to the end of the file to search for the last epoch
                                % to be sure to find at least one line containing a valid epoch, go to the end of the file minus 5000 characters
                                fseek(fid, -10000, 'eof');
                                txt = fread(fid, 10000,'*char')';

                                % Start searching for a valid epoch
                                time = [];
                                loop_n = 1;
                                while isempty(time) && ~isempty(txt)
                                    if ~isempty(find(txt(1:min(1000,numel(txt))) == 13, 1, 'first'))
                                        has_cr = true;  % The file has carriage return - I hate you Bill!
                                    else
                                        has_cr = false;  % The file is UNIX standard
                                    end

                                    % get new line separators
                                    nl = regexp(txt, '\n')';
                                    if nl(end) <  (numel(txt) - double(has_cr))
                                        nl = [nl; numel(txt)];
                                    end
                                    lim = [[1; nl(1 : end - 1) + 1] (nl - 1 - double(has_cr))];
                                    lim = [lim lim(:,2) - lim(:,1)];
                                    lim(lim(:,3) < 20, :) = [];

                                    l = size(lim, 1);
                                    while (l >= 1) && isempty(time)
                                        line = txt(lim(l,1) : lim(l,2));
                                        if ~isempty(regexp(line(1:15),'( [0-9]{1,4} [ 0-9]{1}[0-9]{1} [ 0-9]{1}[0-9]{1})', 'once'))
                                            % Check that the read epoch is within 30 days from the first epoch
                                            % (if it's further in time it's probably a misleading false epoch line)
                                            time = GPS_Time(line(this.id_date), [], true);
                                        end
                                        l = l - 1;
                                    end
                                    if isempty(time) || time.isEmpty()
                                        loop_n = loop_n + 1;
                                        fseek(fid, loop_n * -10000, 'eof'); % If no valid time have been found try to go back more...
                                        txt = fread(fid, 10000,'*char')';
                                    end
                                end
                                this.last_epoch.append(time);
                                this.log.addMessage(sprintf('        last  epoch found at: %s', this.last_epoch.last.toString()), this.verbosity_lev);
                            end
                        end
                        fclose(fid);
                        this.is_valid_list(f) = true;
                    end
                catch ex
                    this.log.addWarning(['"' this.file_name_list{f} this.ext{f} '" appears to be a corrupted RINEX file'], this.verbosity_lev);
                    this.is_valid_list(f) = false;
                end

                % store marker_name
                if isempty(marker_name)
                    this.marker_name{f} = upper(this.file_name_list{f}(1:min(4, numel(this.file_name_list{f}))));
                else
                    this.marker_name{f} = marker_name;
                end
            end
            this.is_valid = all(this.is_valid_list);
            if (~this.is_valid)
                this.log.addWarning('Some or all the RINEX files are corrupted or missing!!!', this.verbosity_lev);
            end
        end

        function checkCoordinates(rin_list, force_delete)
            flag_show = false;
            dist_lim = 1; % [m]
            for r = 1 : numel(rin_list)
                xyz = rin_list(r).coo.xyz;
                id_ko = (all(xyz == 0,2));
                xyz(id_ko,:) = [];
                if not(isempty(xyz))
                    xyz = bsxfun(@minus, xyz, median(xyz, 1, 'omitnan'));
                    dist = 1e-3 * (sqrt(xyz(:,1).^2 + xyz(:,2).^2 + xyz(:,3).^2)); % [km]
                    if any(dist > dist_lim)
                        % This set of file RINEX are from a receiver that have been moved
                        % for more than 100 meters

                        marker_name = rin_list(r).marker_name{find(rin_list(r).is_valid_list, 1, 'first')};
                        if flag_show
                            rin_list(r).coo.showPositionENU
                            title(marker_name);
                        end

                        log = Core.getLogger;
                        log.addWarning(sprintf('The RINEX of the station %s are anomalous. The antenna could have been moved or the files are from different omonimous receivers\n > MAX detected distance: %.3g [km]\n\nThe following files will be ignored:', marker_name, max(dist)));
                        id_coo = find(not(id_ko));
                        id_valid = find(rin_list(r).is_valid_list);
                        id_ko = find(dist > dist_lim)';
                        for i = id_ko
                            file_name = fullfile(rin_list(r).base_dir{id_valid(id_coo(i))}, [rin_list(r).file_name_list{id_valid(id_coo(i))}, rin_list(r).ext{id_valid(id_coo(i))}]);
                            if nargin == 2 && force_delete
                                delete(file_name);
                            end
                            log.addMonoMessage(log.indent(sprintf('- %s', file_name)));
                        end
                        rin_list(r).first_epoch.remEpoch(id_coo(id_ko));
                        rin_list(r).last_epoch.remEpoch(id_coo(id_ko));
                        rin_list(r).is_valid_list(id_valid(id_coo(id_ko))) = false;
                        rin_list(r).coo.rem(id_coo(id_ko));
                    end
                end
            end
        end

        function file_name = getFileName(this, file_number)
            % Get the full path of a file (if the object contains a list of files, the id can be specified)
            % SYNTAX: file_name = this.getFileName(<file_number = 1>)
            if nargin == 1
                file_number = 1;
            end
            file_name = fullfile(this.base_dir{file_number}, [this.file_name_list{file_number} this.ext{file_number}]);
        end

        function first_epoch = getFirstEpoch(this, session)
            % Get the first epoch of a session
            %
            % SYNTAX
            %   first_epoch = this.getFirstEpoch(session)
            if nargin == 1
                if any(this.is_valid_list)
                    first_epoch = this.first_epoch.getCopy;
                else
                    first_epoch = GPS_Time();
                end
            else
                if Core.getState.isRinexSession
                    if this.is_valid_list(session)
                        id_ss = cumsum(this.is_valid_list);
                        first_epoch = this.first_epoch.getEpoch(id_ss(session));
                    else
                        first_epoch = GPS_Time();
                    end
                else
                    first_epoch = this.state.getSessionLimits(session).first;
                end
            end
        end

        function last_epoch = getLastEpoch(this, session)
            % Get the last epoch of a session
            %
            % SYNTAX
            %   first_epoch = this.getFirstEpoch(session)
            if nargin == 1
                if any(this.is_valid_list)
                    last_epoch = this.last_epoch.getCopy;
                else
                    last_epoch = GPS_Time();
                end
            else
                if Core.getState.isRinexSession
                    if this.is_valid_list(session)
                        id_ss = cumsum(this.is_valid_list);
                        last_epoch = this.last_epoch.getEpoch(id_ss(session));
                    else
                        last_epoch = GPS_Time();
                    end
                else
                    last_epoch = this.state.getSessionLimits(session).last;
                end
            end
        end

        function line_num = getEOH(this, file_number)
            % Get the end of header line of a RINEX file (if the object contains a list of files, the id can be specified)
            % SYNTAX: line_num = this.getEOH(<file_number = 1>)
            if nargin == 1
                file_number = 1;
            end
            line_num = this.eoh(file_number);
        end

        function validity = isValid(this, file_number)
            % Get the validity of a RINEX file or the object (if the object contains a list of files, the id can be specified)
            % SYNTAX: validity = isValid(<file_number>)
            validity = false;
            for r = 1 : numel(this)

                if (nargin == 1)
                    validity = validity || any([this(r).is_valid_list]);
                else
                    if file_number <= numel(this(r).is_valid_list)
                        validity = validity || this(r).is_valid_list(file_number);
                    end
                end
            end
        end

        function keepFiles(this, date_start, date_stop)
            % keep only files contained in the two dates
            %
            % SYNTAX
            % this.keepFiles(date_start, date_stop)
            for r = 1 : numel(this)
                [in_bound] = Core_Utils.timeIntersect(this(r).first_epoch, this(r).last_epoch, date_start, date_stop);
                to_keep = this(r).is_valid_list;
                to_keep(to_keep) = in_bound;
                this(r).keep(to_keep);
            end
        end

        function has_obs = hasObsInSession(this, date_start, date_stop)
            % has observation in the two dates
            %
            % SYNTAX
            % this.keepFiles(date_start, date_stop)
            has_obs = false(numel(this),1);
            for r = 1 : numel(this)
                if this(r).isValid
                    in_bound = Core_Utils.timeIntersect(this(r).first_epoch, this(r).last_epoch, date_start, date_stop);
                    has_obs(r) = any(in_bound);
                end
            end
        end

        function keep(this,id)
            % keep only element specified by id
            %
            % SYNTAX
            % this.keep(id)
            this.base_dir = this.base_dir(id);
            this.file_name_list = this.file_name_list(id);
            this.ext = this.ext(id);
            this.eoh = this.eoh(id);
            this.first_epoch = this.first_epoch.getEpoch(id(this.is_valid_list));
            this.last_epoch  = this.last_epoch.getEpoch(id(this.is_valid_list));
            this.is_valid_list = this.is_valid_list(id);
        end

        function printMissingFiles(rin_list, flag_download)
            % Show all the files that seems to be missing for the
            % processing
            if nargin == 1
                flag_download = false;
            end
            clc
            fprintf('These files are missing or currupted\n')
            for r = 1: numel(rin_list)
                id_ko = find(not(rin_list(r).is_valid_list));
                for i = id_ko
                    file_name = [rin_list(r).file_name_list{i}, rin_list(r).ext{i}];
                    if not(flag_download)
                        fprintf('%s\n', file_name);
                    end
                    if numel(file_name) == 12 % it is a RINEX2 file name
                        % Extracting year and doy
                        year = 2000 + str2double(file_name(end-2:end-1));
                        doy = str2double(file_name(5:7));
                        if flag_download
                            str_cmd = sprintf('/usr/bin/python3 /home/gred/Repositories/goget/goGet.py download -m %s --year-doy %04d %03d -o %s --no-wait', rin_list(r).marker_name{i}, year, doy, [rin_list(r).base_dir{i} filesep]);
                            fprintf('%s\n', str_cmd);
                        end
                    end
                end

            end

        end

    end
end


function imdb = setupVoc(datasetDir, varargin)
% SETUPVOC    Setup PASCAL VOC data
%   IMDB = SETUPVOC(DATASETDIR, 'EDITION', '2007') setups the
%   PASCAL VOC 2007 data. This is similar to SETUPGENERIC(), but adapted
%   to the peculiarities of this dataset. In particular, the
%   difficult image flag and the fact that multiple labels apply to
%   each image are supported.
%
%   Note that only the PASCAL VOC 2007 data comes with test images
%   and labels. For the other editions, setting up the test images
%   cannot be automatized due to restrictions in the distribution.
%
%   See also: SETUPGENERIC().

% Author: Andrea Vedaldi

% Copyright (C) 2013 Andrea Vedaldi
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

opts.edition = '2007' ;
opts.autoDownload = true ;
opts.lite = false ;
opts = vl_argparse(opts, varargin) ;

switch opts.edition
  case '2007'
    urls = {'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2007/VOCtrainval_06-Nov-2007.tar', ...
            'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2007/VOCtest_06-Nov-2007.tar'} ;
  case '2008'
    urls = {'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2008/VOCtrainval_14-Jul-2008.tar'} ;
  case '2009'
    urls = {'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2009/VOCtrainval_11-May-2009.tar'} ;
  case '2010'
    urls = {'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2010/VOCtrainval_03-May-2010.tar'} ;
  case '2011'
    urls = {'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2011/VOCtrainval_25-May-2011.tar'} ;
  case '2012'
    urls = {'http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2012/VOCtrainval_11-May-2012.tar'} ;
  otherwise
    error('Unknown PASCAL VOC edition ''%s''.', opts.edition) ;
end

% Download and unpack
vl_xmkdir(datasetDir) ;
if exist(fullfile(datasetDir, ['VOC' opts.edition], 'Annotations'))
  % ok
elseif exist(fullfile(datasetDir, 'VOCdevkit', ['VOC' opts.edition], 'Annotations'))
  % ok
  datasetDir = fullfile(datasetDir, 'VOCdevkit') ;
elseif opts.autoDownload
  for i = 1:length(urls)
    fprintf('Downloading VOC data ''%s'' to ''%s''. This will take a while.', urls{i}, datasetDir) ;
    untar(urls{i}, datasetDir) ;
  end
  datasetDir = fullfile(datasetDir, 'VOCdevkit') ;
else
  error('VOC data not found in %s', datasetDir) ;
end

imdb.images.id = [] ;
imdb.images.set = uint8([]) ;
imdb.images.name = {} ;
imdb.images.size = zeros(2,0) ;
imdb.meta.sets = {'train', 'val', 'test'} ;
imdb.meta.classes = {'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', ...
  'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', ...
  'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'} ;
imdb.imageDir = fullfile(datasetDir, ['VOC', opts.edition], 'JPEGImages') ;

% Get the list of images
map = containers.Map() ;
j = 0 ;
for si = 1:numel(imdb.meta.sets)
  setName = imdb.meta.sets{si} ;
  annoPath = fullfile(datasetDir, ['VOC' opts.edition], ...
    'ImageSets', 'Main', ...
    [setName '.txt']) ;
  fprintf('%s: reading %s\n', mfilename, annoPath) ;
  [names,labels] = textread(annoPath, '%s %f') ;
  for i=1:length(names)
    j = j + 1 ;
    map(names{i}) = j ;
    imdb.images.id(j) = j ;
    imdb.images.set(j) = si ;
    imdb.images.name{j} = [names{i} '.jpg'] ;
    %info = imfinfo(fullfile(imdb.imageDir, imdb.images.name{j})) ;
    %imdb.images.size(:,j) = [info.Width ; info.Height] ;
    %fprintf('\radded %s', imdb.images.name{j}) ;
  end
end

% Get class labels
for ci = 1:length(imdb.meta.classes)
  imdb.classes.imageIds{ci} = [] ;
  imdb.classes.difficult{ci} = false(0) ;
end
for si = 1:numel(imdb.meta.sets)
  for ci = 1:length(imdb.meta.classes)
    setName = imdb.meta.sets{si} ;
    className = imdb.meta.classes{ci} ;
    annoPath = fullfile(datasetDir, ['VOC' opts.edition], ...
      'ImageSets', 'Main', ...
      [className '_' setName '.txt']) ;
    fprintf('%s: reading %s\n', mfilename, annoPath) ;
    [names,labels] = textread(annoPath, '%s %f') ;
    for i = 1:numel(names)
      j = map(names{i}) ;
      if labels(i) >= 0
        imdb.classes.imageIds{ci}(end+1) = j ;
        imdb.classes.difficult{ci}(end+1) = (labels(i) == 0) ;
      end
    end
  end
end

if opts.lite
  ok = {} ;
  for c = 1:3
    trainIds = intersect(imdb.images.id(imdb.images.set == 1), imdb.classes.imageIds{c}) ;
    testIds = intersect(imdb.images.id(imdb.images.set == 3), imdb.classes.imageIds{c}) ;

    ok{end+1} = vl_colsubset(find(ismember(imdb.images.id, trainIds)), 5) ;
    ok{end+1} = vl_colsubset(find(ismember(imdb.images.id, testIds)), 5) ;
  end
  ok = unique(cat(2, ok{:})) ;
  imdb.meta.classes = imdb.meta.classes(1:3) ;
  imdb.classes.imageIds = imdb.classes.imageIds(1:3) ;
  imdb.classes.difficult = imdb.classes.difficult(1:3) ;
  imdb.images.id = imdb.images.id(ok) ;
  imdb.images.name = imdb.images.name(ok) ;
  imdb.images.set = imdb.images.set(ok) ;
  for c = 1:3
    ok = ismember(imdb.classes.imageIds{c}, imdb.images.id) ;
    imdb.classes.imageIds{c} = imdb.classes.imageIds{c}(ok) ;
    imdb.classes.difficult{c} = imdb.classes.difficult{c}(ok) ;
  end
end


function input_info=my_init_input_info(input_info)

if input_info.is_group_data
   input_info_child_groups=input_info.data_child_groups;
   child_num=length(input_info_child_groups);
   for c_idx=1:child_num
       input_info_child_groups{c_idx}=my_init_input_info(input_info_child_groups{c_idx});
   end
   input_info.data_child_groups=input_info_child_groups;
   input_info.child_valid_flags=true(child_num, 1);
end

input_info.bp_finished=false;
input_info.forward_finished=true;

input_info.aux=[];
input_info.dzdx=[];
input_info.dzdw=[];

end


function disp(ds)
   %DISP Datasource disp overloaded operator

   % VERSION: 1.0 of waveform objects
   % AUTHOR: Celso Reyes (celso@gi.alaska.edu)
   % LASTUPDATE: 11/29/2008

   if numel(ds) > 1;
      disp(' ');
      disp(sprintf('[%s] %s object with Types:',...
         size2str(size(ds)), class(ds)));
      for j=1:numel(ds)
         alltypes(j) = {get(ds(j),'type')};
      end
      alltypes = unique(alltypes);
      for i=1:numel(alltypes)
         disp(sprintf('     %s',alltypes{i}));
      end

   elseif isunassigned(ds)
      disp('  unassigned datasource');
   else
      mytype = get(ds,'type');
      disp(['      type: ' upper(mytype)]);
      switch lower(mytype)
         case 'winston'
            disp(['    server: ' get(ds,'server')]);
            disp(['      port: ' num2str(get(ds,'port'))]);

         case 'irisdmcws'
            %do nothing

         case {'file','sac','antelope','seisan','obspy','miniseed'}
            filelist = getfilename(ds,[],[]);
            for n=1:numel(filelist)
               disp(sprintf('  location: %s',filelist{n}));
            end

         case {'user_defined'}
            filelist = getfilename(ds,[],[]);
            for n=1:numel(filelist)
               disp(sprintf('  location: %s',filelist{n}));
            end
            disp(sprintf(' Interpreting Function: %s',func2str(get(ds,'interpreter'))));
         otherwise
            warning('Datasource:unanticipatedType',...
               'unanticipated datasource type');
      end
   end;
end
function DispStr = size2str(sizeval)
   % helper function that changes the way we view the size
   %   from : [1 43 2 6] (numeric)  to  '1x43x2x6' (char)

   DispStr = sprintf('x%d', sizeval);
   DispStr = DispStr(2:end);
end


function  setRelPosition( hObject,units,hObject_pos )
%this function invokes set(hObject,'Position',hObject_pos) while with 'units' provided

old_units=get(hObject,'units');
set(hObject,'units',units);
set(hObject,'Position',hObject_pos);
set(hObject,'units',old_units);

end


function C = OCP_C(u,x,p,parIdx) %#codegen
    C = OCP_GEN_C(u,x,p,parIdx);
end