function [FUN,nonlcon,X0,OUTPUT,optimState] = psArgCheck(caller,FUN,X0,Aineq,Bineq,Aeq,Beq,LB,UB,nonlcon)
%

% Copyright 2020 The MathWorks, Inc.

% Check for non-double inputs
if strcmp(caller,'patternsearch')
    msg = isoptimargdbl('PATTERNSEARCH', {'X0','A',   'b',   'Aeq', 'beq','LB','UB'}, ...
        X0,  Aineq, Bineq, Aeq,   Beq,  LB,  UB);
elseif strcmp(caller, 'paretosearch')
    msg = isoptimargdbl('PARETOSEARCH', {'NVARS','A',   'b',   'Aeq', 'beq','LB','UB'}, ...
        X0,  Aineq, Bineq, Aeq,   Beq,  LB,  UB);
end

if ~isempty(msg)
    error('globaloptim:psArgCheck:dataType',msg);
end

optimState = struct();
if strcmp(caller,'patternsearch')
    if isempty(X0)
        error(message('globaloptim:patternsearch:initialPoint'));
    end
    optimState.numberOfVariables = numel(X0);
elseif strcmp(caller, 'paretosearch')
    % Check NVARS is valid
    valid = isnumeric(X0) && isscalar(X0) && (X0 > 0) ...
        && (X0 == floor(X0));
    if ~valid
        error(message('globaloptim:paretosearch:invalidNvars'));
    end
    optimState.numberOfVariables = X0;
end

% If FUN is a cell array with additional arguments, handle them
if iscell(FUN)
    optimState.objFcnArg = FUN(2:end);
    FUN = FUN{1};
else
    optimState.objFcnArg = {};
end

% Only function_handle or inlines are allowed
if isempty(FUN) ||  ~(isa(FUN,'inline') || isa(FUN,'function_handle'))
    error(message('globaloptim:patternsearch:needFunctionHandleObj'));
end

% If NONLCON is a cell array with additional arguments, handle them
if iscell(nonlcon)
    optimState.conFcnArg = nonlcon(2:end);
    nonlcon = nonlcon{1};
else
    optimState.conFcnArg = {};
end
% Constraint function must be a function_handle or inline
if ~isempty(nonlcon) && ~(isa(nonlcon,'inline') || isa(nonlcon,'function_handle'))
    error(message('globaloptim:patternsearch:needFunctionHandleConstr'));
end

% Determine the 'type' of the problem
if ~isempty(nonlcon)
    type = 'nonlinearconstr';
    % Determine the sub-problem type for the constrained problem (used in ALPS)
    if (~isempty(Aeq)   && ~all(Aeq(:) == 0))   || ~isempty(Beq) || ...
            (~isempty(Aineq) && ~all(Aineq(:) == 0)) || ~isempty(Bineq)
        subtype = 'linearconstraints';
    elseif (~isempty(LB) && any(isfinite(LB(:)))) || ...
            (~isempty(UB) && any(isfinite(UB(:))))
        subtype = 'boundconstraints';
    else
        subtype = 'unconstrained';
    end
    % If Aeq or Aineq is not empty, then problem has linear constraints.
elseif (~isempty(Aeq)   && ~all(Aeq(:) == 0))   || ~isempty(Beq) || ...
        (~isempty(Aineq) && ~all(Aineq(:) == 0)) || ~isempty(Bineq)
    type = 'linearconstraints';
    % This condition satisfies bound constraints
elseif (~isempty(LB) && any(isfinite(LB(:)))) || ...
        (~isempty(UB) && any(isfinite(UB(:))))
    type = 'boundconstraints';
    % If all constraints fields are empty then it is unconstrained
else
    type = 'unconstrained';
end

% Initialize output structure
if strcmp(caller, 'patternsearch')
    OUTPUT = globaloptim.patternsearch.createOutputStruct(FUN, type, [], [], [], 0, 0, []);
elseif strcmp(caller, 'paretosearch')
    OUTPUT = globaloptim.paretosearch.createOutputStruct(0, 0, [], [], [], [], []);
end

% If nonlinear constraints, then subtype is needed to process linear
% constraints (see function preProcessLinearConstr)
if strcmp(type,'nonlinearconstr')
    type = subtype;
end
% Store linear constraint information that is used by direction generators
optimState.linconstrtype = type;
optimState.nineqcstr = size(Aineq,1);
optimState.neqcstr   = size(Aeq,1);
optimState.ncstr     = size(Aineq,1) + size(Aeq,1);
optimState.StartTime = tic;

