function [OPT,THIS,MLLFUNC] = mypreloglik(THIS,RANGE,DOM,TUNE,varargin)
% MYPRELOGLIK  [Not a public function] Prepare for likelihood function evaluation.
%
% Backend IRIS function.
% No help provided.

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

if strncmpi(DOM,'t',1)
    % Time domain opt.
    OPT = passvalopt('model.kalman',varargin{:});
    OPT.domain = 't';
    OPT.ahead = 1;
    MLLFUNC = @mykalman;
elseif strncmpi(DOM,'f',1)
    % Freq domain opt.
    OPT = passvalopt('model.fdlik',varargin{:});
    OPT.domain = 'f';
    MLLFUNC = @myfdlik;
end

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

nper = length(RANGE);
ny = sum(THIS.nametype == 1);

% Time trend for dtrend equations.
OPT.ttrend = myrange2ttrend(THIS,RANGE);

if ischar(OPT.dtrends)
    OPT.dtrends = ~OPT.deviation;
end

% Measurement variables excluded from likelihood function.
if isempty(OPT.exclude)
    OPT.exclude = false(ny,1);
elseif islogical(OPT.exclude)
    OPT.exclude = OPT.exclude(:);
    if length(OPT.exclude) < ny
        OPT.exclude(end+1:ny) = false;
    elseif length(OPT.exclude) > ny
        OPT.exclude = OPT.exclude(1:ny);
    end
elseif ~isempty(OPT.exclude) && ~islogical(OPT.exclude)
    tmpindex = [];
    if ischar(OPT.exclude)
        OPT.exclude = regexp(OPT.exclude,'\w+','match');
    end
    if iscellstr(OPT.exclude)
        tmpindex = strfun.findnames( ...
            THIS.name(THIS.nametype == 1),OPT.exclude(:)');
        if any(isnan(tmpindex))
            warning_(1,OPT.exclude(isnan(tmpindex)));
            tmpindex = tmpindex(~isnan(tmpindex));
        end
    end
    OPT.exclude = false(ny,1);
    OPT.exclude(tmpindex) = true;
end

% Out-of-lik parameters.
if isempty(OPT.outoflik)
    OPT.outoflik = [];
else
    if ischar(OPT.outoflik)
        OPT.outoflik = regexp(OPT.outoflik,'\w+','match');
    end
    OPT.outoflik = OPT.outoflik(:)';
    offset = sum(THIS.nametype < 4);
    index = offset + ...
        strfun.findnames(THIS.name(THIS.nametype == 4),OPT.outoflik);
    isnanindex = isnan(index);
    if any(isnanindex)
        % Unknown parameter names.
        utils.error('model', ...
            ['This parameter name does not exist ', ...
            'in the model object: ''%s''.'], ...
            OPT.outoflik{isnanindex});
    end
    OPT.outoflik = index;
end
OPT.outoflik = OPT.outoflik(:).';
npout = length(OPT.outoflik);
if npout > 0 && ~OPT.dtrends
    utils.error('model', ...
        ['Cannot estimate out-of-likelihood parameters ', ...
        'with the option ''dtrends='' false.']);
end

% OPTIONS FOR TIME DOMAIN ONLY
% =============================

if OPT.domain == 't'
    % Time-varying stdcorr vector; 'clip' means the stdcorr vector will be
    % cut at the last user-supplied period.
    OPT.stdcorr = mytune2stdcorr(THIS,RANGE,TUNE,OPT,'clip');
    
    % User-supplied tunes on the mean of shocks.
    if ~isempty(TUNE)
        % Tunes on shocks.
        if ~isempty(TUNE)
            % Request shock data.
            TUNE = datarequest('e',THIS,TUNE,RANGE);
            if all(TUNE(:) == 0)
                TUNE = [];
            end
        end
    end
    OPT.tune = TUNE;
    
    % Calculate forward expansion if needed.
    if ~isempty(OPT.tune)
        k = find(any(any(TUNE ~= 0,3),1),1,'last');
        if ~isempty(k) && k > 0
            THIS = expand(THIS,k);
        end
    end
end

% Objective function.
if OPT.domain == 't'
    switch lower(OPT.objective)
        case {'prederr'}
            % Weighted prediction errors.
            OPT.objective = 2;
            if isempty(OPT.weighting)
                OPT.weighting = sparse(eye(ny));
            elseif numel(OPT.weighting) == 1
                OPT.weighting = sparse(eye(ny)*OPT.weighting);
            elseif any(size(OPT.weighting) == 1)
                OPT.weighting = sparse(diag(OPT.weighting));
            end
            if size(OPT.weighting,1) ~= ny || ndims(OPT.weighting) > 2
                utils.error('model', ...
                    ['Size of prediction error weighting matrix ', ...
                    'must match number of observables.']);
            end
        case {'loglik','mloglik','-loglik'}
            % Minus log likelihood.
            OPT.objective = 1;
        otherwise
            error('iris:model', ...
                'Unknown objective function: ''%s''.', ...
                OPT.objective);
    end
end

% Range on which the objective function will be evaluated. The `'objrange='`
% option gives the range from which sample information will be used to
% calculate the objective function and estimate the out-of-lik parameters.
if OPT.domain == 't'
    if ~isempty(OPT.objectivesample)
        % For bkw compatibility only.
        OPT.objrange = OPT.objectivesample;
    end
    if isequal(OPT.objrange,Inf)
        OPT.objrange = true(1,nper);
    else
        start = max(1,round(OPT.objrange(1) - RANGE(1) + 1));
        End = min(nper,round(OPT.objrange(end) - RANGE(1) + 1));
        OPT.objrange = false(1,nper);
        OPT.objrange(start : End) = true;
    end
end

% User-supplied initial conditions.
if OPT.domain == 't'
    if isstruct(OPT.initcond)
        [ainit,ans,ans,Painit] = ...
            datarequest('init',THIS,OPT.initcond,RANGE); %#ok<NOANS,ASGLU>
        if isempty(Painit)
            nb = size(THIS.solution{1},2);
            Painit = zeros(nb,nb,size(ainit,3));
        end
        OPT.initcond = {ainit,Painit};
        if any(isnan(ainit(:)))
            utils.warning('model', ...
                ['User-supplied initial condition for the mean ', ...
                'contains NaN.']);
        end
        if any(isnan(Painit(:)))
            utils.warning('model', ...
                ['User-supplied initial condition for the MSE matrix', ...
                'contains NaN.']);
        end
    end
end

% Last backward smoothing period. The option  lastsmooth will not be
% adjusted after we add one pre-sample init condition in `kalman`. This
% way, one extra period before user-requested lastsmooth will smoothed,
% which can be then used in `simulate` or `jforecast`.
if OPT.domain == 't'
    if isempty(OPT.lastsmooth) || isequal(OPT.lastsmooth,Inf)
        OPT.lastsmooth = 1;
    else
        OPT.lastsmooth = round(OPT.lastsmooth - RANGE(1)) + 1;
        if OPT.lastsmooth > nper
            OPT.lastsmooth = nper;
        elseif OPT.lastsmooth < 1
            OPT.lastsmooth = 1;
        end
    end
end

end