function writeAnimation(varargin)
%writeAnimation Write animation to file.
%   writeAnimation(outfile)
%   writes the animation in the current figure to outfile.
%   The format is determined by the extension of outfile,
%   which must be .avi or .gif.
%
%   writeAnimation(vidObj)
%   uses the VideoWriter vidObj to create a video file.
%
%   writeAnimation(fig, outfile)
%   does the same for the figure fig.
%
%   writeAnimation(..., 'AnimationRange', [timeBegin, timeEnd})
%   uses the given time range.
%
%   writeAnimation(..., 'FrameRate', n)
%   writes n frames per unit time.
%
%   writeAnimation(..., 'Backwards', true)
%   writes the animation backwards.
%
%   writeAnimation(..., 'LoopCount', n)
%   sets the loop count of the gif file to n. This has no effect on avi
%   files.
%
%   Example:
%      syms t
%      fanimator(@plot, t, t^2, '*')
%      writeAnimation('myFile.avi')
%
%   See also animationToFrame, fanimator, playAnimation.

%   Copyright 2018 The MathWorks, Inc.

narginchk(1, inf);
p = inputParser;
addRequired(p, 'OutputFile', @(X) ischar(X) || isstring(X) || isa(X, 'VideoWriter'));
addParameter(p, 'AnimationRange', [NaN, NaN], @matlab.graphics.function.internal.checkRangeVector);
addParameter(p, 'FrameRate', NaN, @(X) isreal(X) && X>0);
addParameter(p, 'Backwards', false, @islogical);
% parameters for gif files
addParameter(p, 'LoopCount', 0, @isreal);

% check for optional figure in the first argument
if isa(varargin{1}, 'matlab.ui.Figure')
    fig = varargin{1};
    args = varargin(2:end);
else
    fig = get(groot, 'CurrentFigure');
    args = varargin;
end

parse(p, args{:});
outputFile = p.Results.OutputFile;

F = findAnimators(fig);
if isempty(F)
    % no animated object
    return;
end

[timeMin, timeMax, frameRate] = commonRange(F, ...
    p.Results.AnimationRange, p.Results.FrameRate);
timeStep = 1/frameRate;

% save the old position of the clock, and restore it later
fig = ancestor(F(1), 'figure');
matlab.ui.internal.prepareFigureFor(fig, mfilename('fullpath'));
animTimer = matlab.graphics.function.AnimationTimer(fig, ...
    'TimeBegin', timeMin, 'TimeStep', timeStep, ...
    'TimeEnd', timeMax, 'Backwards', p.Results.Backwards);
oldTime = animTimer.CurrentTime;

cleanupObj =  onCleanup(@() set(animTimer, 'CurrentTime', oldTime));

if isa(outputFile, 'VideoWriter')
  vidObj = outputFile;
  avi = true;
else
  [~,~,extension] = fileparts(outputFile);
  if isempty(extension) || strcmpi(extension, '.avi')
    % initialization - not needed for gif
    avi = true;
    vidObj = VideoWriter(outputFile);
    vidObj.FrameRate = frameRate;
    open(vidObj);
	cleanupObj2 = onCleanup(@() close(vidObj));
  elseif strcmpi(extension, '.gif')
    avi = false;
  else
    error(message('symbolic:writeAnimation:UnknownVideoFormat'));
  end
end

if p.Results.Backwards
    tvec = timeMax: -timeStep: timeMin;
else
    tvec = timeMin: timeStep : timeMax;
end

for t = tvec
    setTime(animTimer, t);
    currFrame = getframe(fig);
    if avi
        writeVideo(vidObj, currFrame);
    else %gif
       im = frame2im(currFrame);
       [A, map] = rgb2ind(im,256);
       if t == tvec(1)
           imwrite(A, map, outputFile, 'gif', ...
               'LoopCount', p.Results.LoopCount, ...
               'DelayTime', timeStep);
       else
           imwrite(A, map, outputFile, 'gif', ...
               'WriteMode', 'append',...
               'DelayTime', timeStep);
       end
    end
end

end