function Pd = getPrecon(problem, x, d, storedb, key)
% Applies the preconditioner for the Hessian of the cost at x along d.
%
% function Pd = getPrecon(problem, x, d)
% function Pd = getPrecon(problem, x, d, storedb)
% function Pd = getPrecon(problem, x, d, storedb, key)
%
% Returns as Pd the result of applying the Hessian preconditioner to the
% tangent vector d at point x. The preconditioner is supposed to be a
% symmetric, positive definite approximation of the inverse of the Hessian.
% 
% If no preconditioner is available, Pd = d (identity).
%
% storedb is a StoreDB object, key is the StoreDB key to point x.
%
% See also: getHessian

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Dec. 30, 2012.
% Contributors: 
% Change log: 
%
%   April 3, 2015 (NB):
%       Works with the new StoreDB class system.

    % Allow omission of the key, and even of storedb.
    if ~exist('key', 'var')
        if ~exist('storedb', 'var')
            storedb = StoreDB();
        end
        key = storedb.getNewKey();
    end

    
    if isfield(problem, 'precon')
    %% Precondition using precon.
    
        % Check whether this function wants to deal with storedb or not.
        switch nargin(problem.precon)
            case 2
                Pd = problem.precon(x, d);
            case 3
                % Obtain, pass along, and save the store for x.
                store = storedb.getWithShared(key);
                [Pd, store] = problem.precon(x, d, store);
                storedb.setWithShared(store, key);
            case 4
                % Pass along the whole storedb (by reference), with key.
                Pd = problem.precon(x, d, storedb, key);
            otherwise
                up = MException('manopt:getPrecon:badprecon', ...
                    'precon should accept 2, 3 or 4 inputs.');
                throw(up);
        end      

    elseif canGetSqrtPrecon(problem)
    %% Precondition by applying the square root of the preconditioner twice.
        
        sqrtPd = getSqrtPrecon(problem, x, d, storedb, key);
        Pd = getSqrtPrecon(problem, x, sqrtPd, storedb, key);
        
    else
    %% No preconditioner provided, so just use the identity.
    
        Pd = d;
        
    end
    
end
