Pods/lottie-ios/lottie-ios/Classes/RenderSystem/ManipulatorNodes/LOTTrimPathNode.m
//
//  LOTTrimPathNode.m
//  Lottie
//
//  Created by brandon_withrow on 7/21/17.
//  Copyright © 2017 Airbnb. All rights reserved.
//

#import "LOTTrimPathNode.h"
#import "LOTNumberInterpolator.h"
#import "LOTPathAnimator.h"
#import "LOTCircleAnimator.h"
#import "LOTRoundedRectAnimator.h"
#import "LOTRenderGroup.h"

@implementation LOTTrimPathNode {
  LOTNumberInterpolator *_startInterpolator;
  LOTNumberInterpolator *_endInterpolator;
  LOTNumberInterpolator *_offsetInterpolator;
  
  CGFloat _startT;
  CGFloat _endT;
  CGFloat _offsetT;
}

- (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode *_Nullable)inputNode
                                   trimPath:(LOTShapeTrimPath *_Nonnull)trimPath {
  self = [super initWithInputNode:inputNode keyName:trimPath.keyname];
  if (self) {
    inputNode.pathShouldCacheLengths = YES;
    _startInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:trimPath.start.keyframes];
    _endInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:trimPath.end.keyframes];
    _offsetInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:trimPath.offset.keyframes];
  }
  return self;
}

- (NSDictionary *)valueInterpolators {
  return @{@"Start" : _startInterpolator,
           @"End" : _endInterpolator,
           @"Offset" : _offsetInterpolator};
}

- (BOOL)needsUpdateForFrame:(NSNumber *)frame {
  return ([_startInterpolator hasUpdateForFrame:frame] ||
          [_endInterpolator hasUpdateForFrame:frame] ||
          [_offsetInterpolator hasUpdateForFrame:frame]);
}

- (BOOL)updateWithFrame:(NSNumber *)frame
      withModifierBlock:(void (^ _Nullable)(LOTAnimatorNode * _Nonnull))modifier
       forceLocalUpdate:(BOOL)forceUpdate {
  BOOL localUpdate = [self needsUpdateForFrame:frame];
  [self forceSetCurrentFrame:frame];
  if (localUpdate) {
    [self performLocalUpdate];
  }
  if (self.inputNode == nil) {
    return localUpdate;
  }
  
  BOOL inputUpdated = [self.inputNode updateWithFrame:frame withModifierBlock:^(LOTAnimatorNode * _Nonnull inputNode) {
    if ([inputNode isKindOfClass:[LOTPathAnimator class]] ||
        [inputNode isKindOfClass:[LOTCircleAnimator class]] ||
        [inputNode isKindOfClass:[LOTRoundedRectAnimator class]]) {
      [inputNode.localPath trimPathFromT:self->_startT toT:self->_endT offset:self->_offsetT];
    }
    if (modifier) {
      modifier(inputNode);
    }
    
  } forceLocalUpdate:(localUpdate || forceUpdate)];
  
  return inputUpdated;
}

- (void)performLocalUpdate {
  _startT = [_startInterpolator floatValueForFrame:self.currentFrame] / 100;
  _endT = [_endInterpolator floatValueForFrame:self.currentFrame] / 100;
  _offsetT = [_offsetInterpolator floatValueForFrame:self.currentFrame] / 360;
}

- (void)rebuildOutputs {
  // Skip this step.
}

- (LOTBezierPath *)localPath {
  return self.inputNode.localPath;
}

/// Forwards its input node's output path forwards downstream
- (LOTBezierPath *)outputPath {
  return self.inputNode.outputPath;
}

@end
