//
//  MFLoadingSpinner.m
//  mobilefirst
//
//  Created by Wesolowski, Brendan on 3/10/16.
//  Copyright © 2016 Verizon Wireless. All rights reserved.
//

#import "MFLoadingSpinner.h"
#import "UIColor+MFConvenience.h"
#import "NSLayoutConstraint+MFConvenience.h"

@interface MFLoadingSpinner ()

@property (strong, nonatomic) CAShapeLayer *myCircle;
@property (strong, nonatomic) CADisplayLink *myDisplay;
@property (weak, nonatomic) dispatch_block_t resumeBlock;

@property (nonatomic) double prevFrame;

@property (nonatomic) BOOL isFast;

@end

@implementation MFLoadingSpinner




const float radius = 19;
const float lineWidth = 3.0;
const float slowSpeed = 0.5;
const float fastSpeed = 2.0;
const float startSpeed = 1.0;
const float fastDistance = .45;
const float slowDistance = 0.1;


-(void)finalize {
	[self.myDisplay invalidate];
	self.myDisplay = nil;
}

-(void)setUpCircle {
	[self setUpCircle:[UIColor blackColor]];
}

-(void)setUpCircle:(UIColor *)strokeColor {
	if(self.myCircle)
	{
		return;
	}
	
	CAShapeLayer *circle = [CAShapeLayer layer];
	circle.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius + lineWidth/2, radius + lineWidth/2) radius:radius startAngle:-M_PI_2 endAngle:3.5*M_PI clockwise:YES].CGPath;
	circle.lineWidth = lineWidth;
	circle.fillColor = [UIColor clearColor].CGColor;
	circle.strokeColor = strokeColor.CGColor;
	circle.lineCap = kCALineCapButt;
	circle.strokeStart = 0;
	circle.strokeEnd = 0+.05;
	[self.layer addSublayer:circle];
	self.myCircle = circle;
	
	self.isFast = YES;
	
	NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"strokeStart",
									   [NSNull null], @"strokeEnd",
									   [NSNull null], @"strokeColor",
									   nil];
	circle.actions = newActions;

	self.myDisplay = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateSpinner)];
	[self.myDisplay addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
	self.myDisplay.frameInterval = 2;
	self.prevFrame = CACurrentMediaTime();
}

-(void)changeColor:(UIColor *)strokeColor {
	self.myCircle.strokeColor = strokeColor.CGColor;
}

-(void)updateSpinner {
	double currentTime = CACurrentMediaTime();
	double renderTime = currentTime - self.prevFrame;
	self.prevFrame = currentTime;
	
	if(self.myCircle.strokeStart > 0.5 && self.myCircle.strokeEnd > 0.5) {
		self.myCircle.strokeStart -= 0.5;
		self.myCircle.strokeEnd -= 0.5;
	}

	float distanceToStart = self.myCircle.strokeEnd - self.myCircle.strokeStart;
	if(distanceToStart < slowDistance && !self.isFast) {
		self.isFast = YES;
	}
	else if(distanceToStart > fastDistance && self.isFast) {
		self.isFast = NO;
	}
	self.myCircle.strokeEnd += (self.isFast ? fastSpeed : slowSpeed) * renderTime;
	self.myCircle.strokeStart+= startSpeed * renderTime;

}

- (void)pauseSpinner {
    if (self.resumeBlock) {
        // Cancel the current resume block if it hasn't run. dispatch our pause into the same queue incase the resume block is already running.
        dispatch_block_cancel(self.resumeBlock);
        self.resumeBlock = nil;
        __weak typeof(self) weakSelf = self;
        dispatch_async(dispatch_get_main_queue(), ^{
            weakSelf.myDisplay.paused = YES;
            weakSelf.hidden = YES;
        });
    } else {
        self.myDisplay.paused = YES;
        self.hidden = YES;
    }
}

- (void)resumeSpinner {
    self.hidden = NO;
	if (!self.myCircle) {
		[self setUpCircle];
		return;
	}
	
	self.myDisplay.paused = NO;
	self.prevFrame = CACurrentMediaTime();
}

- (void)resumeSpinnerAfterDelay {
    if (!self.resumeBlock) {
        __weak typeof(self) weakSelf = self;
        dispatch_block_t resume = dispatch_block_create(0, ^{
            [weakSelf resumeSpinner];
            weakSelf.resumeBlock = nil;
        });
        self.resumeBlock = resume;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), resume);
    }
}

- (nullable NSDictionary *)pinWidthAndHeight {
    CGFloat diameter = radius*2 + lineWidth;
    return [NSLayoutConstraint constraintPinView:self heightConstraint:YES heightConstant:diameter widthConstraint:YES widthConstant:diameter];
}

@end
