function varargout = tfestimate(x,y,varargin)
%TFESTIMATE   Transfer Function Estimate.
%
%   Txy = TFESTIMATE(X,Y)
%   Txy = TFESTIMATE(X,Y,WINDOW)
%   Txy = TFESTIMATE(X,Y,WINDOW,NOVERLAP)
%   [Txy,W] = TFESTIMATE(X,Y,WINDOW,NOVERLAP,NFFT)
%   [Txy,W] = TFESTIMATE(X,Y,WINDOW,NOVERLAP,W)
%   [Txy,F] = TFESTIMATE(X,Y,WINDOW,NOVERLAP,NFFT,Fs)
%   [Txy,F] = TFESTIMATE(X,Y,WINDOW,NOVERLAP,F,Fs)
%   [...] = TFESTIMATE(...,'mimo')
%   [...] = TFESTIMATE(...,'Estimator',EST)
%   [...] = TFESTIMATE(...,FREQRANGE)
%   TFESTIMATE(...)
%
%   See also TFESTIMATE, GPUARRAY.

%   Copyright 2022-2023 The MathWorks, Inc.

narginchk(2,10);
if nargin > 2
    [varargin{:}] = convertStringsToChars(varargin{:});
end

% Check if WINDOW or NFFT is on GPU
% WINDOW and NFFT are on GPU when each is a vector and a gpuArray
isNFFTSecondArg = false;
[windowOrNFFTOnGPU,windowIsVector,nfftIsVector,nfftArgInd,extraArgInd] = ...
    signal.internal.gpu.utilities.isWindowNFFTOnGPU(isNFFTSecondArg,varargin{:});

onGPU = false;
% Both input signals, window (if it is a nonempty numeric vector), and
% NFFT (if it is a nonempty vector) determine whether the calculation
% is done on the GPU and the output datatype
if isgpuarray(x) || isgpuarray(y) || windowOrNFFTOnGPU
    onGPU = true;
    % Ensure that the input signal is on the GPU
    x = gpuArray(x);
    y = gpuArray(y);
    % Check that a window vector has been provided. If so, ensure that
    % it is on the GPU
    if windowIsVector
        varargin{1} = gpuArray(varargin{1});
    end
    % If a vector NFFT is provided, make sure it is on GPU
    if nfftIsVector
        varargin{nfftArgInd} = gpuArray(varargin{nfftArgInd});
    end
    % Gather all extra arguments except for NFFT
    [varargin{extraArgInd}] = gather(varargin{extraArgInd});
else
    % Gather all extra arguments
    [varargin{:}] = gather(varargin{:});
end

% Dispatch in-memory tfestimate if input signal is not gpuArray or input
% window vector is not gpuArray
if ~onGPU
    varargout = cell(1,nargout);
    [varargout{:}] = tfestimate(x,y,varargin{:});
    return;
end

[funcName,idx] = signal.internal.tfestimate.parseEstimator(varargin{:});
if idx == 0
    args = varargin;
else
    args = {varargin{1:idx-1},varargin{idx+2:end}};
end

% Possible outputs are:
%       Plot
%       Txy
%       Txy, freq
[varargout{1:nargout}] = welch({x,y},funcName,args{:});

if nargout == 0
    title(getString(message('signal:dspdata:dspdata:WelchTransferFunctionEstimate')));
end
end

%--------------------------------------------------------------------------
