function par = validateInput(hcMatrix, dec, par)
% validate input arguments to approximateDec

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

% This function is also used internally for computeApproximationDec,
%   cs-approximation/generateApproxData and cs-approximation/..
%   loadApproxData. Therefore, the input/output interface is not
%   documented.

%% Lists / available options
% strings in List must end with an extra space
methodApproxList = {'PCA ' 'nonlinear ' 'nonlinearLocal '};
methodErrorList = {'relativeSquared ', 'relativeMean ', 'relativeMax ', ...
    'relativeTotal ', 'absoluteSquared ', 'absolute ', 'absoluteMax ', ...
    'absoluteTotal ', 'relativeMaxGroupedMean ', 'PCA '};
methodProjectionList = {'true ', 'confined '};

msgMethod = ['Supported approximation methods are: ' methodApproxList{:}];
msgError = ['Supported error types are: ' methodErrorList{:}];
msgProjection = ['Supported projection types are: ' methodProjectionList{:}];

%% consistecy of dec and hcMatrix
if ~dec.isProper && dec.isComplete
    error('elk:decomposition:wrongInput', ['input representation dec ' ...
        'must be proper or incomplete (via computeExtendedEmbedding).']);
end
if dec.nC ~= size(hcMatrix, 1)
    error('elk:decomposition:wrongInput', ['dimension of vectors in ' ...
        ' must match dec.nC.']);
end
if size(hcMatrix, 1) < 1
    error('elk:decomposition:wrongInput', ['please give me a vector to ' ...
        'work with - the provided hcMatrix is empty']);
end
% And now, let's have some fun with a user:
if size(hcMatrix, 2) <= par.targetDim && ~strcmpi(par.method, 'pca')
    warning('elk:decomposition:input', ['Are you kidding me? The '...
        'number of hC-vectors just define a subspace perfectly, ' ...
        ' you do not need nonlinear optimization to find it. ' ...
        ' You shall pass, however.']);
end
if size(hcMatrix, 2) < par.targetDim
    warning('elk:decomposition:input', ['Have you recognized that your ' ...
        'problem allows a not countable and infinite number of solutions? ' ...
        'I will provide you one, but you have to find all of them by ' ...
        'yourself. Have fun. :D']);
end

%% basic parameters
% .. they are always required

% method
checkArgumentList(methodApproxList, msgMethod, par.method);

% target dimension
if par.targetDim >= dec.nC
    error('elk:decomposition:wrongInput', ['The target dimension should be ' ...
        'lower than the dimension of the input representation in dec.']);
end

% zerotol should already be OK
    
%% extended parameters
% .. they apply only for nonlinear optimization (not PCA)
if strcmpi(par.method, 'pca')
    return
end

% list of measures for error calculation
if isempty(par.measureList)
    par.measureList = {'volume'};
end
if ~iscell(par.measureList)
    par.measureList = {par.measureList};
end
% do the measures exist?
try
    sampleMeasureVector = computeMeasureDec(dec, 'hC', hcMatrix(:,1), ...
        par.measureList, par.zerotol, 0, 1);
catch thisError
    warning(['elk:decomposition:wrongInput', 'Something is wrong with ' ...
        'the measure list or the hcMatrix you provided for approximateDec']);
    rethrow(thisError);
end

% error type
checkArgumentList(methodErrorList, msgError, par.errorType);

% measure weight vector
if isempty(par.measureWeightVector)
    par.measureWeightVector = ones(1, length(sampleMeasureVector));
else
    % ensure row vector
    par.measureWeightVector = par.measureWeightVector(:)';
end

% projection type
checkArgumentList(methodProjectionList, msgProjection, par.projectionType);

%! DEV: currently unused:
% % distance limit
% if isempty(par.distanceLimit)
%     par.distanceLimit = max(hcMatrix(:))*1e-3;
% end
% 
% % penalty
% if par.penaltySlope < 0
%     error('elk:decomposition:wrongInput', 'the penalty slope must be positive');
% end
% if par.penaltyRatioLimit < 0 || par.penaltyRatioLimit > 1
%     error('elk:decomposition:wrongInput', ['the penalty ratio limit ' ....
%         ' must be in the interval [0, 1]']);
% end
%/

% the following parameters are for debugging and should only be applied if
%   you know what you do:
if ~(numel(par.manualScaling) == 1) && all(par.manualScaling(:) == 0.5)
    warning('elk:decomposition:scalingMatrix', ['I hope, you know what ' ...
        'you are doing, providing a manual scaling (matrix).']);
end
if ~isempty(par.manualBoundingCone)
    warning('elk:decomposition:boundingCone', ['I hope, you know what ' ...
        'you are doing, providing a manual bounding cone']);
end

% if strcmpi(par.method, 'PCA')
%     % nothing to do for manual initial condition
% else
%     if ~isempty(par.manualInitialCondition) && ...
%             isnumeric(par.manualInitialCondition)
%         warning('elk:decomposition:scalingMatrix', ['I hope, you know what ' ...
%             'you are doing, providing a manual initial condition']);
%     elseif isempty(par.manualInitialCondition) || ...
%             strcmpi(par.manualInitialCondition, 'nonlinearLocal')
%         disp('NONLINEAR')
%         % the possibly more advanced initial condition is obtained by a
%         %   local optimization run.
%         thisPar = par;
%         thisPar.method = 'nonlinearLocal';
%         thisPar.manualInitialCondition = 'PCA';
%         dataApprox = approximateDec(hcMatrix, dec, thisPar);
%         par.manualInitialCondition = dataApprox.mappingReducedToEmbedding;
%         disp('/NONLINEAR')
%         
%     elseif strcmpi(par.manualInitialCondition, 'PCA')
%         % the simple initial condition is the PCA solution
%         disp('PCA')
%         thisPar = par;
%         thisPar.method = 'PCA';
%         dataApprox = approximateDec(hcMatrix, dec, thisPar);
%         par.manualInitialCondition = dataApprox.mappingReducedToEmbedding;
%         disp('/PCA')
%         
%     else
%         error('elk:approximation:inputError', ['Please correct the value '...
%             'for the manualInitialCondition option, it does not make sense.'])
%     end
% end