function Y = randsample(varargin)
%RANDSAMPLE Random sample on GPU, with or without replacement.
%   Y = RANDSAMPLE(N,K)
%   Y = RANDSAMPLE(POPULATION,K)
%   Y = RANDSAMPLE(N,K,REPLACE) or RANDSAMPLE(POPULATION,K,REPLACE)
%   Y = RANDSAMPLE(N,K,true,W) or RANDSAMPLE(POPULATION,K,true,W)
%   Y = RANDSAMPLE(S,...)
%
%   Sampling is performed on the GPU only if an input population is
%   provided and is on the GPU or weights are provided and are on the GPU.
%   When running on the GPU the GPU random number generator is used unless
%   an alternative random stream is passed in S.
%
%   See also RANDSAMPLE, GPUARRAY.

%   Copyright 2020 The MathWorks, Inc.

if nargin < 2
    error(message('stats:randsample:TooFewInputs'));
end

firstArgIsRNG = isa(varargin{1},"RandStream") ...
    || isa(varargin{1},"parallel.gpu.RandStream");
if firstArgIsRNG
    populationArg = 2;
    weightArg = 5;
else
    populationArg = 1;
    weightArg = 4;
end

if (isgpuarray(varargin{populationArg}) && ~isscalar(varargin{populationArg})) ...
        || (nargin>=weightArg && isgpuarray(varargin{weightArg}))
    % Run on GPU, but gather other flags
    toGather = populationArg+1:min(nargin, weightArg-1);
    [varargin{toGather}] = gather(varargin{toGather});
    % If running on the GPU and no RNG specified, use the GPU RNG
    if ~firstArgIsRNG
        varargin = [{parallel.gpu.RandStream.getGlobalStream()}, varargin];
    end
else
    % Don't run on GPU - just gather everything.
    [varargin{:}] = gather(varargin{:});
end

% Now just call the standard function
Y = parallel.internal.array.callToolboxFunction('stats/stats/randsample', varargin{:});
