classdef FEDisplay < matlab.mixin.CustomDisplay
%FEDisplay Custom display class for PDE unified workflow objects.

% Copyright 2022 The MathWorks, Inc.

    properties(Hidden)
        DisplayAnalysisType (1,1) string = ""
        DisplayPropertyList (1,:) string = ""
        DisplayGroups (:,2) cell = {}
    end

    methods(Hidden)
        function displayAllProperties(obj)
            % Display method for "show all properties" link
            displayRowsOrGroups(obj,"");
        end

        function displayRowsOrGroups(obj,props)
            grps = obj(1).DisplayGroups;
            if isempty(grps)
                displayRows(obj,props);
            else
                displayByGroups(obj,grps,props);
            end
        end

        function displayRows(obj,propList)
            % Tabular display of properties without header or footer
            arguments
                obj
                propList (1,:) string = ""
            end

            allprops = string(properties(obj))';
            if propList==""
                propList = allprops;
            else
                propList = intersect(propList,allprops,'stable');
            end

            headings = ["Index", propList];
            padding = "    ";
            align = "center";
       
            % set up tabular layout: property labels, indices, then body
            layout = strings(numel(obj)+1,numel(propList)+1);
            layout(1,:) = headings;
            layout(2:end,1) = string(1:numel(obj));
            for j=1:numel(propList)
                layout(2:end,j+1) = cellfun(@makeString,{obj.(propList(j))});
            end

            % adjust spacing and print
            widths = max(strlength(layout));
            layout = strjust(pad(layout,widths),align);

            for line=layout'
                fprintf("%s\n",join(line,padding));
            end
            fprintf("\n");
           
            function x = makeString(x)
                if isempty(x)
                    x = "[]";
                elseif isstring(x) || (isnumeric(x) && isscalar(x)) || isa(x,"function_handle")
                    x = strtrim(formattedDisplayText(x));
                elseif isnumeric(x) && isvector(x) && ~isscalar(x) && numel(x) < 4 % short vector
                    x = "[" + join(arrayfun(@makeString,x)," ") + "]";
                else % matrix or other datatypes, e.g. Results objects
                    sz = strtrim (join(string(size(x)),...
                        matlab.internal.display.getDimensionSpecifier));
                    x = "[" + sz + " " + class(x) + "]";
                end
            end
        end

        function displayByGroups(obj,layout,props)
            % Display property groups, for femodel

            if props ~= "" % prune down the groups to a subset of properties
                for k=1:size(layout,1)
                    list = layout{k,2};
                    layout{k,2} = list(ismember(list,obj.DisplayPropertyList));
                end
            end
            
            propgrp = matlab.mixin.util.PropertyGroup.empty;
            for k=1:size(layout,1)
                if ~isempty(layout{k,2})
                    propgrp(end+1) = matlab.mixin.util.PropertyGroup(layout{k,2},layout{k,1});
                end
            end

            matlab.mixin.CustomDisplay.displayPropertyGroups(obj,propgrp);
        end
    end

    methods(Access = protected)

        function displayNonScalarObject(obj)
             if isempty(obj(1).DisplayGroups) % vector property
                  displayScalarObject(obj,inputname(1));
             else
                 % No custom display for femodel object arrays
                 displayNonScalarObject@matlab.mixin.CustomDisplay(obj);
             end
        end

        function displayScalarObject(obj,name)
            if nargin < 2
                name = inputname(1);
            end

            header = obj(1).DisplayAnalysisType;
            props = obj(1).DisplayPropertyList;

            if header ~= ""
                header = sprintf("\nProperties for analysis type: %s\n",header);
            end

            % Add class descriptor before header
            cName = matlab.mixin.CustomDisplay.getClassNameForHeader(obj);
            dimstr = matlab.mixin.CustomDisplay.convertDimensionsToString(obj);
            cHeader = [dimstr,' ',cName,' array'];
            header = sprintf("  %s\n%s\n",cHeader,header);

            fprintf(header);

            displayRowsOrGroups(obj,props);

            if props ~= ""
                footer = getFooter(obj,name);
                disp(footer);
            end
        end

        function footer = getFooter(~,var)
            if nargin < 2
                var = inputname(1);
            end
            msg = getString(message('MATLAB:graphicsDisplayText:FooterLinkFailureMissingVariable',var));
            linktext = getString(message('MATLAB:graphicsDisplayText:AllPropertiesText'));
            linkcmd = sprintf("if exist('%s','var'), ",var) + ...
                sprintf("displayAllProperties(%s); ",var) + ...
                sprintf("else, disp('%s'), end",msg);

            footer = sprintf("  Show <a href=""matlab:%s"">%s</a>\n",linkcmd,linktext);
        end

    end     
    
end
