function hrep = convertVrepToHrep(vrep, zerotol, flatness, useCddlib)
% convert a V-representation into a H-representation
%
% Syntax: hrep = convertVrepToHrep(vrep)
%   or    hrep = convertVrepToHrep(vrep, zerotol, flatness)
%
% The parameter zerotol applies for scaleVrep only (default is elkZerotol).
%
% Consider that cddlib applies an additional zerotol that is stored in the 
%   function zerotolCddlib during initialization of this library 
%   (buildCddlib).
%
% The parameter flatness is only applied if the dimension of the object is 
%   smaller than the dimension it is embedded in (e.g. a 2D object in 3D 
%   space). The flatness is applied by adding [flatness/2] to all facet 
%   distances for which the corresponding hyperplane fully contains the
%   polytope.
%
% There are two underlying methods to perform this conversion. The direct
%   approach uses triangulation (convhulln). An alternative approach is to 
%   utilize duality and use convertHrepToVrep with the underlying 
%   double-description method (cddlib). The default is choosen by 
%   speed and reliability. The alternative is used if this approach fails.
%
% convert(.., prefereCddlib) gives the possibility to change the default
%   standard algorithm to be used. Default: 0
%
% See also: convertPolytope, convertHrepToVrep, scaleVrep

% 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
if ~exist('zerotol', 'var') || isempty(zerotol)
    zerotol = elkZerotol;
end
if ~exist('flatness', 'var') || isempty(flatness)
    flatness = 0;
end
if ~exist('useCddlib', 'var') || isempty(useCddlib)
    useCddlib = 0;
end
if isempty(vrep.V)
    hrep.A = vrep.V;
    hrep.h = [];
    return
end
vrepDim = size(vrep.V, 2);

%% Reduce dimension if flat
[vrepReduced, reduceTrafo, reduceOffset] = reduceVrepDimension(vrep, zerotol);
reducedDim = size(vrepReduced.V, 2);

%% Scale polytope
[vrepScaled, scale, scaleOffset] = scaleVrep(vrepReduced, zerotol);

% outer conversion structure
useAlternative = 0;
while useCddlib > -1
try
    if ~useCddlib
        %% direct approach (convhulln)
        hrep = convertVrepToHrepByConvhulln(vrepScaled, zerotol);
    else
        %% dual approach (cddlib)
        % map to dual polytope in H-representation
        dualHrep = computeDualPolytope(vrepScaled);
        
        % convert to dual Vrep
        dualVrep = convertHrepToVrep(dualHrep, zerotol, inf, 1);
        
        % convert back to normal Hrep
        hrep = computeDualPolytope(dualVrep);
    end
    % assign to exit loop:
    useCddlib = -1;
catch thisError
    if ~useAlternative
        warning('elk:conversion:method', thisError.message);
        warning('elk:conversion:method', ...
            'Using alternative approach to convert polytope.');
        useAlternative = 1;
        useCddlib = ~useCddlib;
    else
        % safe input polytope
        if exist('log_convertVrepToHrep.mat', 'file')
            load log_convertVrepToHrep.mat
            logVrep{end+1} = vrep;
        else
            logVrep{1} = vrep;
        end
        save log_convertVrepToHrep.mat logVrep
        warning('elk:polytope:method', ...
            ['Given vrep cannot be converted to hrep (usually cddlib). ' ...
            'Polytope stored in: ' cd filesep 'log_convertVrepToHrep.mat']);
        rethrow(thisError);
    end
end
end

%% Revert scaling
hrep = stretchHrep(hrep, scale, zeros(length(scale), 1));
hrep = moveHrep(hrep, scaleOffset);

%% Project back to original dimension
if reducedDim < vrepDim
    hrep = liftHrepDimension(hrep, reduceTrafo, reduceOffset, flatness);
end

%% apply flatness
% flatFacetIndexList = (1:(2*(vrepDim-reducedDim))) + size(hrep.A, 1);
% hrep.h(flatFacetIndexList) = hrep.h(flatFacetIndexList) + flatness/2;

%% Normalize
hrep = normalizeHrep(hrep);

