//
//  AnimHelp.swift
//  Tea Talk
//
//  Created by Bilal Bakhrom on 17/11/2019.
//  Copyright © 2019 Bilal Bakhrom. All rights reserved.
//

import UIKit

struct AnimHelp {
    
    static func animation(completion: (AnimConfig) -> Void) -> CAAnimation? {
        let config = AnimConfig()
        completion(config)
        
        switch config.animationType {
        case .basicFade,
             .basicScale,
             .basicXPosition,
             .basicYPosition:
            return _basicAnimation(config: config)
            
        case .springXPosition, .springYPosition:
            return _springAnimation(config: config)
            
        case .none:
            return nil
        }
    }
    
    static private func _basicAnimation(config: AnimConfig) -> CABasicAnimation {
        let anim = CABasicAnimation(keyPath: config.animationType.keyPath)
        
        if let key = config.key {
            anim.setValue(anim, forKey: key)
        }
        
        anim.fromValue = config.fromValue
        anim.toValue = config.toValue
        anim.duration = config.duration
        anim.fillMode = config.fillMode
        anim.timingFunction = config.timingFunction
        anim.beginTime = config.beginTime
        anim.delegate = config.delegate
        anim.autoreverses = config.autoreverses
        anim.repeatCount = config.repeatCount
        return anim
    }
    
    static private func _springAnimation(config: AnimConfig) -> CASpringAnimation {
        let anim = CASpringAnimation(keyPath: config.animationType.keyPath)
        
        if let key = config.key {
            anim.setValue(anim, forKey: key)
        }
        
        anim.fromValue = config.fromValue
        anim.toValue = config.toValue
        anim.duration = config.duration
        anim.fillMode = config.fillMode
        anim.timingFunction = config.timingFunction
        anim.beginTime = config.beginTime
        anim.delegate = config.delegate
        anim.autoreverses = config.autoreverses
        anim.repeatCount = config.repeatCount
        anim.damping = config.damping
        return anim
    }
    
    static func addDuration(_ duration: CFTimeInterval) -> CFTimeInterval {
        return CACurrentMediaTime() + duration
    }

}


extension AnimHelp {
    
    class AnimConfig {
        var animationType: AnimationType = .none
        var key: String?
        var fromValue: Any?
        var toValue: Any?
        var beginTime: CFTimeInterval = 0.0
        var fillMode: CAMediaTimingFillMode = .backwards
        var timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: .easeIn)
        var delegate: CAAnimationDelegate?
        var autoreverses: Bool = false
        var repeatCount: CFloat = .zero
        
        /// Defines how the spring’s motion should be damped due to the forces of friction.
        ///
        /// Default value is 10.0
        var damping: CGFloat = 10.0
        
        
        /// Specifies the basic duration of the animation, in seconds
        ///
        /// Default value is 1.0
        var duration: CFTimeInterval = 1.0
    }
    
    enum AnimationType {
        case basicFade
        case basicScale
        case basicYPosition
        case basicXPosition
        case springYPosition
        case springXPosition
        case none
        
        var keyPath: String? {
            switch self {
            case .basicFade: return KeyPath.opacity.rawValue
            case .basicScale: return KeyPath.scale.rawValue
            case .basicYPosition, .springYPosition: return KeyPath.posY.rawValue
            case .basicXPosition, .springXPosition: return KeyPath.posX.rawValue
            case .none: return nil
            }
        }
    }
    
    enum KeyPath: String {
        case opacity = "opacity"
        case posY = "position.y"
        case posX = "position.x"
        case scale = "transform.scale"
    }
}

