function varargout = sharedCodeGenerator(varargin)
% SHAREDCODEGENERATOR for pre-generating code shared across multiple models
% SHAREDCODEGENERATOR creates a new SHAREDCODEGENERATOR or brings the existing
% app to the foreground.
%
% H = SHAREDCODEGENERATOR returns a handle to a new app or the handle to the
% existing app.

% Copyright 2015-2016 The MathWorks, Inc.

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @sharedCodeGenerator_OpeningFcn, ...
'gui_OutputFcn', @sharedCodeGenerator_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

function cleanup = i_HourGlassPointer(hFig)

origPointer = get(hFig, 'pointer');
set(hFig, 'pointer', 'watch');
drawnow
cleanup = onCleanup(@()set(hFig, 'pointer', origPointer));

function i_configSetFilterEnable(figH, val)

configH = findobj(figH, 'Tag', 'ConfigSetModel');
hFilteredOutRules = findobj(figH, 'Tag', 'FilteredOutRules');
hOpenConfigSet = findobj(figH, 'Tag', 'OpenConfigSet');
if val
enabled = 'on';
else
enabled = 'off';
end
set(configH, 'Enable', enabled);
set(hFilteredOutRules, 'Enable', enabled);
set(hOpenConfigSet, 'Enable', enabled);

function lRelease = i_populateReleasePulldown(figH)

releaseH = findobj(figH, 'Tag', 'ReleaseSelected');

oldChoices = get(releaseH, 'String');
oldValue = get(releaseH, 'Value');
oldSelection = oldChoices{oldValue};
oldChoices = oldChoices(1:end-1); % strip off the Configure item

choices = coder.sharedutil.availableReleases;

% Update the list if necessary
if ~isequal(choices, oldChoices)

% Add a list entry allowing users to configure available releases
configureEntry = {DAStudio.message('Coder:pregen:pgAppReleasesConfigure')};
choices = [choices(:); configureEntry];
set(releaseH, 'String', choices);

% Restore the old selection if possible
idxNew = strcmp(choices, oldSelection);
if sum(idxNew)==1
set(releaseH, 'Value', find(idxNew));
else
set(releaseH, 'Value', 1); % default
end
end

items = get(releaseH, 'String');
value = get(releaseH, 'Value');
lRelease = items{value};

function i_populateRulePulldown(figH, lIncludeAdvisorFlaggedRules, lRelease)

allRules = coder.sharedutil.findRules('IncludeAdvisorFlaggedRules', lIncludeAdvisorFlaggedRules,...
'Release', lRelease);

ruleH = findobj(figH, 'Tag', 'RuleSelected');

oldChoices = get(ruleH, 'String');
oldValue = get(ruleH, 'Value');
oldSelection = oldChoices{oldValue};

defaultRule = {DAStudio.message('Coder:pregen:pgAppRulesAll')};
choices = [defaultRule; allRules(:)];
set(ruleH, 'String', choices);

% Restore the old selection if possible
idxNew = strcmp(choices, oldSelection);
if sum(idxNew)==1
set(ruleH, 'Value', find(idxNew));
else
set(ruleH, 'Value', 1); % default
end

function i_initializeWidgetsFromMessageCatalog(figH)

widget = findobj(figH, 'Tag', 'SourceFilesLabel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppSourceFileTooltip');
set(widget, 'TooltipString', tooltip);

widget = findobj(figH, 'Tag', 'ConfigurationSetSpecLabel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppConfigSetSpecTooltip');
set(widget, 'TooltipString', tooltip);

widget = findobj(figH, 'Tag', 'OpenConfigSet');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppOpenConfigSetLabel');
text = DAStudio.message('Coder:pregen:pgAppOpenConfigSetLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'CreateModel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppCreateModelTooltip');
text = DAStudio.message('Coder:pregen:pgAppCreateModelLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'RuleLabel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppRuleTooltip');
text = DAStudio.message('Coder:pregen:pgAppRuleLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'ReleaseLabel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppReleaseTooltip');
text = DAStudio.message('Coder:pregen:pgAppReleaseLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'SourceFilesLabel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppSourceFilesTooltip');
text = DAStudio.message('Coder:pregen:pgAppSourceFilesLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'ModelAdvisorFlaggedRules');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppAdvisorFlaggedTooltip');
text = DAStudio.message('Coder:pregen:pgAppAdvisorFlaggedLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'ConfigSetFilterPane');
assert(~isempty(widget), 'widget not found');
text = DAStudio.message('Coder:pregen:pgAppConfigSetPane');
set(widget, 'Title', text);

widget = findobj(figH, 'Tag', 'SelectRules');
assert(~isempty(widget), 'widget not found');
text = DAStudio.message('Coder:pregen:pgAppSelectRules');
set(widget, 'Title', text);

widget = findobj(figH, 'Tag', 'UseConfigSetFilter');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppConfigSetFilterTooltip');
text = DAStudio.message('Coder:pregen:pgAppConfigSetFilterLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'ConfigurationSetSpecLabel');
assert(~isempty(widget), 'widget not found');
tooltip = DAStudio.message('Coder:pregen:pgAppConfigSetSpecTooltip');
text = DAStudio.message('Coder:pregen:pgAppConfigSetSpecLabel');
set(widget, 'TooltipString', tooltip);
set(widget, 'String', text);

widget = findobj(figH, 'Tag', 'FilteredOutRules');
assert(~isempty(widget), 'widget not found');
text = DAStudio.message('Coder:pregen:pgAppFilteredOutRules');
tooltip = DAStudio.message('Coder:pregen:pgAppFilteredRulesTip');
set(widget, 'TooltipString', tooltip);
set(widget, 'ColumnName', text);

widget = findobj(figH, 'Tag', 'ActiveRules');
assert(~isempty(widget), 'widget not found');
text = DAStudio.message('Coder:pregen:pgAppActiveRules');
tooltip = DAStudio.message('Coder:pregen:pgAppActiveRulesTip');
set(widget, 'TooltipString', tooltip);
set(widget, 'ColumnName', text);

widget = findobj(figH, 'Tag', 'SourceFileNames');
assert(~isempty(widget), 'widget not found');
text = DAStudio.message('Coder:pregen:pgAppSourceFileNames');
tooltip = DAStudio.message('Coder:pregen:pgAppSourceFileNamesTip');
set(widget, 'TooltipString', tooltip);
set(widget, 'ColumnName', text);

% --- Executes just before untitled is made visible.
function sharedCodeGenerator_OpeningFcn(hObject, ~, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to untitled (see VARARGIN)

% Choose default command line output for untitled
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes untitled wait for user response (see UIRESUME)
% uiwait(handles.figure1);

lRelease = i_populateReleasePulldown(hObject);

lIncludeAdvisorFlaggedRules = false;
i_populateRulePulldown(hObject, lIncludeAdvisorFlaggedRules, lRelease);

i_initializeWidgetsFromMessageCatalog(hObject);

i_configSetFilterEnable(hObject, true);
% Create a default config set
hConfigSetModel = findobj(hObject, 'Tag', 'ConfigSetModel');
hUseConfigSetFilter = findobj(hObject, 'Tag', 'UseConfigSetFilter');
hUseConfigSetFilter.Value = true;
baseWsVariableName = i_createNewConfigSet;
hConfigSetModel.String = baseWsVariableName;

set(handles.figure1, 'Name', ...
DAStudio.message('Coder:pregen:pgAppTitle'));

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

updateGui(hObject);

% --- Outputs from this function are returned to the command line.
function varargout = sharedCodeGenerator_OutputFcn(~, ~, handles)
% varargout cell array for returning output args (see VARARGOUT);
% handles structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

function [lSourceFileExpr, release, lConfigSetSpec, rule, ...
lIncludeAdvisorFlaggedRules] = getSettings(hObject)

figH = ancestor(hObject, {'figure'});

lSourceFileH = findobj(figH, 'Tag', 'SourceFileSpec');
lSourceFileExpr = get(lSourceFileH, 'String');

releaseH = findobj(figH, 'Tag', 'ReleaseSelected');
allReleases = get(releaseH, 'String');
release = allReleases{get(releaseH, 'Value')};

hUseConfigSetFilter = findobj(figH, 'Tag', 'UseConfigSetFilter');
if hUseConfigSetFilter.Value
configH = findobj(figH, 'Tag', 'ConfigSetModel');
lConfigSetSpec = get(configH, 'String');
else
lConfigSetSpec = '';
end

ruleH = findobj(figH, 'Tag', 'RuleSelected');
allRules = get(ruleH, 'String');
rule = allRules(get(ruleH, 'Value'));

if length(rule)==1 && isempty(rule{1})
% Apply mapping for no rule specified
rule = {};
end

hAdvisorFlaggedRules = findobj(figH, 'Tag', 'ModelAdvisorFlaggedRules');
lIncludeAdvisorFlaggedRules = logical(hAdvisorFlaggedRules.Value);

function [lConfigSet, isValid] = getConfigSetForModel(lConfigSetSpec)

% The config set spec may refer to either a model or an object in the base
% workspace
[lConfigSet, isValid, errMsg] = ...
coder.sharedutil.validateConfigSetSpec(lConfigSetSpec);

if ~isValid
errMsgTitle = DAStudio.message('Coder:pregen:pgAppErrorTitle');
errordlg(errMsg, errMsgTitle, 'modal');
end

function [activeRules, lConfigSetSpec, lConfigSet] = updateGui(hObject)

figH = ancestor(hObject, {'figure'});

[lSourceFileExpr, release, lConfigSetSpec, rule, lIncludeAdvisorFlaggedRules] ...
= getSettings(hObject);

[lConfigSet, isValid] = getConfigSetForModel(lConfigSetSpec);
if ~isValid
activeRules = {};
lSourceFiles = {};
lFilteredOutRules = {};
else
if strcmp(rule, DAStudio.message('Coder:pregen:pgAppRulesAll'))
% Replace graphical name "All rules" with empty cell array
rule = {};
end
[activeRules, ~, lSourceFiles, lFilteredOutRules] = coder.sharedutil.findRules...
('SourceFile', lSourceFileExpr, 'Rules', rule, 'Release', release, ...
'ActiveForConfigSet', lConfigSet, 'Sparse', false, ...
'IncludeAdvisorFlaggedRules', lIncludeAdvisorFlaggedRules);
end

sourceFilesH = findobj(figH, 'Tag', 'SourceFileNames');
set(sourceFilesH, 'Data', lSourceFiles);

activeRulesH = findobj(figH, 'Tag', 'ActiveRules');
set(activeRulesH, 'Data', activeRules(:));

filteredOutRulesH = findobj(figH, 'Tag', 'FilteredOutRules');
set(filteredOutRulesH, 'Data', lFilteredOutRules(:));

% Ensure releases menu is up to date
i_populateReleasePulldown(figH);

function SourceFileSpec_Callback(hObject, ~, handles) %#ok<*DEFNU>
% hObject handle to SourceFileSpec (see GCBO)
% handles structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of SourceFileSpec as text
% str2double(get(hObject,'String')) returns contents of SourceFileSpec as a double

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

updateGui(hObject);

% --- Executes during object creation, after setting all properties.
function SourceFileSpec_CreateFcn(hObject, ~, ~)
% hObject handle to SourceFileSpec (see GCBO)
% handles empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end

function ConfigSetModel_Callback(hObject, ~, handles)
% hObject handle to ConfigSetModel (see GCBO)
% handles structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of ConfigSetModel as text
% str2double(get(hObject,'String')) returns contents of ConfigSetModel as a double

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

updateGui(hObject);

% --- Executes during object creation, after setting all properties.
function ConfigSetModel_CreateFcn(hObject, ~, ~)
% hObject handle to ConfigSetModel (see GCBO)
% handles empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in RuleSelected.
function RuleSelected_Callback(hObject, ~, handles)
% hObject handle to RuleSelected (see GCBO)
% handles structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns RuleSelected contents as cell array
% contents{get(hObject,'Value')} returns selected item from RuleSelected

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

updateGui(hObject);

% --- Executes during object creation, after setting all properties.
function RuleSelected_CreateFcn(hObject, ~, ~)
% hObject handle to RuleSelected (see GCBO)
% handles empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in CreateModel.
function CreateModel_Callback(hObject, ~, handles)
% hObject handle to CreateModel (see GCBO)
% handles structure with handles and user data (see GUIDATA)

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

[activeRules, lConfigSetSpec, lConfigSet] = updateGui(hObject);

if isempty(activeRules)
errMsg = DAStudio.message('Coder:pregen:pgAppNoActiveRules');
errMsgTitle = DAStudio.message('Coder:pregen:pgAppErrorTitle');
errordlg(errMsg, errMsgTitle, 'modal');
return;
end

if length(activeRules)>1 && isempty(lConfigSetSpec)
errMsg = DAStudio.message('Coder:pregen:pgAppConfigSetNotSpecified');
errMsgTitle = DAStudio.message('Coder:pregen:pgAppErrorTitle');
errordlg(errMsg, errMsgTitle, 'modal');
return;
end

[~, release] = getSettings(hObject);
lSparse = false;
model = coder.sharedutil.createSharedCodeModel(activeRules, ...
'Release', release, 'ConfigSetInitial', lConfigSet, 'Sparse', lSparse);

coder.sharedutil.buildInRelease(model, release);

% --- Executes when selected cell(s) is changed in FilteredOutRules.
function FilteredOutRules_CellSelectionCallback(hObject, eventdata, handles)
% hObject handle to FilteredOutRules (see GCBO)
% Indices: row and column indices of the cell(s) currently selected
% handles structure with handles and user data (see GUIDATA)

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

if ~isempty(eventdata.Indices)
rowIndex = eventdata.Indices(1,1);
rule = hObject.Data{rowIndex};
[~, release, lConfigSetSpec] = getSettings(hObject);
[~, isValid] = getConfigSetForModel(lConfigSetSpec);
if ~isValid
return;
end
coder.sharedutil.printConstraintInfo(rule, lConfigSetSpec, release);
commandwindow
end

% --------------------------------------------------------------------
function FilteredOutRules_ButtonDownFcn(hObject, ~, handles) %#ok
% hObject handle to FilteredOutRules (see GCBO)
% handles structure with handles and user data (see GUIDATA)

% --- Executes when entered data in editable cell(s) in FilteredOutRules.
function FilteredOutRules_CellEditCallback(hObject, ~, handles) %#ok
% hObject handle to FilteredOutRules (see GCBO)
% Indices: row and column indices of the cell(s) edited
% PreviousData: previous data for the cell(s) edited
% EditData: string(s) entered by the user
% NewData: EditData or its converted form set on the Data property. Empty if Data was not changed
% Error: error string when failed to convert EditData to appropriate value for Data
% handles structure with handles and user data (see GUIDATA)

function baseWsVariableName = i_createNewConfigSet

% Avoid overwriting an existing config set by finding an available base
% workspace variable name
variableNameRoot = 'sharedcodeCS';
baseWsVariableName = variableNameRoot;
idx = 1;
while evalin('base', ['exist(''' baseWsVariableName ''', ''var'')'])
baseWsVariableName = sprintf('%s%d', variableNameRoot, idx);
idx = idx+1;
end

% Create a default configuration set in base workspace
csDefault = coder.sharedutil.getDefaultConfigSet;

% Make configuration set name consistent with base workspace
% variable name
csDefault.Name = baseWsVariableName;

assignin('base', baseWsVariableName, csDefault);

% --- Executes on button press in UseConfigSetFilter.
function UseConfigSetFilter_Callback(hObject, ~, handles)
% hObject handle to UseConfigSetFilter (see GCBO)
% handles structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of UseConfigSetFilter

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

figH = ancestor(hObject, {'figure'});

% Enable/disable the corresponding edit box and table
i_configSetFilterEnable(figH, hObject.Value)

hConfigSetModel = findobj(figH, 'Tag', 'ConfigSetModel');
if hObject.Value && isempty(hConfigSetModel.String)
baseWsVariableName = i_createNewConfigSet;
hConfigSetModel.String = baseWsVariableName;
end

updateGui(hObject);

% --- Executes on button press in ModelAdvisorFlaggedRules.
function ModelAdvisorFlaggedRules_Callback(hObject, ~, handles)
% hObject handle to ModelAdvisorFlaggedRules (see GCBO)
% handles structure with handles and user data (see GUIDATA)

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok

% Update the rules pulldown
[~, lRelease, ~, ~, lIncludeAdvisorFlaggedRules] = getSettings(hObject);
figH = ancestor(hObject, {'figure'});
i_populateRulePulldown(figH, lIncludeAdvisorFlaggedRules, lRelease);

updateGui(hObject);
% Hint: get(hObject,'Value') returns toggle state of ModelAdvisorFlaggedRules

% --- Executes on button press in OpenConfigSet
function OpenConfigSet_Callback(hObject, ~, ~)
% hObject handle to OpenConfigSet (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)

[~, ~, lConfigSetSpec] = getSettings(hObject);
[lConfigSet, isValid] = getConfigSetForModel(lConfigSetSpec);

if isValid
lConfigSet.openDialog;
end

function i_handle_configure_releases(hObject)

figH = ancestor(hObject, {'figure'});

releaseH = findobj(figH, 'Tag', 'ReleaseSelected');
allReleases = get(releaseH, 'String');
release = allReleases{get(releaseH, 'Value')};

if strcmp(release, DAStudio.message('Coder:pregen:pgAppReleasesConfigure'))

msgTitle = DAStudio.message('Coder:pregen:pgAppConfigureReleasesTitle');
[msg, docCmd] = coder.sharedutil.getConfigureReleasesMsg;
msgbox(msg, msgTitle, 'modal');

% Additionally print a hyperlink to the command window
link = sprintf('<a href="matlab:%s">%s</a>', docCmd, docCmd);
disp(link)

% Reset the pulldown to default
set(releaseH, 'Value', 1);
end

% --- Executes on selection change in ReleaseSelected.
function ReleaseSelected_Callback(hObject, ~, handles)
% hObject handle to ReleaseSelected (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns ReleaseSelected contents as cell array
% contents{get(hObject,'Value')} returns selected item from ReleaseSelected

% Special handling if user selects configure option
i_handle_configure_releases(hObject);

cursorCleanup = i_HourGlassPointer(handles.figure1); %#ok<NASGU>

% List of available rules must be updated
[~, lRelease, ~, ~, lIncludeAdvisorFlaggedRules] = getSettings(hObject);
figH = ancestor(hObject, {'figure'});
i_populateRulePulldown(figH, lIncludeAdvisorFlaggedRules, lRelease);

updateGui(hObject);

% --- Executes during object creation, after setting all properties.
function ReleaseSelected_CreateFcn(hObject, ~, ~)
% hObject handle to ReleaseSelected (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end