function hcMatrix = mapFromProperEmbedding(heMatrix, dec, zerotol, ...
    partitionVector, enforcePartition)
% map hE-vector from proper embedding to hC-vector space
%
% Syntax: hcMatrix = convertToProperEmbedding(hcMatrix, dec)
%
% The input decomposition is assumed to be improper and the hE vectors
%   reside in the hE-space of the proper embedding. The input hE-vectors 
%   (each column in heMatrix) are assumed to reside on the nC-dimensional 
%   domains in hE-space that correspond to the unified partitions of the 
%   improper representation. If this is not the case the corresponding
%   unified partition might not be found or the shape of the corresponding
%   polytope might be changed.
%
% See also: projectDec, mapToConfonementCone

% 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/>.

if dec.isProper
    error(['elk:decomposition:inputError', 'The input decomposition is ' ...
        'supposed to be improper for this function.']);
    % if it is proper, one does not need this function.
end
if ~dec.isComplete
    % in case of an incomplete representation, there is not much to do:
    hcMatrix = dec.properData.mappingProperToNew * heMatrix;
    return
end
if ~exist('zerotol', 'var') || isempty(zerotol)
    zerotol = elkZerotol;
end
if ~exist('partitionVector', 'var') || isempty(partitionVector)
    partitionVector = zeros(1, size(heMatrix, 2));
    processFilter = true(1, size(heMatrix, 2));
    
    for iPart = 1:dec.nPU
        filterInPartition = processFilter;
        filterInPartition(processFilter) = max(...
            dec.unifiedPartition{iPart}.embeddingDomain.hrepStrict.A * ...
            heMatrix(:, processFilter), [], 1) < zerotol;
        partitionVector(filterInPartition) = iPart;
        processFilter(filterInPartition) = false;
        
        if ~any(processFilter)
            break;
        end
    end
        
    % error handling
    if any(partitionVector == 0)
        error('elk:decomposition:indistinctError', ...
            ['the unified partition for some input vector could ' ...
            'not be found. This can have several causes, please check: ' ...
            '(1) whether your decomposition is ordinary, (2) whether ' ...
            'all input vectors describe a polytope of the input improper ' ...
            'decomposition, (3) otherwise, the decomposition was not ' ...
            'created properly and this should not happen.']);
    end
end
% partitionVector
if exist('enforcePartition', 'var') && enforcePartition
    for iPart = 1:dec.nPU
        thisFilter = partitionVector == iPart;
        heMatrix(:, thisFilter) = dec.unifiedPartition{iPart...
            }.embedding.validityProjection * heMatrix(:, thisFilter);
    end    
end

hcMatrix = nan(dec.nC, size(heMatrix, 2));
for iPart = 1:dec.nPU
    thisFilter = partitionVector == iPart;
    hcMatrix(:, thisFilter) = ...
        dec.unifiedPartition{iPart}.projection.fromProper * ...
        heMatrix(:, thisFilter);
end

if any(isnan(hcMatrix(:)))
    error(['elk:decomposition:wrongInput', 'Please check your input to ' ...
        'this function (partitionVector) as some vectors could not ' ...
        'be projected.']);
end