function [code,d] = sprintf(this,varargin)
% sprintf  Format SVAR as a model code and write to text string.
%
% Syntax
% =======
%
%     [C,D] = sprintf(S,...)
%
% Input arguments
% ================
%
% * `S` [ SVAR ] - SVAR object that will be written as a model code.
%
% - Output arguments
%
% * `C` [ cellstr ] - Text string with the model code for each
% parameterisation.
%
% * `D` [ cell ] - Parameter database for each parameterisation; if
% `'hardParameters='` is true, the databases will be empty.
%
% Options
% ========
%
% * `'decimal='` [ numeric | *empty* ] - Precision (number of decimals) at
% which the coefficients will be written if `'hardParameters='` is true; if
% empty, the `'format='` options is used.
%
% * `'declare='` [ `true` | *`false`* ] - Add declaration blocks and keywords
% for VAR variables, shocks, and equations.
%
% * `'eNames='` [ cellstr | char | *empty* ] - Names that will be
% given to the VAR residuals; if empty, the names from the SVAR object will
% be used.
%
% * `'format='` [ char | *'%+.16e'* ] - Numeric format for parameter values;
% it will be used only if `'decimal='` is empty.
%
% * `'hardParameters='` [ *`true`* | `false` ] - Print coefficients as hard
% numbers; otherwise, create parameter names and return a parameter
% database.
%
% * `'yNames='` [ cellstr | char | *empty* ] - Names that will be
% given to the variables; if empty, the names from the SVAR object will
% be used.
%
% * `'tolerance='` [ numeric | *getrealsmall()* ] - Treat VAR coefficients
% smaller than `'tolerance='` in absolute value as zeros; zero coefficients
% will be dropped from the model code.
%
% Description
% ============
%
% Example
% ========
%

% -IRIS Toolbox.
% -Copyright (c) 2007-2012 Jaromir Benes.

% Parse options.
options = passvalopt('SVAR.sprintf',varargin{:});

if isempty(strfind(options.format,'%+'))
    VAR.error(39,'Format string must contain %+.',options.format);
end

if ~isempty(options.decimal)
    options.format = ['%+.',sprintf('%g',options.decimal),'e'];
end

%**************************************************************************

[ny,p,nalt] = sizeof(this);

if ~isempty(options.ynames)
    this.ynames = options.ynames;
end
ynames = get(this,'yNames');

if ~isempty(options.enames)
    this.enames = options.enames;
end
enames = get(this,'eNames');

% Add time subscripts if missing from the variable names.
for i = 1 : ny
    if isempty(strfind(ynames{i},'{t}'))
        ynames{i} = sprintf('%s{t}',ynames{i});
    end
end

% Replace time subscripts with hard typed lags.
ynames = strrep(ynames,'{t}','{%+g}');
ynamesLags = cell([1,ny]);
for i = 1 : ny
    ynamesLags{i} = cell([1,p+1]);
    for j = 0 : p
        ynamesLags{i}{1+j} = sprintf(ynames{i},-j);
    end
    ynamesLags{i}{1} = strrep(ynamesLags{i}{1},'{-0}','');
end

% Number of digits for printing parameter indices.
if ~options.hardparameters
    pformat = ['%',sprintf('%g',floor(log10(max([ny,p])))+1),'g'];
end

% Preallocatte output arguments.
code = cell([1,nalt]);
d = cell([1,nalt]);

% Cycle over all parameterisations.
for ialt = 1 : nalt
    % Retrieve SVAR system matrices.
    A = -reshape(this.A(:,:,ialt),[ny,ny,p]);
    B = this.B(:,:,ialt);
    K = this.K(:,ialt);
    if ~options.constant
        K(:) = 0;
    end
    
    % Write equations.
    equation = cell([1,ny]);
    d{ialt} = struct();
    
    for eq = 1 : ny
        equation{eq} = [ynamesLags{eq}{1},' ='];
        rhs = false;
        if abs(K(eq)) > options.tolerance
            equation{eq} = [equation{eq},' ', ...
                doprintparameter('K',{eq},K(eq))];
            rhs = true;
        end
        for t = 1 : p
            for y = 1 : ny
                if abs(A(eq,y,t)) > options.tolerance
                    equation{eq} = [equation{eq},' ', ...
                        doprintparameter('A',{eq,y,t},A(eq,y,t)),'*', ...
                        ynamesLags{y}{1+t}];
                    rhs = true;
                end
            end
        end
        for e = 1 : ny
            if abs(B(eq,e)) > options.tolerance
                equation{eq} = [equation{eq},' ', ...
                    doprintparameter('B',{eq,e},B(eq,e)),'*',enames{e}];
                rhs = true;
            end
        end
        if ~rhs
            % If nothing occurs on the RHS, add zero.
            equation{eq} = [equation{eq},' 0'];
        end
    end
    
    % Declare variables if requested.
    if options.declare
        nl = sprintf('\n');
        tab = sprintf('\t');
        ynames = regexprep(ynames,'\{.*\}','');
        code{ialt} = [ ...
            '!variables:transition',nl, ...
            strfun.cslist(ynames,'wrap',75,'lead',tab),nl, ...
            '!shocks:transition',nl, ...
            strfun.cslist(enames,'wrap',75,'lead',tab),nl, ...
            '!equations:transition',nl, ...
            sprintf('\t%s;\n',equation{:})];
    else
        code{ialt} = sprintf('%s;\n',equation{:});
    end
    
    if ~options.hardparameters
        for i = 1 : ny
            d{ialt}.(['std_',enames{i}]) = this.std;
        end
    end
    
end

% Nested functions.

%**************************************************************************
    function x = doprintparameter(matrix,position,value)
        if options.hardparameters
            x = sprintf(options.format,value);
        else
            if p <= 1 && numel(position) == 3
                position = position(1:2);
            end
            x = [matrix,sprintf(pformat,position{:})];
            d{ialt}.(x) = value;
            x = ['+',x];
        end
    end
% doprintparameter().

end