function revertToTMFBuild(arg, varargin)
%REVERTTOMFBUILD Revert model or project to template makefile-based build.
% CODER.MAKE.REVERTTOTMFBUILD(MODEL) reverts the specified Simulink model
% to use a template makefile-based build.
%
% CODER.MAKE.REVERTTOTMFBUILD(MODEL, PARAM1, VALUE1, ..., PARAMN, VALUEN)
% is the same as above but with parameter-value pairs specified.
%
% Parameters (applicable to Simulink models only):
%
% 'ApplyToEntireHierarchy' - Apply the changes to all models in the model
%                            hierarchy. Default is true.
% 'SaveChanges'            - Automatically save the changes made on the
%                            model(s) or project. Default is false.
%
% At the end of the conversion, if the model or project was not initially
% open, the model or project will be closed except when there are unsaved
% changes.
%
% CODER.MAKE.REVERTTOTMFBUILD(Simulink.ConfigSet) configures the ConfigSet
% object such that, when attached to model, the model will use a template
% makefile-based build. 
%
% CODER.MAKE.REVERTTOTMFBUILD(Simulink.ConfigSet, PARAM1, VALUE1, ..., PARAMN, VALUEN)
% is the same as above but with parameter-value pairs specified.

% Copyright 2012-2018 The MathWorks, Inc.

options = processInputArgs(varargin);
inputType = getInputType(arg);
nondefaultMakeCommand = 'make_rtw USE_TMF=1';
doneMsg = message('CoderFoundation:utility:DoneStatus');

switch inputType
    
    case 'SimulinkModel'
        
        % ------------------------------------------------
        % Apply change to each model in the hierarchy
        % ------------------------------------------------        
        models = getModelsInHierarchy(arg, options);
        for i=1:numel(models)
            model = models{i};
            msg = message('CoderFoundation:utility:ProcessingModel', model);
            disp(msg.getString());            
            % Load/open the model
            initiallyOpen = loadModel(model, options);            
            % Check the model's STF
            config = getActiveConfigSet(model);
            
            if coder.make.internal.usingToolchainInfo(config)
                % Apply changes
                set_param(config, 'MakeCommand', nondefaultMakeCommand);
                % Save changes
                saveModel(model, options);
            end
            
            % Close the model
            closeModel(model, initiallyOpen, options);
        end
        disp(doneMsg.getString());
        
    case 'SimulinkConfigSetObject'
        
        config = arg;
        model = getModelFromConfigObject(config);
        if isempty(model) && coder.make.internal.usingToolchainInfo(config)
            % Apply changes (update handle)
            warning(message('CoderFoundation:utility:NoModelAssociatedWithConfigSet'));
            set_param(config, 'MakeCommand', nondefaultMakeCommand);
        elseif ~isempty(model)
            % Update the associated model(s)
            coder.make.revertToTMFBuild(model);
        end
        
    otherwise
        error(message('CoderFoundation:utility:UnsupportedArtifactType'));
        
end

% -------------------------------------------------------------------------
% Extract the model from the Simulink.ConfigSet object
% -------------------------------------------------------------------------
function model = getModelFromConfigObject(config)
model = '';
sys = config.getModel();
if ~isempty(sys)
    model = get_param(sys, 'Name');
    isRootConfig = strcmpi(model, 'DefaultBlockDiagram');
    if isRootConfig
        error(message('CoderFoundation:utility:NotAllowedForTMFConversion'));
    end
end

% -------------------------------------------------------------------------
% Get the models that comprise the model hierarchy.
% -------------------------------------------------------------------------
function models = getModelsInHierarchy(model, options)
if options.ApplyToEntireHierarchy
    models = flipud(find_mdlrefs(model));
else
    models = {model};
end

% -------------------------------------------------------------------------
% Load or open a model. Get the initial state.
% -------------------------------------------------------------------------
function initiallyOpen = loadModel(model, options)
initiallyOpen = RTW.areModelsOpen(model);
if options.SaveChanges
    load_system(model);
else
    open_system(model);
end

% -------------------------------------------------------------------------
% Save model changes.
% -------------------------------------------------------------------------
function saveModel(model, options)
if options.SaveChanges
    save_system(model)
end

% -------------------------------------------------------------------------
% Close the model.
% -------------------------------------------------------------------------
function closeModel(model, initiallyOpen, options)
if options.SaveChanges
    if ~initiallyOpen
        close_system(model, 1);
    end
end

% -------------------------------------------------------------------------
%
% -------------------------------------------------------------------------
function options = processInputArgs(args)
options.SaveChanges = false;
options.ApplyToEntireHierarchy = true;

for i=1:2:numel(args)
    fname = args{i};
    fvalue = args{i+1};
    if isfield(options, fname)
        options.(args{i}) = fvalue;
        if ~islogical(fvalue)
            error(message('CoderFoundation:utility:InvalidRevertTMFFuncArgumentDataType', fname));
        end
    else
        error(message('CoderFoundation:utility:InvalidRevertTMFFuncArgument', fname));
    end
end

% -------------------------------------------------------------------------
% Categorize the input that the caller passed
% -------------------------------------------------------------------------
function configType = getInputType(arg)
configType = '';
if isa(arg, 'Simulink.ConfigSet')
    configType = 'SimulinkConfigSetObject';    
elseif ischar(arg)    
    argType = coder.make.internal.determineArtifactFromName(arg);    
    if strcmpi(argType, 'model')
        configType = 'SimulinkModel';
    end
end

% LocalWords:  STF TMF Func REVERTTOMFBUILD
