function grain = gtFSimCreateGrainTable(grain, fields, det_index, updateVars, verbose)
% GTCREATEGRAINTABLE
%     grain = gtFSimCreateGrainTable(grain, fields, [det_index], [updateVars], [verbose])
%     -----------------------------------------------------------------------------------
%     Only reflections on the detector are built in the table
%     It adds fields 'table' and 'table_header'
%     Needs field 'ondet'
%
%     INPUT:
%       grain      = <struct/double>  structure grain
%       fields     = <cell>           names of fields to put in the table
%       det_index  = <double>         detector index {1}
%       updateVars = <logical>        update vars in grain {false}
%       verbose    = <logical>        print comments {true}
%
%     OUTPUT:
%       grain      = <struct>         updated grain

%[sub]-sfGetSubFields
%[sub]-sfGetRowIndexes

if (~exist('verbose', 'var') || isempty(verbose))
    verbose = true;
end
output = GtConditionalOutput(verbose);

grainDirsModel = fullfile('4_grains', 'phase_%02d', 'grain_%04d.mat');
if isnumeric(grain)
    grain = load(sprintf(grainDirsModel, phaseid, grain));
    output.odisp(['Loaded grain from file ' grainDirsModel])
end
if (~exist('fields', 'var') || isempty(fields))
    gtError('gtFSimCreateGrainTable:missing_input', 'Missing input for ''fields''')
end
if (~exist('updateVars', 'var') || isempty(updateVars))
    updateVars = false;
end
if (~exist('det_index', 'var') || isempty(det_index))
    det_index = 1;
end

gr1 = sfGetSubFields(grain.allblobs, fields);

if (isfield(grain, 'proj') && isfield(grain.proj, 'ondet'))
    gr1 = sfGetRowIndexes(gr1, grain.proj(det_index).ondet);
else
    gr1 = sfGetRowIndexes(gr1, grain.ondet);
end

restFields = setdiff(fields, fieldnames(gr1));
gr2 = sfGetSubFields(grain, restFields);

% cat the two structures
gr = catstruct(gr1, gr2);
% add missing fields to grain
if (updateVars)
    grain = gtAddMatFile(grain, gr, true, true, false, false, false);
end

fields = fieldnames(gr);
grCell = struct2cell(gr)';

size1 = cellfun(@(x) size(x, 1), grCell);
if (length(unique(size1)) == 1)
    grMat = cell2mat(grCell);
else
    output.odisp('Error: chosen fields don''t have the same size...')
    grCell = grCell(size1 == size1(1));
    grMat = grCell;
end

nEntry = (1:size(grMat, 1))';

grain.fsimgui.table = gr;
grain.fsimgui.table_num = [nEntry grMat];
grain.fsimgui.table_header = strtrim(['index ' sprintf('%s ', fields{:})]);

end

%%%%%%%%%%%%%%%%%
% sub-functions %
%%%%%%%%%%%%%%%%%

function db_info = sfGetRowIndexes(db_info, ids)
% sfGETROWINDEXES
%   db_info = sfGetRowIndexes(db_info, ids)
%
% db_info : structure with field content of same length
% ids     : rows indexes to get

    if (~isempty(ids))
        db_info = structfun(@(x)double(x(ids, :)), db_info, 'UniformOutput', false);
    end
end

function [structData, fields] = sfGetSubFields(structData, fields)
% sfGETSUBFIELDS
%   structData = sfGetSubFields(structData, fields)
%
% structData : original structure
% fields     : cell list of fields to get (row vector)

    if (~all(isfield(structData, fields), 2))
        fields(~isfield(structData, fields)) = [];
    end

    structData = cell2struct(cellfun(@(x) structData.(x), fields, 'UniformOutput', false), fields, 2);
end
