function this = chooseNextPointParallel(this)
% Choose the next point to evaluate, making use of predictions
% of pending points.
%

%   Copyright 2016-2022 The MathWorks, Inc.

if this.NumObjectiveEvaluations < size(this.QueuedX,1)
    % There are queued initial points
    this.XNext = this.QueuedX(this.NumObjectiveEvaluations + 1, :);
    this.FantasyModels = this;
    this.FantasyModels.FantasyModels = [];
    % Impute pending objective for plotting purposes only.
    if anyPendingX(this.Parallel)
        PendingXTable = conditionalizeX(this, this.Parallel.PendingX);
        this.PendingObj = imputeObjective(this, PendingXTable, 'modelprediction');
    end
elseif acqFcnIsNonBayes(this)
    % Either grid or random or asha. Choose point normally.
    this = chooseNextPoint(this);
    this.FantasyModels = this;
    this.FantasyModels.FantasyModels = [];
    % Impute pending objective for plotting purposes only.
    if anyPendingX(this.Parallel)
        PendingXTable = conditionalizeX(this, this.Parallel.PendingX);
        this.PendingObj = imputeObjective(this, PendingXTable, 'modelprediction');
    end
elseif ~anyPendingX(this.Parallel)
    % No pending X. Choose point normally.
    this = chooseNextPoint(this);
    this.FantasyModels = this;
    this.FantasyModels.FantasyModels = [];
else
    % We have pending points.
    % Predict objective, runtime, and constraints of pending points
    PendingXTable           = conditionalizeX(this, this.Parallel.PendingX);
    PendingObjective        = imputeObjective(this, PendingXTable, this.PrivOptions.ParallelMethod);
    PendingMeanRuntime      = predictObjectiveEvaluationTime(this, PendingXTable);
    PendingMeanConstraints  = predictConstraints(this, PendingXTable);
    PendingMeanError        = predictError(this, PendingXTable);
    % Make a copy of the BO object to do fantasy prediction
    BO2 = this;
    % Append predictions to training sets.
    BO2.XTrain = [BO2.XTrain; legalizePoints(BO2, BO2.Parallel.PendingX)];
    BO2.FTrain = [BO2.FTrain, PendingObjective'];
    BO2.ErrorTrain = [BO2.ErrorTrain; PendingMeanError];
    if BO2.PrivOptions.NumCoupledConstraints > 0
        BO2.ConstraintTrain = [BO2.ConstraintTrain; PendingMeanConstraints];
    end
    BO2.ObjectiveEvaluationTimeTrain = [BO2.ObjectiveEvaluationTimeTrain, PendingMeanRuntime'];
    % Refit models to all points including fantasy points
    BO2 = fitModels(BO2, true);
    % Choose next point using the fantasy models
    BO2         = chooseNextPoint(BO2);
    this.XNext  = BO2.XNext;
    % Save fantasy models for Acquisition Function plotting.
    % Save PendingObj for Objective model plotting.
    this.FantasyModels = BO2;
    this.FantasyModels.FantasyModels = [];
    this.PendingObj    = PendingObjective;
end
end
