function [lVersions, lLocations] = sharedCodeMATLABVersions(varargin)
% SHAREDCODEMATLABVERSIONS manages MATLAB releases available for shared code generation
%
% [VERSIONS, FOLDERS] = SHAREDCODEMATLABVERSIONS returns the available MATLAB
%   VERSIONS and corresponding installation FOLDERS.
%
% SHAREDCODEMATLABVERSIONS('Folder', 'c:\MATLAB\R2013b') specifies that a
%   version of the MATLAB software is installed in c:\MATLAB\R2013b. The
%   software checks that this folder corresponds to MATLABROOT for a valid
%   installation of MATLAB, retrieves the MATLAB version number and stores this
%   information as a preference.
%
% SHAREDCODEMATLABVERSIONS('Remove', 'R2013b') removes the corresponding stored
%   folder and MATLAB version data.
%
%   See also SHAREDCODEGENERATOR, MATLABROOT

%   Copyright 2016-2017 The MathWorks, Inc.

% Allow string inputs
[varargin{:}] = convertStringsToChars(varargin{:});

prefGroup = 'sharedCodeGenerator';
prefName = 'versions';

p = inputParser;
addParameter(p, 'Folder', '', @ischar);
addParameter(p, 'Version', '', @ischar);
addParameter(p, 'Remove', '', @ischar);
parse(p, varargin{:});

lFolder = p.Results.Folder;
lRemove = p.Results.Remove;
lVersion = p.Results.Version;

% Now load existing preferences
if ispref(prefGroup, prefName)
    lVersionStruct = getpref(prefGroup, prefName);
else
    lVersionStruct = struct('Version', {}, 'Location', {});
end

if ~isempty(lFolder)
    lVersionStruct = i_addFolder(lFolder, lVersion, lVersionStruct);
end

if ~isempty(lRemove)
    lVersionStruct = i_removeItem(lRemove, lVersionStruct);
end

setpref(prefGroup, prefName, lVersionStruct);

N = length(lVersionStruct);
[lVersions{1:N}] = lVersionStruct(:).Version;
[lLocations{1:N}] = lVersionStruct(:).Location;

% Sort by most recent version first
[~, sortIdx] = sort(lVersions);
sortIdx = sortIdx(end:-1:1);
lVersions = lVersions(sortIdx);
lLocations = lLocations(sortIdx);


function lVersionsStruct = i_removeItem(lRemove, lVersionsStruct)

N = length(lVersionsStruct);
[versions{1:N}] = lVersionsStruct(:).Version;
[locations{1:N}] = lVersionsStruct(:).Location;

% Remove any item with matching version string or location
removeIdx = strcmpi(lRemove, versions) | strcmpi(lRemove, locations);
lVersionsStruct = lVersionsStruct(~removeIdx);



function lVersionStruct = i_addFolder(lFolder,  lVersion, lVersionStruct)

if isempty(lVersion)
    % Identify the version number by invoking MATLAB
    lVersion = i_getVersionInvokeMATLAB(lFolder);
end

N = length(lVersionStruct);
[existingVersions{1:N}] = lVersionStruct(:).Version;
[existingLocations{1:N}] = lVersionStruct(:).Location;
discardIdx = strcmp(lFolder, existingLocations) | ...
    strcmp(lVersion, existingVersions);

lVersionStruct = lVersionStruct(~discardIdx);

lVersionStruct(end+1).Version = lVersion;
lVersionStruct(end).Location = lFolder;



function lVersionInvokeMATLAB = i_getVersionInvokeMATLAB(lMATLABFolder)


% Temporary folder for diary file to capture output from running version command
tmpFolder = tempname;
mkdir(tmpFolder);
removeFolder = onCleanup(@()rmdir(tmpFolder, 's'));

% Since runInMATLAB returns the version string, the actual command to run is empty
lEmptyCommand = '';

lVersionInvokeMATLAB = coder.sharedutil.runInMATLAB(lEmptyCommand, lMATLABFolder);
