function ert_to_grt_switch(model, stf_grt, stf_ert)
%ERT_GRT_SWITCH Switches the model between the ERT- and GRT-based STF

%   Copyright 2007-2012 The MathWorks, Inc.

%   The function will only switch from STF_ERT to STF_GRT where these
%   are ERT and GRT versions, respectively of the System Target File for a
%   Target environment.
%
%   model can be a model name or a Simulink configuration set.
%
%   Example:
%
%   ert_to_grt_switch(gcs, linkfoundation.util.getSTFName('grt'), linkfoundation.util.getSTFName('ert'))


narginchk(3, 3);

% If user has Embedded Coder return without switching to STF_GRT
ert_licensed = (builtin('_license_checkout','RTW_Embedded_Coder', 'quiet') ...
    == 0); %_license_checkout returns 0 on success and 1 on failure
ert_installed = exist('ert_make_rtw_hook.m','file');
ert_available = ert_licensed && ert_installed;

if (ert_available)
    return;
else
    newSysTargetFile = stf_grt;
end

% Check that STF is ERT --> so that we can switch to GRT
cs = i_getActiveConfigSet(model);
systemTargetFile = get_param(cs, 'SystemTargetFile');
if strcmp(systemTargetFile, stf_grt)
    % There is nothing to do. Return.
    return;
end

% Check that the current STF is the ERT the allowed options
if ~strcmp(systemTargetFile, stf_ert)
    DAStudio.error('TARGETFOUNDATION:demos:InvalidSTF', systemTargetFile, stf_ert);
end

% Save the current config set
origCS = cs.copy;

% Switch target
settings.TemplateMakefile = strrep(newSysTargetFile, '.tlc', '.tmf');
cs.switchTarget(newSysTargetFile, settings);

% Preserve the Adaptor name
set_param(cs, 'AdaptorName', get_param(origCS, 'AdaptorName'))

% Restore code generation settings
%
% Settings not to re-apply
settingsToKeep = {...
    'TemplateMakefile',...
    'SystemTargetFile',...
    'IsERTTarget',...
    'ERTFirstTimeCompliant'};
% settingsToReset is an Nx2 cell array:
% first value is the property name while the second is the reset
% value. The idea is to reset the value when switching the target from
% an ERT based STF to GRT
settingsToReset = {'CodeReplacementLibrary', 'C89/C90 (ANSI)'; ...
    'IgnoreCustomStorageClasses', 'on'; ...
    'CombineOutputUpdateFcns', 'off'; ...
    'ERTCustomFileBanners', 'off'; ...
    'SupportContinuousTime', 'on'; ...
    'SupportNonInlinedSFcns', 'on'; ...
    'CustomSymbolStrFcn', '$R$N$M$F'};
i_restoreSettings(origCS, cs, linkfoundation.util.getCodeGenComponentName, ...
    settingsToKeep, settingsToReset);
% Now, also restore Target Hardware Resources component data
propName = 'TargetHardwareResources';
settingsToReset = {propName, get_param(origCS, propName);};
i_restoreSettings(origCS, cs, 'Target Hardware Resources', ...
    settingsToKeep, settingsToReset);
i_restoreSettings(origCS, cs, 'Solver', '', '');
end


%--------------------------------------------------------------------------
function i_restoreSettings(origCS, cs, componentName, ...
    settingsToKeep, settingsToReset)
% Re-apply settings from old target
componentOrig = origCS.getComponent(componentName);
componentNew  = cs.getComponent(componentName);
propsOrig     = componentOrig.getPossibleProperties;
propsNew      = componentNew.getPossibleProperties;
props         = intersect(propsNew, propsOrig);
props         = setdiff(props, settingsToKeep);
for i=1:length(props)
    prop = props{i};
    try
        val = get_param(componentOrig, prop);
        enabledState = componentOrig.getPropEnabled(prop);
        componentNew.setPropEnabled(prop, 'on');
        if ~isempty(settingsToReset)
            tmp = ismember(settingsToReset(:, 1), prop);
            if any(tmp)
                val = settingsToReset{tmp, 2};
            end
        end
        set_param(componentNew, prop, val);
        componentNew.setPropEnabled(prop, enabledState);
    catch me %#ok<NASGU>
        % property may be read-only
    end
end
end


%--------------------------------------------------------------------------
function cs = i_getActiveConfigSet(model)
% see if "model" is a configuration set or a model
switch class(model)
    case 'char'
        % ensure a root model name
        model = strtok(model, '/');
        % get the config set
        cs = getActiveConfigSet(model);
    case 'Simulink.ConfigSet'
        % set the config set
        cs = model;
    otherwise
        DAStudio.error('TARGETFOUNDATION:demos:InvalidInputModelOrCS');
end
end


% LocalWords:  STF linkfoundation tmf Nx GETACTIVECONFIGSET
