function data = summarizeCases
% open, verify and summarize all cases
%
% A matrix is generated with every case in a row and every column
%   containing a particular data.

% loading cases will advance through the cases provided in the database
%   folder
caseList = obtainData('init');

%% define data columns
data.headingList.case = {...
    'caseSet', ...
    'caseName', ...
    'caseKey'};
data.headingList.dec = {...
    'nH', ...
    'nC', ...
    'nS', ...
    'nPU', ...
    'nPS'};
data.headingList.decExtra = {...
    'facetsOfValidityCone'};
data.headingList.decTiming = {...
    'fixPosition', ...
    'generateCone', ...
    'propernessHandling', ...
    'simplifyCone', ...
    'addBoundaryData', ...
    'decomposeCone', ...
    'validateDec', ...
    };
data.headingList.partitionTiming = {...
    'obtainUnifiedTime', ...
    'obtainSimplexTime'};
data.headingList.measTiming = {...
    'mixedVolumeTensor', ...
    'convertedTensor', ...
    'computeMeasureTime', ...
    'computeRealMeasureTime'};

%% initialize matrices
data.matrix.case = zeros(0, length(data.headingList.case));
data.matrix.dec = zeros(0, length(data.headingList.dec));
data.matrix.decExtra = zeros(0, length(data.headingList.decExtra));
data.matrix.decTiming = zeros(0, length(data.headingList.decTiming));
data.matrix.partitionTiming = zeros(0, length(data.headingList.partitionTiming));
data.matrix.meas.feret = zeros(0, length(data.headingList.measTiming));
data.matrix.meas.surface = zeros(0, length(data.headingList.measTiming));
data.matrix.meas.volume = zeros(0, length(data.headingList.measTiming));
iRow = 0;
isOK = true;
data.caseNameList = {'potash', 'paracetamol', 'magnesiumSulfate', 'lactose'};
data.texCaseNameList = {'potash alum', 'paracetamol', ...
    '$\\mbox{MgSO}_{4}\\cdot 11\\mbox{H}_{2}\\mbox{O}$', ...
    'lactose'};
data.caseMarkerList = {'+', 'o', 'v', 'x'};

for iCaseSet = 1:length(caseList)
    %% printout caseSet
    caseSet = obtainData(caseList(iCaseSet).name);
    disp(['Processing case set: ' caseList(iCaseSet).name])
    disp(['  Name: ' caseSet.name]);
    disp(['  Crystal Keys: ' num2str(caseSet.keyVector)]);
    
    %% prepare new rows
    data = extendCaseNumber(data, length(caseSet.keyVector));
    
    for iCase = 1:length(caseSet.keyVector)
        thisCaseName = [caseSet.name '_' num2str(caseSet.keyVector(iCase))];
        fprintf(['  .. ' thisCaseName]);
        try
            thisResult = obtainData(thisCaseName, 'database', './data');
        catch errorMessage
            warning(errorMessage.message)
            continue
        end
        iRow = iRow + 1;
        
        %% validate decomposition
        if ~thisResult.dec.validationData.result
            fprintf([' .. dec is INVALID']);
            warning('Decomposition is invalid');
            isOK = false;
        end
        
        %% write case data
        thisCaseNameIndex = findIndex(data.caseNameList, thisResult.name);
        data.matrix.case(iRow, :) = [iCase thisCaseNameIndex ...
                                     caseSet.keyVector(iCase)];
        
        %% write decomposition data
%         data.matrix.dec(iRow, :) = [thisResult.dec.nH thisResult.dec.nC, ...
%                            thisResult.dec.nS ...
%                            thisResult.dec.nPU thisResult.dec.nPS];
        data.matrix.dec(iRow, :) = createRow(thisResult.dec, ...
            data.headingList.dec);
        
        %% additional decomposition data
        data.matrix.decExtra(iRow, 1) = size(thisResult.dec.validityCone.A, 1);
        
        %% write decTiming data
%         tmpTime = result.dec.timingData;
%         data.matrix.dec = [thisResult.dec.nH thisResult.dec.nC, ...
%                            thisResult.dec.nS ...
%                            thisResult.dec.nPU thisResult.dec.nPS];
        data.matrix.decTiming(iRow, :) = createRow(...
            thisResult.dec.timingData, ...
            data.headingList.decTiming);
        
        %% write partTiming data
        data.matrix.partitionTiming(iRow, :) = createRow(...
            thisResult, ...
            data.headingList.partitionTiming);
        data.matrix.partitionTiming(iRow, :) = ...
            data.matrix.partitionTiming(iRow, :) / ...
            thisResult.obtainPartitionSamples;
        
        %% write meas data
        [data isOK] = createMeasRow(data, thisResult, 'feret', iRow, isOK);
        [data isOK] = createMeasRow(data, thisResult, 'surface', iRow, isOK);
        [data isOK] = createMeasRow(data, thisResult, 'volume', iRow, isOK);
        
        fprintf('\n');
    end    
    
end

%% save data
save(['data' filesep 'summarizedData.mat'], 'data');

end

function data = extendCaseNumber(data, nNew) 
    data.matrix.case(end + (1:nNew), :) = nan;
    data.matrix.dec(end + (1:nNew), :) = nan;
    data.matrix.decTiming(end + (1:nNew), :) = nan;
    data.matrix.partitionTiming(end + (1:nNew), :) = nan;
    data.matrix.meas.feret(end + (1:nNew), :) = nan;
    data.matrix.meas.surface(end + (1:nNew), :) = nan;
    data.matrix.meas.volume(end + (1:nNew), :) = nan;
end

function caseIndex = findIndex(nameList, thisName)
caseIndex = 1;
while caseIndex <= length(nameList)
    if strcmp(nameList{caseIndex}, thisName)
        break
    end
    caseIndex = caseIndex + 1;
end

if caseIndex > length(nameList)
    error('The data in the database folder contains unexpected data');
end
end

function rowData = createRow(inStruct, fieldNameList)
rowData = nan([1, length(fieldNameList)]);
for iField = 1:length(fieldNameList)
    rowData(iField) = inStruct.(fieldNameList{iField});
end
end

function [data isOK] = createMeasRow(data, result, measName, iRow, isOK)
nPar = max(1, size(result.dec.measureData.(measName).par, 1));
tmp = reshape(cell2mat(struct2cell(...
    result.dec.measureData.(measName).time)), [2 nPar]);
data.matrix.meas.(measName)(iRow, 1) = sum(tmp(1,:)) / nPar;
data.matrix.meas.(measName)(iRow, 2) = sum(tmp(2,:)) / nPar;
data.matrix.meas.(measName)(iRow, 3) = ...
    result.(measName).computeMeasureTime / ...
    result.(measName).computeMeasureSamples / ...
    result.(measName).computeMeasureNPar;
data.matrix.meas.(measName)(iRow, 4) = ...
    result.(measName).computeRealMeasureTime / ...
    result.(measName).computeRealMeasureSamples / ...
    result.(measName).computeRealMeasureNPar;
if ~all(result.(measName).verifyMatrix)
    fprintf([' .. meas ' upper(measName) ' is INVALID']);
    warning(['Measure ' upper(measName) ' is invalid']);
    isOK = false;
end

end
