classdef BuildInfoSettings < RTW.BuildInfoClass & handle
%RTW.BuildInfoSettings class
%   RTW.BuildInfoSettings extends RTW.BuildInfoClass.
%
%    RTW.BuildInfoSettings properties:
%       Settings - Property is of type 'handle'  
%       DisplayLabel - Property is of type 'ustring'  
%       Group - Property is of type 'ustring'  
%       FileSep - Property is of type 'ustring'  
%       Matlabroot - Property is of type 'ustring'   
%       LocalAnchorDir - Property is of type 'ustring'  
%       BuildInfoOutputFolder - Property is of type 'ustring'  
%       TargetInfo - Property is of type 'mxArray'  
%       DisablePackNGo - Property is of type 'bool'  
%       DisableReportInPackNGo - Property is of type 'bool'  
%       TargetProvidesMain - Property is of type 'bool'  
%       HasUnresolvedExtensions - Property is of type 'bool'  
%       HasUnresolvedPaths - Property is of type 'bool'  
%       CompilerRequirements - Property is of type 'struct'  


%   Copyright 2017-2020 The MathWorks, Inc.

    properties
        FileSep = '';
        Matlabroot = '';        
        LocalAnchorDir = '';
        BuildInfoOutputFolder = '';
        TargetInfo = [  ];
        DisablePackNGo = false;
        DisableReportInPackNGo = false;
        TargetProvidesMain = false;
        HasUnresolvedExtensions = false;
        HasUnresolvedPaths = false;
    end
    
    properties (SetObservable)    
       CompilerRequirements = coder.make.internal.CompilerRequirements;
    end

    methods
        function h = BuildInfoSettings(varargin)
        %BUILDINFOSETTINGS Class constructor (for RTW.BuildInfoSettings).
        % Instantiate class
        % override the base class display label. 
            h.DisplayLabel = 'Settings';
            
            % All BuildInfo classes have a handle to a settings object.  Since this is
            % the settings object, make sure the handle is empty.
            h.Settings = [];
            
            % default the FileSep property to whatever filesep for this platform is
            h.FileSep = filesep;
            
            % set the matlab root in the buildinfo to the current matlab install
            % dir
            h.updateMatlabRoot();
                        
            h.LocalAnchorDir  = '';
            h.BuildInfoOutputFolder = '';
            h.HasUnresolvedExtensions = false;    
            h.HasUnresolvedPaths      = false;
        end
    end

    methods 
        function set.DisablePackNGo(obj,value)
            value = logical(value); %  convert to logical
            obj.DisablePackNGo = value;
        end

        function set.DisableReportInPackNGo(obj,value)
            value = logical(value); %  convert to logical
            obj.DisableReportInPackNGo = value;
        end

        function set.TargetProvidesMain(obj,value)
            value = logical(value); %  convert to logical
            obj.TargetProvidesMain = value;
        end

        function set.HasUnresolvedExtensions(obj,value)
            value = logical(value); %  convert to logical
            obj.HasUnresolvedExtensions = value;
        end

        function set.HasUnresolvedPaths(obj,value)
            value = logical(value); %  convert to logical
            obj.HasUnresolvedPaths = value;
        end
    end

    methods
        function val = areChildrenOrdered(~)
        %ARECHILDRENORDERED - returns true if children are returned in a specific order
        %from getChildren and getHierarchicalChildren.
            val = true;
        end
        
        function val = getChildren(~)
        %GETCHILDREN - returns non-hierarchical child properties for DA Studio Explorer
            val = [];
        end
        
        function dlgstruct = getDialogSchema(~, ~)
        %GETDIALOGSCHEMA - returns the dialog struct for display in a DDG
            dlgstruct = [];
        end
        
        function val = getHierarchicalChildren(~)
        %GETHIERARCHICALCHILDREN - returns hierarchical child properties for DA Studio
        %explorer
            val = [];
        end
        
        function val = getPreferredProperties(h) %#ok
        %GETPREFERREDPROPERTIES - Returns the preferred properties for the DA Studio
        %Explorer
            val = {'FileSep' 'Matlabroot' 'LocalAnchorDir'};
        end
        
        function val = isHierarchical(~)
        %ISHIERARCHICAL - returns true if this class has hierarchical child properties.
            val = false;
        end
        
        function setCompilerRequirements(obj,varargin)
        %SETCOMPILERREQUIREMENTS - sets property CompilerRequirements. varargin expects 
        %name-value pairs to set values for the corresponding fields.
            assert(mod(numel(varargin), 2) == 0, 'Invalid input to setCompilerRequirements.  setCompilerRequirements takes a sequence of name-value pairs');
            for i = 1:2:numel(varargin)
                
                fieldName = varargin{i};
                value = varargin{i+1};
                
                % coder.make.internal.CompilerRequirements uses MCOS property validation.
                obj.CompilerRequirements.(fieldName) = value;
            end
        end        
    end

    methods (Hidden)
        function rc = getSpecialDirsAndTokens(h,varargin)
        %GETSPECIALDIRSANDTOKENS - Undocumented internal function
            opts = locCheckArgs(varargin{:});
            
            % for certain directories, the paths are replaced with makefile tokens.
            % Note that the Master and Local anchordirs map to the same token.
            % This is intentional so that parallel builds generate the same
            % makefile as sequential builds.
            %
            % NOTE: the matlabroot token must be the first in the list for proper
            % makefile generation (see RTW.genMakefileAndBuild usage of special dirs).
            dirs    = {h.Matlabroot h.LocalAnchorDir};
            toks    = {'$(MATLAB_ROOT)'  '$(START_DIR)'};
            tmfToks = {'|>MATLAB_ROOT<|' '|>START_DIR<|'};                
            
            % If the relativeAnchorOverride is not an empty character array the
            % user is requesting that the START_DIR token be replaced by a
            % specified relative path. Ensure the tokens are mapped to that
            % relative path.
            if ~isempty(opts.relativeAnchorOverride)
                dirs    = {h.Matlabroot opts.relativeAnchorOverride};
            end
            
            if ~opts.includeEmptyNames
                % strip out any emtpy dirs.
                emptyIdx = strcmp(dirs,''); % Equivalent to ismember, but faster. Do not modify.
                dirs     = dirs(~emptyIdx);
                toks     = toks(~emptyIdx);
                tmfToks  = tmfToks(~emptyIdx);
            end
            
            rc.dirs    = dirs;
            rc.toks    = toks;
            rc.tmfToks = tmfToks;
            
            if opts.includeAltNames
                rc.altNames = coder.make.internal.transformPaths(rc.dirs, 'ignoreErrors',true);
            end
            
            if opts.includeRegexpPats
                rc.regexpPats = regexptranslate('escape',rc.dirs);
                if opts.includeAltNames
                    rc.regexpAltNamePats = regexptranslate('escape',rc.altNames);
                end
            end
        end

        function updateMatlabRoot(h)
        % UPDATEMATLABROOT - updates the MATLAB root to the current install
        % directory
        % matlabroot may return the incorrect case, so we need to transform it to
        % the full name
            mlr = coder.make.internal.transformPaths(matlabroot,'pathType','full');
            h.Matlabroot = mlr;
        end
    end
    
    methods (Static, Access = public)
        function h = loadobj(s)
            % LOADOBJ
            %   Handle differences between objects serialized in earlier
            %   releases.
            if isstruct(s)
                h = RTW.BuildInfoSettings;
                fields = fieldnames(s);
                for k = 1:numel(fields)
                    if isprop(h, fields{k})
                        h.(fields{k}) = s.(fields{k});
                    end
                end
            else
                h = s;
            end
            
            if isstruct(h.CompilerRequirements)
               % If CompilerRequirements was previously a struct, then 
               % convert to MCOS.  
               
               % Cache the serialized value
               compilerRequirementsStruct = h.CompilerRequirements;
               
               % Construct a new coder.make.internal.CompilerRequirements object and copy
               % the fields that are present.
               h.CompilerRequirements = coder.make.internal.CompilerRequirements;
               fields = fieldnames(compilerRequirementsStruct);
               for currField = fields(:)'  % make sure is row
                   % Currently all permitted fields in the struct from
                   % R2018b/R2019a/R2019b are properties in the new MCOS
                   % object, so we do not currently need to validate that
                   % the property exists.
                   h.CompilerRequirements.(currField{:}) = compilerRequirementsStruct.(currField{:});
               end
            end
        end
    end
end

function opts = locCheckArgs(varargin)
    
    persistent parser;
    
    if isempty(parser)        
        parser = inputParser();
        parser.FunctionName = 'RTW.BuildInfoSettings.getSpecialDirsAndTokens';

        % Add includeEmptyNames
        paramName = 'includeEmptyNames';
        defaultValue = false;
        validationFcn = @islogical;

        parser.addParameter(paramName, defaultValue, validationFcn);

        % Add includeAltNames
        paramName = 'includeAltNames';

        parser.addParameter(paramName, defaultValue, validationFcn);

        % Add includeEmptyNames
        paramName = 'includeRegexpPats';

        parser.addParameter(paramName, defaultValue, validationFcn);          

        % Add relativeAnchorOverride    
        paramName = 'relativeAnchorOverride';
        defaultValue = '';
        validationFcn = @ischar;

        parser.addParameter(paramName, defaultValue, validationFcn);
    end

    parser.parse(varargin{:});
    opts = parser.Results;
end
