function varargout = createDockerImage(varargin)
%COMPILER.RUNTIME.CREATEDOCKERIMAGE  Create a MATLAB Runtime image
%
%    COMPILER.RUNTIME.CREATEDOCKERIMAGE(RESULTS) creates a MATLAB Runtime
%        Docker image using a vector of compiler.build.Results objects
%        RESULTS. The RESULTS objects can be created by any compiler.build
%        function.
%
%    COMPILER.RUNTIME.CREATEDOCKERIMAGE(FILEPATH) creates a MATLAB Runtime
%        Docker image using a list of requiredMCRProducts.txt files
%        generated by the MATLAB Compiler product.
%
%    COMPILER.RUNTIME.CREATEDOCKERIMAGE(...,NAME,VALUE) creates a MATLAB
%        Runtime Docker image with additional customizations specified by
%        name-value pairs.
%
%    NAME = COMPILER.RUNTIME.CREATEDOCKERIMAGE(...) creates a MATLAB
%        Runtime Docker image and returns the name of the image NAME.
%
%    INPUT ARGUMENTS:
%
%    - RESULTS (A vector compiler.build.Results object)
%        One or more build results, created by a compiler.build function.
%
%    - FILEPATH (A row char vector, a cellstr vector, or a string vector)
%        One or more paths to the requiredMCRProducts.txt file generated by
%        the MATLAB Compiler product.
%
%    OUTPUT ARGUMENTS:
%
%    - NAME (A row char vector)
%        The name of the created MATLAB Runtime Docker image.
%
%    NAME-VALUE PAIR ARGUMENTS:
%
%    - BaseImage (A row char vector or a string scalar)
%        Name of the Docker image that is used in the FROM line to
%        create the MATLAB Runtime image.  By default, a base image with
%        all required dependencies is created.
%
%    - DockerContext (A row char vector or a string scalar)
%        Path to folder where the docker image is built.
%
%    - ExecuteDockerBuild ('on'/'off', true/false, or 1/0)
%        Determines if the function will build the Docker image. This is
%        set to 'on' by default. If set to 'off' the function will generate
%        the Dockerfile within the DockerContext folder without calling
%        'docker build'.
%
%    - ImageName (A row char vector or a string scalar)
%        Name of the MATLAB Runtime Docker image.
%
%    - VerbosityLevel ('none', 'concise' or 'verbose')
%
%        'none' - Option for no screen output.
%
%        'concise' - Option for enabling update information but no Docker
%        screen output.
%
%        'verbose' (default) - Option for all screen output, including
%        Docker output that occurs from "docker pull" and "docker build".
%
%    EXAMPLES:
%
%    % Create two standalone applications.
%    results1 = compiler.build.standaloneApplication('mymagic.m');
%    results2 = compiler.build.standaloneApplication('myapp.mlapp');
%
%    % Create a MATLAB Runtime Docker image that can be used for both
%    % deployed standalone applications.
%    name = COMPILER.RUNTIME.CREATEDOCKERIMAGE([results1,results2], ...
%        'ImageName','example-combo-image');
%
%    % Create both standalone application Docker images using the same
%    % Runtime image
%    compiler.package.docker(results1,'RuntimeImage',name)
%    compiler.package.docker(results2,'RuntimeImage',name)
%
%    See also compiler.package.docker, compiler.package.microserviceDockerImage

%   Copyright 2023 The MathWorks, Inc.

narginchk(1,Inf)

opts = compiler.internal.runtime.DockerImageOptions(varargin{:});

if opts.ExecuteDockerBuild
    proxy = compiler.internal.package.docker.Proxy;
    proxy.assertDockerIsAvailable('compiler.runtime.createDockerImage')
end

rtcontext = compiler.internal.validate.makePathAbsolute(opts.DockerContext);
defaultdepsimage = compiler.internal.package.docker.GenericImage.empty;
instname = compiler.internal.package.docker.Constants.InstallerImageRepository;
logger = compiler.internal.package.docker.log.Logger( ...
    compiler.internal.package.docker.VerbosityLevel(opts.VerbosityLevel));

% Manage deps image
if strlength(opts.BaseImage) == 0
    depscontext = fullfile(rtcontext, ...
        compiler.internal.package.docker.Constants.RuntimeDepsContextSubDir);
    defaultdepsimage = makeDefaultDepsImage(depscontext,opts.ExecuteDockerBuild,logger);
    depsimage = defaultdepsimage;
else
    % Use customer specified deps image
    depsimage = compiler.internal.package.docker.GenericImage(opts.BaseImage,logger,opts.ExecuteDockerBuild);
    % We trust makeAvailable to handle ExecuteDockerBuild, Dockerfiles, etc. correctly
    depsimage.makeAvailable
end

% only need the installer image if execute docker build is on
installerZip = '';
if strcmp(computer('arch'),'glnxa64')
    installerZip = compiler.internal.runtime.utils.getExistingMCRInstallerWithValidation;
end

instcontext = fullfile( ...
    compiler.internal.package.docker.Constants.WorkingDirectory,'installer');
instimage = compiler.internal.package.docker.MatlabRuntimeInstallerImage( ...
    instname,instcontext,opts.ExecuteDockerBuild,logger,defaultdepsimage, ...
    'InstallerFullPath',installerZip);

% Create runtime image
rtimage = compiler.internal.package.docker.MatlabRuntimeImage( ...
    opts.ImageName,logger,rtcontext,opts.ExecuteDockerBuild, ...
    opts.NumericRuntimeDefinition,instimage,depsimage, 'ForceBuild', true);
rtimage.makeAvailable

if nargout
    varargout{1} = opts.ImageName;
end

function depsimage = makeDefaultDepsImage(depscontext,executebuild,logger)

% OS image
osname = compiler.internal.package.docker.Constants.BaseOSImage;
osimage = compiler.internal.package.docker.GenericImage(osname,logger,executebuild);


% Ensure deps image is available
depsname = compiler.internal.package.docker.Constants.BaseImageRepository;
depsimage = compiler.internal.package.docker.MatlabRuntimeDepsImage( ...
    depsname,depscontext,executebuild,logger,osimage);
% We trust makeAvailable to handle ExecuteDockerBuild, Dockerfiles, etc. correctly
depsimage.makeAvailable
