classdef BuildInfo < RTW.BuildInfoBuildObj & matlab.mixin.CustomDisplay
%RTW.BuildInfo class
%   RTW.BuildInfo extends RTW.BuildInfoBuildObj.
%

%   Copyright 2017-2023 The MathWorks, Inc.

    properties
        ComponentName char = '';
        Tokens RTW.BuildInfoKeyValuePair = RTW.BuildInfoKeyValuePair.empty;
        BuildArgs RTW.BuildInfoKeyValuePair = RTW.BuildInfoKeyValuePair.empty;
        MakeVars RTW.BuildInfoKeyValuePair = RTW.BuildInfoKeyValuePair.empty;
        MakeArgs char = '';
        SysLib = RTW.BuildInfoModules.empty;
    end
    properties(Hidden=true)
        Viewer = [];
        TargetPreCompLibLoc char = '';
        TargetLibSuffix char = '';
    end
    properties(SetAccess=private, Dependent=true)
        LinkObj RTW.BuildInfoLinkObj
    end
    properties(Dependent=true)
        ModelRefs RTW.BuildInfoLinkObj
    end
    properties (Dependent = true, Hidden = true, SetAccess=private)
        % All linkable objects - includes both LinkObj and ModelRefs
        % (directly owned and from searching hierarchy)
        Linkables
    end
    properties(SetAccess=private, Hidden=true)
        % Linkable objects owned directly by this buildInfo
        LinkablesDirect RTW.BuildInfoLinkObj = RTW.BuildInfoLinkObj.empty;
    end
    properties(SetAccess=private, Hidden=true, Transient=true)
        % Checksum used to determine if the full buildInfo hierarchy loaded
        % in memory is up to date (i.e. transient property LinkablesInternal
        % is populated and valid)
        LinkablesDirectChecksum = {};
    end
    properties(SetAccess=private, Transient=true, Hidden=true)
        % Ordered linkable objects (cached value that skips searching hierarchy)
        LinkablesInternal RTW.BuildInfoLinkObj = RTW.BuildInfoLinkObj.empty;
    end
    properties(Dependent=true, SetAccess=private, Hidden=true)
        % LinkObjs owned directly by this component
        LinkObjsDirect
        
        % ModelRefs owned directly by this component
        ModelRefsDirect

        % Compiler requirements owned directly by this component
        CompilerRequirementsDirect
    end
    
    properties (Dependent = true, Hidden = true, Access=public)
        % ModelName is an alias for ComponentName
        % ComponentName should be preferred to ModelName
        ModelName char;
        CompilerRequirements
    end
    
    properties (Hidden = true)
        DisallowedBuildVariants (1,:) coder.make.enum.BuildVariant = ...
            coder.make.enum.BuildVariant.empty(1,0)
    end
    % Properties that must not be serialized
    properties(Hidden = true, Transient=true)
        ModelHandle double = 0;
        BuildTools = [];
        ComponentBuildFolder char = ''
    end
    
    properties (Access=private)
        ReportInfo = [];
    end
    
    methods(Access=private)
        function clearReportInfo(this)
            this.ReportInfo = [];
        end
    end

    methods
        function val = get.Linkables(this)
            % Load child buildInfos
            loadChildBuildInfos(this);
            val = this.LinkablesInternal;
        end
        
        function val = get.LinkObjsDirect(this)
            val = this.LinkablesDirect...
                (~strcmp({this.LinkablesDirect.Group}, coder.make.internal.BuildInfoGroup.ModelRefGroup));
        end
        
        function val = get.ModelRefsDirect(this)
            val = this.LinkablesDirect...
                (strcmp({this.LinkablesDirect.Group}, coder.make.internal.BuildInfoGroup.ModelRefGroup));
        end
        
        function set.LinkObjsDirect(this, val)
            this.LinkablesDirect = [this.ModelRefsDirect; val];
        end
        
        function set.ModelRefsDirect(this, val)
            this.LinkablesDirect = [val; this.LinkObjsDirect];
        end
        
        function set.LinkObj(this, val)
            this.LinkObjsDirect = val;
        end
        
        function set.ModelRefs(this, val)
            this.ModelRefsDirect = val;
        end
        
        function val = get.LinkObj(this)
            val = this.Linkables;
            val = val(~strcmp({val.Group}, coder.make.internal.BuildInfoGroup.ModelRefGroup));
        end
        
        function val = get.ModelRefs(this)
            val = this.Linkables;
            val = val(strcmp({val.Group}, coder.make.internal.BuildInfoGroup.ModelRefGroup));
        end
        
        function val = get.CompilerRequirementsDirect(this)
            % Compiler requirements owned directly by this component (non including 
            % requirements owned by any child component)
            val = getCompilerRequirements(this.Settings);
        end
        
        function val = get.CompilerRequirements(this)
            val = getCompilerRequirements(this);
        end
        
        function set.CompilerRequirements(this, val)
            setCompilerRequirements(this.Settings, val)
        end
        
        function set.ComponentBuildFolder(this, val)
        % The component build folder is always stored as a relative path. It can be
        % specified directly as a relative path or as a path beginning with the $(START_DIR)
        % root folder.
            
            if ~isempty(val) 
                lRootFolder = this.Settings.LocalAnchorDir;
                if isempty(lRootFolder)
                    lRootFolder = pwd;
                end
                
                % Make sure we have a canonical path
                if coder.make.internal.isRelativePath(val) 
                    val = fullfile(lRootFolder, val);
                end
                val = builtin('_canonicalizepath', val);
                
                assert(startsWith...
                       (val, lRootFolder), ...
                       'The component build folder must be a relative path or path starting with %s', ...
                       lRootFolder)
                
                % Obtain a relative path by stripping off the leading "<root folder>", 
                % for example, if root folder is "Z:\" then "Z:\build_folder" becomes
                % "build_folder" or if root folder is "Z:\myfolder" then "Z:\my_folder\build_folder"
                % becomes "\build_folder"
                val = val((length(lRootFolder)+1:end));
                
                % Remove any leading file separator
                val = regexprep(val, ['^' regexptranslate('escape', filesep)], '');
            end
            this.ComponentBuildFolder = val;
        end
            

        function h = BuildInfo(handle)
            arguments
                handle  = 0
            end
            
            if (handle ~= 0)
                h.ModelName = get_param(handle,'Name');
                h.ModelHandle  = handle;
            else
                h.ModelName = 'untitled';
                h.ModelHandle  = 0;
            end
            
            h.Settings     = RTW.BuildInfoSettings;
            h.Options      = RTW.BuildInfoOptions();
            h.Inc          = RTW.BuildInfoModules('Includes');
            h.Src          = RTW.BuildInfoModules('Sources');
            h.Other        = RTW.BuildInfoModules('Other');
            h.SysLib       = RTW.BuildInfoModules('SysLibs');
            h.DisplayLabel = 'Build Info';
        end
        % ModelName is an alias for ComponentName
        % ComponentName should be preferred to ModelName
        function set.ModelName(obj,str)
            obj.ComponentName = str;
        end        
        function str = get.ModelName(obj)
            str = obj.ComponentName;
        end
    end


    methods        
        addBuildArgs(h,varargin)
        addExternalModeInfo(buildInfo,extModeTransport,rtiostreamSrcFileFullPath)
        addKeyValuePair(h,Type,varargin)
        addLCCSocketsLib(buildInfo)
        ret = addLibraries(h,varargin)
        ret = addLinkObjects(h,varargin)
        addMakeVars(h,varargin)
        ret = addPreincludeFiles(h, varargin)
        addSysLibPaths(h,varargin)
        ret = addSysLibs(h,varargin)
        addTMFTokens(h,varargin)
        val = areChildrenOrdered(h)
        checkForDups(~,fPathNames,names)
        ret = checkForUnresolvedFiles(h,varargin)
        removeKeyValuePair(h,Type,varargin)
        removeTMFTokens(h,varargin)
        removeBuildArgs(h,varargin)
        [key,val] = findBuildArg(h,keyname)
        findIncludeFiles(h,varargin)
        kvPair = findKeyValuePair(h,Type,keyName)
        ret = findLinkObject(h,libname)
        [key,val] = findTMFToken(h,keyname)
        [Keys,Vals] = getBuildArgs(h,varargin)
        ret = getBuildDirList(h,varargin)
        buildName = getBuildName(h)
        val = getChildren(h)
        dlgstruct = getDialogSchema(hSrc,schemaName)
        [fPathNames,names] = getFullFileList(h,varargin)
        Groups = getGroups(h)
        val = getHierarchicalChildren(h)
        [Keys,Vals] = getKeyValuePair(h,varargin)
        ret = getLibraryPaths(h,varargin)
        lObjs = getLinkObjects(h,varargin)
        ret = getLocalBuildDir(h)
        [MakeStrs,Vars,Vals] = getMakeVars(h)
        [syslibs,libpaths] = getSysLibInfo(h)
        v = getViewer(h)
        val = isHierarchical(h)
        packNGo(buildInfo,varargin)
        updateFilePathsAndExtensions(h,varargin)
        updateFileSeparator(h,varargin)
        varargout = addIncludeFiles(h,concatenatePaths,replaceMatlabroot,varargin)
        varargout = addIncludePaths(h,replaceMatlabroot,varargin)
        removeIncludePaths(h,pathsToRemove, groupsToRemove)
        varargout = addSourceFiles(h,concatenatePaths,replaceMatlabroot,varargin)
        varargout = addSourcePaths(h,replaceMatlabroot,varargin)
    end


    methods(Access = protected, Hidden=true)
        cpObj = copyElement(obj)
    end

    methods (Hidden)

        function setLinkablesDirect(obj, val)
            obj.LinkablesDirect = val;
        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.
                compilerRequirements = obj.CompilerRequirementsDirect;
                compilerRequirements.(fieldName) = value;
                setCompilerRequirements(obj.Settings, compilerRequirements);
            end
        end
        
        function cleanup = attachReportInfoPriorToSerialize(this, val)
            this.ReportInfo = val;
            cleanup = onCleanup(@()clearReportInfo(this));
        end
        
        function val = detachReportInfo(this)
            val = this.ReportInfo;
            clearReportInfo(this);
        end
        
        removeLinkObjects(h, linkObjNames, groups, groupsToKeep)
        removeLinkables(h, linkObjNames, groups, groupsToKeep)
        setRootFolder(h, val);
        setOutputFolder(h,lOutputFolder)
        resp = getBuildToolInfo(h,field)
        [sDirFiles,mlrFiles,fPathNames,names,pathToTopBuildInfo] = getHierarchicalFileList(h,fPathNames,names)
        postLoadUpdate(h,buildInfoMatPath)       
        replacePathString(h,oldStr,newStr)        
        setStartDir(h,startDir)
        setTargetProvidesMain(h,targetProvidesMain)
    end
    
    
    methods (Access = protected)
        % Customized display
        propgrp = getPropertyGroups(obj);
    end
end

