classdef (ConstructOnLoad) Animator < ...
    matlab.graphics.primitive.world.Group & ...
    matlab.graphics.mixin.SceneNodeGroup & ...
    matlab.graphics.mixin.AxesParentable & ...
    matlab.graphics.internal.Legacy 
%Animator Create animator object
%   Animator(animatableProperties, data, frameRate, trange, XLim, YLim, ZLim) 
%   creates an animator object as a child of the current axes.

%   Copyright 2018-2020 The MathWorks, Inc.

properties (SetAccess = 'private')
  AnimationRange;  
  FrameRate = 10;
end

properties (Hidden, SetAccess = 'private')
  animatableProperties;
  % Cell array of data.
  Data;
  % currentFrame; % number of current frame
end  

methods
    function self = Animator(animatableProperties, data, frameRate, trange)
        %initialize immutable properties
        self.Type = 'animator';
        
        if nargin == 0
          return;
        end  
         
        self.Data = data;
        self.FrameRate = frameRate;
        self.animatableProperties = animatableProperties;
        self.AnimationRange = trange;
    end
  
    function B = isValidAnimator(self)
        % Returns a logical array. 
        % B(idx) is true if the animated object of self(idx) is valid. 
        
        % We cannot overload isvalid because it is sealed.
        B = arrayfun(@(X) isvalid(X) && numel(X.Children) == 1 && isvalid(X.Children), self); 
    end
    
    function setTime(self, t)
        % replaces the properties of AnimatedObject by those valid at time t
        self = self(isValidAnimator(self));
        for anim = self(:).'
            % compute the number of the frame
            frameNumber = min(floor(anim.FrameRate * (t - startTime(anim))) + 1, nframes(anim));
            frameNumber = max(1, frameNumber);
            names = anim.animatableProperties;
            v = anim.Data{frameNumber};
            set(animatedObject(anim), names, v);
        end
    end
    
    function h = animatedObject(anim)
        h = anim.Children;
    end
    
end

methods (Hidden)   
    
    function n = nframes(self)
        n = arrayfun(@(x) numel(x.Data), self);
    end    
  
    function t = startTime(self)
        t = arrayfun(@(X) X.AnimationRange(1), self);
    end    
        
    function t = endTime(self)
        t = arrayfun(@(X) X.AnimationRange(2), self);
    end    
    
end % methods

methods (Access = protected, Hidden)
        function groups = getPropertyGroups(~)
            % Customize short display.
            props = {
                'AnimationRange',...
                'FrameRate'
                };
            groups = matlab.mixin.util.PropertyGroup(props);
        end
end % protected and hidden methods

end % classdef

