function y = ehtStreamDeparse(x,numCBPS,numBPSCS)  
%ehtStreamDeparse Stream deparser
%
%   Y = ehtStreamDeparse(X,NUMCBPS,NUMBPSCS) deparses the spatial
%   streams in input X to form encoded streams. This is the inverse of the
%   operation defined in IEEE 802.11-2016 Sections 19.3.11.8.2 and
%   21.3.10.6, and IEEE P802.11ax/D4.1, Section 27.3.11.6.
%
%   Y is a matrix of size (Ncbps*Nsym/Nes)-by-Nes containing stream
%   deparsed data, where Ncbps is the number of coded bits per OFDM symbol,
%   Nsym is the number of OFDM symbols, and Nes is the number of encoded
%   streams.
%
%   X is a matrix of size (Ncbpss*Nsym)-by-Nss containing stream parsed
%   data, where Ncbpss is the number of coded bits per OFDM symbol per
%   spatial stream, and Nss is the number of spatial streams.
%
%   NUMCBPS is a scalar specifying the number of coded bits per OFDM
%   symbol. NUMCBPS must be equal to NUMBPSCS*Nss*Nsd, where Nsd is one of
%   12, 24, 48, 51, 52, 102, 108, 117, 234, 468, 490, 980, 1960, or 3920.
%
%   NUMBPSCS is a scalar specifying the number of coded bits per subcarrier
%   per spatial stream. It must be equal to 1, 2, 4, 6, 8, 10, or 12.
%
%   Example 1:
%   % Stream parse 3 OFDM symbols with 2 encoded streams into 5 spatial  
%   % streams. Deparse the symbols into one encoded stream.
%
%       % Input parameters
%       numCBPS = 235200;
%       numBPSCS = 12;
%       numES = 1;
%       numSS = 5;
%       numSym = 3;
%
%       % Create input bits
%       bits = randi([0 1],numCBPS*numSym/numES,numES);
%
%       % Stream parser
%       parsedData = ehtStreamParse(bits,numSS,numCBPS,numBPSCS);
%
%       % Stream Deparse
%       deparsed = ehtStreamDeparse(parsedData,numCBPS,numBPSCS);
%       disp(isequal(bits,deparsed))
%
%   See also ehtStreamParse.

%   Copyright 2020 The MathWorks, Inc.

% Validate numBPSCS
if (~isnumeric(numBPSCS) || ~isscalar(numBPSCS) || ~any(numBPSCS==[1 2 4 6 8 10 12]))
    error('numBPSCS must be equal to 1, 2, 4, 6, 8, 10, or 12.');
end

% Validate numCBPS
validateattributes(numCBPS,{'numeric'},{'scalar'},mfilename,'numCBPS');

% Return an empty matrix if x is empty
if isempty(x)
    y = zeros(0,1);
    return;
end

% Validate input x
validateattributes(x,{'double'},{'2d'},mfilename,'Input x');

% Cross-validation between inputs
Nss = size(x,2);
numES = 1;
coder.internal.errorIf(~any(Nss==1:8), ...
    'wlan:wlanStreamParse:InvalidInputColumnsNUMSS'); % The number of columns of x must be a valid numSS
if ~any(numCBPS/(numBPSCS*Nss)==[24 36 48 63 72 102 126 234 468 702 980 1448 1682 1960 2428 2940 3408 3920])
    error('numCBPS must be equal to numBPSCS*numSS*Nsd, where Nsd is one of 24, 52, 108, 234, 468, 980, 1960, or 3920.'); 
end

if size(x,2)==1 % 1 spatial stream
    y = x;
else
    coder.internal.errorIf(mod(numel(x),numCBPS)~=0,'wlan:wlanStreamParse:InvalidInputSizeNUMCBPS'); % Integer number of OFDM symbols
    numSS = size(x,2);
    blkSize = max(1,numBPSCS/2); % IEEE Std 802.11-2016, Equation 21.68
    sumS = numSS*blkSize;
    numBlock = floor(numCBPS/(numES*sumS)); % IEEE Std 802.11-2016, Equation 21.69

    % Cross-validation between inputs and numSS (size(x,2))
    coder.internal.errorIf(~(numCBPS==numBlock*numES*sumS || numES==numSS),'wlan:wlanStreamParse:InvalidInputRelation');

    % Stream deparsing for all OFDM symbols
    % No tail in IEEE P802.11ax/D4.1, Section 27.3.11.6.
    tempX = reshape(x,blkSize,numES,[],numSS); % [blkSize,numES,numBlock*numSym,numSS]
    tempX = permute(tempX,[1 4 3 2]); % [blkSize,numSS,numBlock*numSym,numES]
    y = reshape(tempX,[],numES); % [(numCBPS*numSym/numES),numES]
end

end