function [X,T,INFO] = stftmag2sig(S,varargin)
%STFTMAG2SIG Signal reconstruction from STFT magnitude on the GPU
%
%   X = STFTMAG2SIG(S,NFFT)
%   X = STFTMAG2SIG(S,NFFT,Fs)
%   X = STFTMAG2SIG(S,NFFT,Ts)
%   X = STFTMAG2SIG(...,'Window',WINDOW)
%   X = STFTMAG2SIG(...,'OverlapLength',NOVERLAP)
%   X = STFTMAG2SIG(...,'FrequencyRange',FREQRANGE)
%   X = STFTMAG2SIG(...,'Method',METHOD)
%   X = STFTMAG2SIG(...,'InitializePhaseMethod',INITPHASEMETHOD)
%   X = STFTMAG2SIG(...,'InitialPhase',INITPHASE)
%   X = STFTMAG2SIG(...,'MaxIterations',MAXITERATIONS)
%   X = STFTMAG2SIG(...,'InconsistencyTolerance',INCONSTOL)
%   X = STFTMAG2SIG(...,'InputTimeDimension',TIMEDIMENSION)
%   X = STFTMAG2SIG(...,'Method','fgla','UpdateParameter',ALPHA)
%   X = STFTMAG2SIG(...,'Display',DISPLAY)
%   [X,T] = STFTMAG2SIG(...)
%   [X,T,INFO] = STFTMAG2SIG(...)
%
%   Limitations:
%   'legla' method is not supported.
%
%   See also STFT, ISTFT, GPUARRAY.

%   Copyright 2020-2023 The MathWorks, Inc.

narginchk(1,27);
nargoutchk(0,3);

% Gather all extra arguments except Window and InitPhase. If Window or
% InitPhase has been provided as a gpuArray, also send the input signal X
% to the GPU.
if nargin > 1
    k = 1;
    while k <= numel(varargin)
        % Loop through varargin to check if 'Window' or 'InitialPhase'
        % name-value pair has been specified
        currentArg = varargin{k};
        if (isStringScalar(currentArg) || ischar(currentArg)) ...
                && (startsWith('Window', currentArg, 'IgnoreCase', true) ...
                || startsWith('InitialPhase', currentArg, 'IgnoreCase', true))
            % check for window and initial phase
            value = varargin{k+1};
                
            if isgpuarray(value)
                S = gpuArray(S);
            end
            k = k + 2;
        else
            varargin{k} = gather(currentArg);
            k = k + 1;
        end
    end
end

isOnGPU = isgpuarray(S);

% Dispatch to in-memory STFTMAG2SIG if the input signal S is not a
% gpuArray. It will already have been sent to the GPU if the window
% argument was on the GPU.
if ~isOnGPU
    [X,T,INFO] = stftmag2sig(S,varargin{:});
    return
end

%---------------------------------
%Parse input
% Validate input stft data attributes
validateattributes(S,{'single','double'},...
    {'nonsparse','finite','nonnan','3d','nonnegative','real'},'stftmag2sig','S');

dataType = underlyingType(S);

%--------------------------------------
% Parse name-value pairs
opts = signal.internal.stftmag2sig.stftmag2sigParser(size(S),dataType,varargin{:});

if isOnGPU && strcmp(opts.Method,'legla')
    error(message('signal:stftmag2sig:GPUArrayNotSupportedForLEGLA'))
end

%---------------------------------------
% Phase reconstruction
switch opts.Method
    case "gd"
        [X,T,INFO] = signal.internal.stftmag2sig.computeSTFTmag2sigGD(cast(S,opts.DataType),opts);  
    otherwise
        [X,T,INFO] = signal.internal.stftmag2sig.computeSTFTmag2sig(cast(S,opts.DataType),opts);
end
