function obj = squeeze(obj)
%SQUEEZE Remove singleton dimensions.
%   B = squeeze(A) returns a dlarray B with the same elements as A but with
%   all singleton dimensions removed. A singleton dimension is a dimension
%   such that size(A,dim)==1. If A has dimension labels, those belonging to
%   singleton dimensions are removed.
%
%   2-D dlarrays are unaffected by squeeze. If a formatted dlarray has more
%   than two dimensions, but all dimensions 3 and above are singleton, the
%   singleton dimensions and their labels are discarded.
%
%   See also SQUEEZE, DLARRAY.

%   Copyright 2019 The MathWorks, Inc.

[fdobj, objdata] = extractData(obj.FormattedData);

VtoDMap = obj.ViewToDataMap;
hasPermutations = ~isempty(VtoDMap);
if ~hasPermutations
    % Create a dummy ordering to use for correcting dimension labels
    nd = max(ndims(objdata), numel(fdobj.DimensionMetadata));
    VtoDMap = 1:nd;
end

if numel(VtoDMap)<=2
    % There are only two dimensions to work on, so we don't need to do anything
    return
end

% Find singleton dimensions that we want to squeeze out
[singletons, data_size] = iGetSingletonDimensions(objdata, VtoDMap);

% Remove labels that we don't need 
fdobj = iRemoveDimensionLabels(fdobj, singletons);

if ~hasPermutations
    % No implicit permutation means we can easily use squeeze on the underlying
    % data and update the labels to match.   
    objdata = squeeze(objdata);
else
    % We can't use squeeze because the first and second dimensions might be out
    % of position and they have special behaviour.  Instead we apply the same
    % algorithm that squeeze uses to our size vector and then use it to
    % reshape.
   
    % Remove the dimensions but make sure we have at least two size numbers
    data_size(singletons) = [];
    data_size(end+1:2) = 1;
    objdata = reshape(objdata, data_size);
    
    % Update the permutation vectors. We remove references to dimensions that
    % have been taken out of the data, then map the remaining old values down
    % into 1:newNDims.
    DtoVMap = obj.DataToViewMap;
    DtoVMap(singletons) = [];
    if numel(DtoVMap)<=1
        % This will occur if there is one non-singleton dimension that is in
        % dimension 3 or higher.  The result in the underlying data and for the
        % user is a column vector, so we don't need a permutation at all.
        VtoDMap = [];
        DtoVMap = [];
    else
        [~, VtoDMap] = sort(DtoVMap);
        DtoVMap = [];
        DtoVMap(VtoDMap) = 1:length(VtoDMap);
    end
    
    obj.ViewToDataMap = VtoDMap;
    obj.DataToViewMap = DtoVMap;
end

% Update stored data
obj.FormattedData = insertData(fdobj, objdata);

end


function [singletons, data_size] = iGetSingletonDimensions(objdata, VtoDMap)
nd = numel(VtoDMap);
data_size = size(objdata, 1:nd);
singletons = (data_size==1);
if all(singletons(VtoDMap(3:end)))
    % Don't change the first two dimensions if dimensions 3:end are all
    % singleton.  This will ensure that rows stay as rows.
    singletons(VtoDMap(1:2)) = false;
end
end


function fdobj = iRemoveDimensionLabels(fdobj, singletons)
% Remove dimension labels corresponding to the singleton dimensions in sz

dims = fdobj.DimensionMetadata;
if ~isempty(dims)
    % Remove labels for the singleton dimensions that squeezing removes.
    dims(singletons) = [];
    if isscalar(dims)
        % One remaining dimension, gain a trailing 'U'
        dims = [dims 'U'];
    end
    
    fdobj.DimensionMetadata = dims;
end
end
