function pars = build_parameters_structure_v6(R, opts, responseMatrixName, varargin)

%BUILD_PARAMETERS_STRUCTURE Build parameters structure for ENTROPY.m

%   Copyright (C) 2009 Cesare Magri
%   Version 4

% -------
% LICENSE
% -------
% This software is distributed free under the condition that:
%
% 1. it shall not be incorporated in software that is subsequently sold;
%
% 2. the authorship of the software shall be acknowledged and the following
%    article shall be properly cited in any publication that uses results
%    generated by the software:
%
%      Magri C, Whittingstall K, Singh V, Logothetis NK, Panzeri S: A
%      toolbox for the fast information analysis of multiple-site LFP, EEG
%      and spike train recordings. BMC Neuroscience 2009 10(1):81;
%
% 3.  this notice shall remain in place in each source file.

% ----------
% DISCLAIMER
% ----------
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
% IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
% THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
% PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
% PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

% Recap of the fields in the parameter structure
% ----------------------------------------------
%
% R-related parameters:
%   - pars.Nc
%   - pars.Ns
%   - pars.Nt
%   - pars.maxNt
%   - pars.totNt
%
% TESTMODE-related parameters:
%   - pars.testmode
%
% METHOD-related parameters:
%   - pars.methodFunc
%   - pars.methodNum
%
% EXTRAPOLATION-related parameters
%   - pars.xtrp
%
% BIAS-related parameters:
%   - pars.biasCorrNum
%   - pars.biasCorrFuncName
%
% BOOTSTRAP-related parameters:
%   - pars.btsp
%
% OUTPUT-related parameters:
%   - pars.whereHR
%   - pars.whereHRS
%   - pars.whereHlR
%   - pars.whereHlRS
%   - pars.whereHiR
%   - pars.whereChiR
%   - pars.whereHshR
%   - pars.whereHshRS
%   - pars.whereHiRS
%   - pars.doHR
%   - pars.doHRS
%   - pars.doHlR
%   - pars.doHlRS
%   - pars.doHiR
%   - pars.doHiRS
%   - pars.doChiR
%   - pars.doHshR
%   - pars.doHshRS
%
% CHECKS-related parameters:
%   - pars.addChecks
%   - pars.numberOfSpecifiedOptions
%   - pars.Noutput

opts.responseMatrixName = responseMatrixName;

if isempty(varargin)
    msg = 'No output option specified';
    error('buildParsStruct:noOutputOptSpecified', msg);
end


% R -----------------------------------------------------------------------
% The MEX functions require double type for working:
if ~strcmp(class(R), 'double')
    msg = 'Responses must be of type double.';
    error('buildParsStruct:RnotDouble', msg);
end
    
if ndims(R)<4
    [pars.Nc, size2ofR, pars.Ns] = size(R);
else
    msg = 'Response matrix can be at most a 3-D matrix.';
    error('buildParsStruct:Rnot3D', msg);
end;


% NT ----------------------------------------------------------------------
% The MEX functions require double type for working:
if ~strcmp(class(opts.nt), 'double')
    msg = 'opts.nt must be of type double.';
    error('buildParsStruct:NtNotDouble', msg);
end
    
% If the number of trials per stimulus is constant, NT can be provided 
% as a scalar. In this case, the array version is built internally.
if isscalar(opts.nt)
    pars.Nt = ones(pars.Ns,1) * opts.nt;
    pars.maxNt = opts.nt;
    pars.totNt = opts.nt* pars.Ns;
    
    pars.trials_indxes = 1:pars.totNt;
else
    if length(opts.nt)~=pars.Ns
        msg = ['size(' responseMatrixName ',3) must match length(opts.nt). Try transposing nt.'];
        error('buildParsStruct:lengthNt_vs_size3R', msg);
    end

    % R and NT compatibility:
    pars.Nt = opts.nt(:);
    pars.maxNt = max(pars.Nt);
    pars.totNt = sum(pars.Nt);
    
    pars.trials_indxes = findtrial(pars.Nt, pars.maxNt, pars.Ns);
end

% R and NT compatibility:
if pars.maxNt~=size2ofR
    msg = ['max(opts.nt) must be equal to size(' responseMatrixName ',2).'];
    error('buildParsStruct:maxNt_vs_size2R', msg);
end


% TEST MODE (optional) ----------------------------------------------------
pars.numberOfSpecifiedOptions = 0;
if isfield(opts, 'testMode') && opts.testMode
    pars.numberOfSpecifiedOptions = pars.numberOfSpecifiedOptions + 1;
    pars.testMode = true;
else
    pars.testMode = false;
end


% METHOD ------------------------------------------------------------------
pars.methodName = opts.method;
switch lower(opts.method)
    case {'dr'}
        pars.methodFunc = @direct_method_v6a;
        pars.methodNum = 1;
        
    case {'gs'}
        pars.methodFunc = @gaussian_method_v7_1_0;
        pars.methodNum = 2;
        
% % %     case {'gsfast'}
% % %         pars.methodFunc = @gaussian_method_v11;
% % %         pars.methodNum = 3;
% % %         pars.covfunc = @fastcov_v2;
        
    otherwise
        if pars.testMode
            pars.methodFunc = str2func(opts.method);
            pars.methodNum = -1;
        else
            msg = ['Method option ' opts.method ' not found.'];
            error('buildParsStruct:methodNotFound', msg);
        end
end;


% BIAS --------------------------------------------------------------------
switch lower(opts.bias)
    case 'naive'
        pars.biasCorrNum = 0;
    case 'qe'
        pars.biasCorrNum = 1;
    case 'pt'
        pars.biasCorrNum = 2;
    case 'gsb'
        pars.biasCorrNum = 3;
    otherwise
        pars.biasCorrNum = -1;
        pars.biasCorrFuncName = opts.bias;
end


% BTSP (optional) ---------------------------------------------------------
if isfield(opts, 'btsp')
    pars.numberOfSpecifiedOptions = pars.numberOfSpecifiedOptions + 1;
    
    if round(opts.btsp)~=opts.btsp
        msg = 'opts.btsp must be an integer.';
        error('buildParsStruct:btspNotInteger', msg);
    else
        pars.btsp = opts.btsp;
    end
else
    % No bootstrap:
    pars.btsp = 0;
end


% XTRP (optional) ---------------------------------------------------------
if isfield(opts, 'xtrp')
    pars.numberOfSpecifiedOptions = pars.numberOfSpecifiedOptions + 1;
    
    if round(opts.xtrp)~=opts.xtrp
        msg = 'opts.xtrp must be a positive integer.';
        error('buildParsStruct:xtrpNotInteger', msg);
    else
        pars.xtrp = opts.xtrp;
    end
else
    % No average over repetitions:
    pars.xtrp = 1;
end


% OUTPUT LIST -------------------------------------------------------------
% Checking which output-options have been selected and keeping track of the
% position they have in VARARGIN: this will allow do provide the outputs in
% the correct order.
pars.Noutput = length(varargin); % number of ouputs

% varargin = lower(varargin);

% The following logical quantities need not to be saved into the pars
% structure:
whereHRSbs      = strcmpi(varargin, 'hrsbs'   );
whereHlRSbs     = strcmpi(varargin, 'hirsbs'  );
whereHiRbs      = strcmpi(varargin, 'hirbs'   );
whereChiRbs     = strcmpi(varargin, 'chirbs'  );
whereHshRSbs    = strcmpi(varargin, 'hshrsbs' );

% These instead are saved and used later:
pars.whereHR    = strcmpi(varargin, 'hr'      );
pars.whereHRS   = strcmpi(varargin, 'hrs'     ) | whereHRSbs;
pars.whereHlR   = strcmpi(varargin, 'hlr'     );
pars.whereHlRS  = strcmpi(varargin, 'hirs'    ) | whereHlRSbs;
pars.whereHiR   = strcmpi(varargin, 'hir'     ) | whereHiRbs;
pars.whereChiR  = strcmpi(varargin, 'chir'    ) | whereChiRbs;
pars.whereHshR  = strcmpi(varargin, 'hshr'    );
pars.whereHshRS = strcmpi(varargin, 'hshrs'   ) | whereHshRSbs;

% See note in ENTROPY regarding this quantity:
pars.whereHiRS  = strcmpi(varargin, 'hirsdef' );

if pars.Nc==1
    % If Nc=1 then computing HlR, HiR, ChiR or HshR is equivalent to
    % computing HR.
    pars.doHR    = any(pars.whereHR | pars.whereHlR | pars.whereHiR | pars.whereChiR | pars.whereHshR);
    
    % If Nc=1 then computing HlRS, HiR, HiRS or HshRS is equivalent to
    % computing HRS.
    pars.doHRS   = any(pars.whereHRS | pars.whereHlRS | pars.whereHiRS | pars.whereHshRS);
    pars.doHlR   = false;
    pars.doHlRS  = false;
    pars.doHiR   = false;
    pars.doHiRS  = false;
    pars.doChiR  = false;
    pars.doHshR  = false;
    pars.doHshRS = false;
    
    pars.doHlRSbs  = any(whereHlRSbs);
    pars.doHiRbs   = any(whereHiRbs);
    pars.doChiRbs  = any(whereChiRbs);
    pars.doHshRSbs = any(whereHshRSbs);
    
    % If Nc=1 we only compute the botstrap for HRS:
    pars.doHRSbs   = any(whereHRSbs) || pars.doHlRSbs || pars.doHiRbs || pars.doChiRbs || pars.doHshRSbs;
    pars.doHlRSbs  = false;
    pars.doHiRbs   = false;
    pars.doHiRSbs  = false;
    pars.doChiRbs  = false;
    pars.doHshRSbs = false;
    
else
    pars.doHR    = any(pars.whereHR   );
    pars.doHRS   = any(pars.whereHRS  );
    pars.doHlR   = any(pars.whereHlR  );
    pars.doHlRS  = any(pars.whereHlRS );
    pars.doHiR   = any(pars.whereHiR  );
    pars.doHiRS  = any(pars.whereHiRS );
    pars.doChiR  = any(pars.whereChiR );
    pars.doHshR  = any(pars.whereHshR );
    pars.doHshRS = any(pars.whereHshRS);
    
    pars.doHRSbs   = any(whereHRSbs);
    pars.doHlRSbs  = any(whereHlRSbs);
    pars.doHiRbs   = any(whereHiRbs);
    pars.doChiRbs  = any(whereChiRbs);
    pars.doHshRSbs = any(whereHshRSbs);
    
end

% For backward compatibility: if opts.btsp is provided but the quantities
% for which to apply bootstrap are not specified then bootstrap is computed
% for all possible quantities.
if ~any(pars.doHRSbs || pars.doHlRSbs || pars.doHiRbs || pars.doChiRbs || pars.doHshRSbs) && pars.btsp>0
    pars.doHRSbs   = pars.doHRS;
    pars.doHlRSbs  = pars.doHlRS;
    pars.doHiRbs   = pars.doHiR;
    pars.doChiRbs  = pars.doChiR;
    pars.doHshRSbs = pars.doHshRS;
    
end

% ADDCHECKS (optionals) ---------------------------------------------------
if isfield(opts, 'verbose') && opts.verbose
    pars.numberOfSpecifiedOptions = pars.numberOfSpecifiedOptions + 1;
    
    pars.addChecks = true;
    
else
    pars.addChecks = false;
    
end

if any(pars.addChecks)
	additional_checks_v5(R, pars, opts);
end;