function [gettableProps, settableProps, allSettingsProps, allSettingsConstraints] = getPropertiesAndConstraints(metaClassObj)
% For a given metaclass return all gettable properties, settable
% properties, all properties, and all constraints on settable properties.

%   Copyright 2017 The MathWorks, Inc.

import parallel.internal.customattr.Reflection

persistent propClassMap

validateattributes(metaClassObj, {'parallel.internal.customattr.MetaClass'}, {}, 'getSettingsProps', 'classObj')

if isempty(propClassMap)
    propClassMap = containers.Map();
end

className = metaClassObj.Name;
if ~propClassMap.isKey(className)
    [allProps, useGetSet, gettableConstraints] = Reflection.getAllPublicProperties(metaClassObj);
    gettableSettingsProps = allProps(useGetSet);
    gettableConstraints = gettableConstraints(useGetSet);
    
    [~, ~, settableSettingsProps] = Reflection.getAllUserSettableProperties(metaClassObj);
    [~, gettableIdx, settableIdx] = union(gettableSettingsProps, settableSettingsProps);
    
    settableConstraints = cellfun(@(x) Reflection.getConstraint(metaClassObj, x), ...
        settableSettingsProps(settableIdx), 'UniformOutput', false);
    
    allSettingsProps        = [settableSettingsProps(settableIdx), gettableSettingsProps(gettableIdx)];
    allSettingsConstraints  = [settableConstraints, gettableConstraints(gettableIdx)];
    propClassMap(className) = {gettableSettingsProps, settableSettingsProps, allSettingsProps, allSettingsConstraints};
end

props = propClassMap(className);
gettableProps = props{1};
settableProps = props{2};
allSettingsProps = props{3};
allSettingsConstraints = props{4};
end