function x = eval(this,d,range)
% eval  Evaluate model equations on specified database.
%
% Syntax
% =======
%
%     discrep = eval(m,d,range)
%
% Input arguments
% ================
%
% * `m` [ model ] - Model object whose equations will be evaluated.
%
% * `d` [ struct ] - Input database.
%
% * `range` [ numeric ] - Evaluation date range.
%
% Output arguments
% =================
%
% * `discrep` [ tseries ] - Discrepancies between LHSs and RHSs of model
% equations when evaluated on the input database; expectations are replaced
% with actual leads.
%
% Description
% ============
%
% Example
% ========
%
%}


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

P = inputParser();
P.addRequired('m',@ismodel);
P.addRequired('data',@isstruct);
P.addRequired('range',@isnumeric);
P.parse(this,d,range);

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

nalt = size(this.Assign,3);
ndata = getNdata_();
nloop = max([nalt,ndata]);

range = range(:).';
nrange = length(range);

t = this.tzero;
if issparse(this.occur)
    nt = size(this.occur,2)/length(this.name);
else
    nt = size(this.occur,3);
end
maxt = nt - t;
mint = 1 - t;

rangex = (range(1) + mint) : (range(end) + maxt);
nrangex = nrange - mint + maxt;

nname = length(this.name);
x = nan([nrange,nname,nt]);
L = nan([1,nname]);
W = nan([nrange,sum(this.nametype == 1)]);

neqtn = sum(this.eqtntype <= 2);
evaleqtn = nan([neqtn,nrange,nloop]);
for iloop = 1 : nloop
    if iloop <= nalt
        updateParams_();
    end
    % We must update the data in every loop because the deterministic trends
    % might have changed.
    updateData_();
    for i = 1 : neqtn
        aux = this.eqtnF{i}(x,t,L);
        evaleqtn(i,:,iloop) = permute(aux,[2,1]);
    end
end

% Convert results to tseries.
comments = this.eqtnlabel(this.eqtntype <= 2);
comments = comments(1,:,ones([1,nloop]));
x = tseries();
x.start = range(1);
x.data = permute(evaleqtn,[2,1,3]);
x.Comment = comments;
x = mytrim(x);


%***********************************************************************
% Nested function getNdata_().
    function ndata = getNdata_()
        ndata = 1;
        for i = 1 : length(this.nametype <= 3)
            x = d.(this.name{i});
            if istseries(x)
                tmpsize = size(x);
                ndata = max([ndata,prod(tmpsize(2:end))]);
            end
        end
    end
% End of nested function getNdata().

%***********************************************************************
% Nested function updateParams_().
    function updateParams_()
        % Update parameters.
        p = this.Assign(1,this.nametype == 4,iloop);
        x(:,this.nametype == 4,t) = p(ones([1,nrange]),:);
        
        % Update steady-state levels.
        L = real(this.Assign(1,:,iloop));
        
        % Update deterministic trends.
        W = mydtrendsrequest(this,'range',rangex,iloop);
        W = permute(W,[2,1]);
        % The `dtrendsrequest` function does not delogarithmise the
        % deterministic trends.
        isLog = this.log(this.nametype == 1);
        W(:,isLog) = exp(W(:,isLog));
    end
% End of nested function updateParams_().

%***********************************************************************
% Nested function updateData_().
    function updateData_()
        x(:,this.nametype <= 3,:) = NaN;
        for i = find(this.nametype <= 3)
            try
                % Get the range data for the iloop-th data set.
                aux = rangedata(d.(this.name{i}),rangex);
                aux = aux(:,:);
                aux = aux(:,min([iloop,ndata]));
                % Correct measurement variables for deterministic trends.
                if this.nametype(i) == 1
                    if this.log(i)
                        aux = aux ./ W(:,i);
                    else
                        aux = aux - W(:,i);
                    end
                end
            catch
                aux = nan([nrangex,1]);
            end
            if this.nametype(i) == 3
                aux(isnan(aux)) = 0;
            end
            for j = 1 : nrange
                x(j,i,1:end) = permute(aux((j+t-1)+mint:(j+t-1)+maxt),[2,3,1]);
            end
        end
    end
% End of nested function updateData_().

end
