function acceptMeas = validateMeasureDataDec(dec, varargin)
% validates the measure data in a decomposition structure
%
% Syntax: acceptMeas = validateMeasureDataDec(dec)
%
% The measure data in dec is validated according to the following tests:
%   (T1) The coefficient tensors for all simplex partitions that belong to
%          the same unified partition must be equal. A failure here
%          indicates either a failure in the conversion, a failure in
%          the triangulation of the unified partitions or any prior step of
%          the decomposition.
%   (T2) The calculated measure of the polytope, the corresponding 
%          hC-vector and the corresponding lambda-vector must be equal for 
%          every partition. This step verifies the mixed volumes in
%          tensorSe.
%
% validateMeasureDataDec(.., 'measure', measureNameList) let you specify
%   the measures that are validated. Single parameters cannot be tested.
%   measureNameList is a cell array of the field names of dec.measureData.
%   Default: all fields of dec.measureData
%
% validateMeasureDataDec(.., 'zerotol', zerotol) sets the zerotol. 
%   Default: elkZerotol
%
% validateMeasureDataDec(.., 'verbose', verbose) sets the verbosity. For 
%   verbose=0, no messages are displayed, verbose=1 states which tests
%   went wrong including some details about measure and partition. 
%   Default: 1
%
% validateMeasureDataDec(.., 'detailed', detail) sets the format of the
%   returned variable. With detail=0 only a single boolean is returned, 
%   whether the validation was successful. With detail=1 a matrix is 
%   returned where the row index is generated from the measures and the
%   tests: the first third contains (T1), the second third contains the
%   tests of the polytope measure against the measure by hC-vector and the
%   last third contains the test of the polytope measure against the
%   polytope measure against the lambda-vector. The columns are according
%   to the simplex partitions. Default: 0
%
% See also: validateDec, addMeasureDataDec, computeMeasureDec

% The elk-library: convex geometry applied to crystallization modeling.
%   Copyright (C) 2012 Alexander Reinhold
%
% 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/>.

%% Input handling

% cancel, if measure data does not exist
if ~isfield(dec, 'measureData')
    error('elk:decomposition:wrongInput', ...
        'The decomposition does not contain measure data');
end

% options
[measureNameList, detailed, zerotol, verbose] = mapOption(varargin, ...
    'measure', fieldnames(dec.measureData),...
    'detailed', 0, ...
    'zerotol', elkZerotol, ...
    'verbose', 1);

% ensure measure is a cell-array
if ~iscell(measureNameList)
    measureNameList = {measureNameList};
end

%% Perform check
% starting with invalid assignements
coefficientTest = ones([length(measureNameList), ...
                        dec.nPS]);
vectorHcTest = coefficientTest;
vectorLamTest = coefficientTest;


for iMeasure = 1:length(measureNameList)
    % shortcut to measure
    thisMeasure = dec.measureData.(measureNameList{iMeasure});
    
    % for each measure, we cycle through the simplex partitions to check
    for iSimplex = 1:dec.nPS
        
        thisSimplex = dec.simplexPartition{iSimplex};
        referenceIndex = find(...
            dec.simplexToUnifiedVector == dec.simplexToUnifiedVector(iSimplex), ...
            1, 'first');
        
        thisSampleLam = ones(1, dec.nC);
        thisSampleHc  = thisSampleLam * dec.se(thisSimplex.seIndexVector, :);
        
        if thisMeasure.isPar
            
            for iPar = 1:length(thisMeasure.tensorSe)
                % coefficient test
                thisError = thisMeasure.tensorHc{iPar}{iSimplex}(:) ...
                          - thisMeasure.tensorHc{iPar}{referenceIndex}(:);
                thisTest = all(isZero(thisError, zerotol));
                
                if thisTest == 0 && verbose
                    disp(['[-] (T1) - Validation of [' thisMeasure.name ...
                        ', ' num2str(iPar) ...
                        '] failed: tensor of simplex partition ' ...
                        num2str(referenceIndex) ' and ' num2str(iSimplex) ...
                        ' do not match (max error: ' ...
                        num2str(max(abs(thisError))) ').']);
                end
                
                coefficientTest(iMeasure, iSimplex) = ...
                    coefficientTest(iMeasure, iSimplex) & thisTest;
                
                % get measures
                referenceMeasure = thisMeasure.handleH(...
                    dec.mappingReducedToFull*thisSampleHc', ...
                    thisMeasure.par(iPar, :));
                hcMeasure = computeMeasureDec(dec, ...
                    'hc', {iSimplex, thisSampleHc}, ...
                    {thisMeasure.name, thisMeasure.par(iPar, :)}, ...
                    zerotol, 1);
                lamMeasure = computeMeasureDec(dec, ...
                    'se', {iSimplex, thisSampleLam}, ...
                    {thisMeasure.name, thisMeasure.par(iPar, :)}, ...
                    zerotol, 1);
                
                % hC-vector test
                thisTest = isZero(hcMeasure - referenceMeasure, zerotol);
 
                if thisTest == 0 && verbose
                    disp(['[-] (T2) - Validation of [' thisMeasure.name ...
                        ', ' num2str(iPar) ...
                        '] failed: measure for hC-vector of partition ' ...
                        num2str(iSimplex) ' is wrong. (max error: '...
                        num2str(abs(max(hcMeasure(:) - referenceMeasure(:)))) ...
                        ')']);
                end
                
                vectorHcTest(iMeasure, iSimplex) = ...
                    vectorHcTest(iMeasure, iSimplex) & thisTest;
                
                % lambda-vector test
                thisTest = isZero(lamMeasure - referenceMeasure, zerotol);
                
                if thisTest == 0 && verbose
                    disp(['[-] (T2) - Validation of [' thisMeasure.name ...
                        ', ' num2str(iPar) ...
                        '] failed: measure for lambda-vector of partition ' ...
                        num2str(iSimplex) ' is wrong.']);
                end
                
                vectorLamTest(iMeasure, iSimplex) = ...
                    vectorLamTest(iMeasure, iSimplex) & thisTest;
            end
            
        else
            % coefficient test
            thisError = thisMeasure.tensorHc{iSimplex}(:) ...
                      - thisMeasure.tensorHc{referenceIndex}(:);
            thisTest = all(isZero(thisError, zerotol));
            
            if thisTest == 0 && verbose
                disp(['[-] (T1) - Validation of [' thisMeasure.name ...
                    '] failed: tensor of simplex partition ' ...
                    num2str(referenceIndex) ' and ' num2str(iSimplex) ...
                    ' do not match (max error: ' ...
                        num2str(max(abs(thisError))) ').']);
            end
            
            coefficientTest(iMeasure, iSimplex) = ...
                    coefficientTest(iMeasure, iSimplex) & thisTest;
                
            % get measures
            referenceMeasure = thisMeasure.handleH(...
                               dec.mappingReducedToFull*thisSampleHc');
            hcMeasure = computeMeasureDec(dec, ...
                'hc', {iSimplex, thisSampleHc}, thisMeasure.name, ...
                zerotol, 1);
            lamMeasure = computeMeasureDec(dec, ...
                'se', {iSimplex, thisSampleLam}, thisMeasure.name, ...
                zerotol, 1);
            
            % hC-vector test
            thisError = hcMeasure - referenceMeasure;
            thisTest = isZero(thisError, zerotol);
            
            if thisTest == 0 && verbose
                disp(['[-] (T2) - Validation of [' thisMeasure.name ...
                    '] failed: measure for hC-vector of partition ' ...
                    num2str(iSimplex) ' is wrong. (max error: '...
                    num2str(max(abs(thisError(:)))) ')']);
            end
            
            vectorHcTest(iMeasure, iSimplex) = ...
                vectorHcTest(iMeasure, iSimplex) & thisTest;
            
            % lambda-vector test
            thisError = lamMeasure - referenceMeasure;
            thisTest = isZero(lamMeasure - referenceMeasure, zerotol);
            
            if thisTest == 0 && verbose
                disp(['[-] (T2) - Validation of [' thisMeasure.name ...
                    '] failed: measure for lambda-vector of partition ' ...
                    num2str(iSimplex) ' is wrong. (max error: '...
                    num2str(max(abs(thisError(:)))) ')']);
            end
            
            vectorLamTest(iMeasure, iSimplex) = ...
                vectorLamTest(iMeasure, iSimplex) & thisTest;
            
        end

    end
    
    dec.meas.(measureNameList{iMeasure}) = thisMeasure;
end

if ~detailed
    acceptMeas = prod(prod([coefficientTest, vectorHcTest, vectorLamTest]));
else
    acceptMeas = [coefficientTest; vectorHcTest; vectorLamTest];
end
