//
//  Timer.swift
//  Components
//
//  Created by Vidal HARA on 14.11.2018.
//  Copyright © 2018 Vidal HARA. All rights reserved.
//

import UIKit

extension VHService {
    /// You can use VHTimer to handle timers without memory leak
    /// with delegate or completion block.
    ///
    ///     let timer = VHTimer({
    ///         // Do action
    ///     })
    ///
    ///     timer.start(sec: 5.0, isRepating: true)
    open class VHTimer {

        /// Timer
        open private(set) weak var timer: Timer?

        private var isRepeating = true
        private var interval = 0.3
        private var completionBlock: (() -> Void)?

        /// You can create VHTimer with completion block
        ///
        /// - Parameter completionBlock: Do action when timer fires
        public init(_ completionBlock: (() -> Void)? = nil) {
            self.setCompletionBlock(completionBlock)
        }

        /// Creates a timer and schedules it on the current run loop in the default mode.
        /// After seconds have elapsed, the timer fires,
        /// sending the message with delegate or completion block.
        ///
        /// - Parameters:
        ///   - sec: The number of seconds between firings of the timer.
        ///         If sec is less than or equal to 0.0 this timer will stop.
        ///   - isRepeating: If true, the timer will repeatedly reschedule itself until stopped.
        ///         If false, the timer will be invalidated after it fires.
        open func start(sec: Double = 0.3, isRepeating: Bool = true) {
            self.set(sec: sec, isRepeating: isRepeating)
            self.stop()

            timer = Timer.scheduledTimer(timeInterval: sec,
                                         target: Item(manager: self),
                                         selector: #selector(Item.fire),
                                         userInfo: nil, repeats: isRepeating)
        }

        /// Creates a timer and schedules it on the current run loop in the default mode.
        /// After time - Date().timeIntervalSince1970 seconds have elapsed, the timer fires,
        /// sending the message with delegate or completion block.
        ///
        /// - Parameters:
        ///   - time: Date timeIntervalSince1970
        ///   - isRepeating: If true, the timer will repeatedly reschedule itself until stopped.
        ///     If false, the timer will be invalidated after it fires.
        open func start(fireDateSince1970 time: Double, isRepeating: Bool = true) {
            let sec = time - Date().timeIntervalSince1970
            if sec >= 0 {
                self.start(sec: sec, isRepeating: isRepeating)
            } else {
                self.stop()
            }
        }

        /// This will work if timer is **not started** yet
        ///
        /// - Parameters:
        ///   - sec: The number of seconds between firings of the timer.
        ///         If sec is less than or equal to 0.0 this timer will stop.
        ///   - isRepeating: If true, the timer will repeatedly reschedule itself until stopped.
        ///         If false, the timer will be invalidated after it fires.
        open func set(sec: Double, isRepeating: Bool) {
            self.interval = sec
            self.isRepeating = isRepeating
        }

        /// You can set your completion block even after you create your VHTimer
        ///
        /// - Attention:
        ///     This will override the old completion block which you set.
        ///
        /// - Parameter completionBlock: Do action when timer fires
        open func setCompletionBlock(_ completionBlock: (() -> Void)?) {
            self.completionBlock = {
                completionBlock?()
            }
        }

        /// Stops the timer from ever firing again and requests its removal from its run loop.
        open func stop() {
            timer?.invalidate()
            timer = nil
        }

        /// Fire the completion block you set
        open func fire() {
            self.completionBlock?()
        }

        /// Restarts the timer with last setted interval and repeating state.
        open func reStart() {
            self.stop()
            start(sec: self.interval, isRepeating: self.isRepeating)
        }

        deinit {
            stop()
        }
    }
}



private extension VHService.VHTimer {

    private class Item {
        weak var manager: VHService.VHTimer?

        init(manager: VHService.VHTimer) {
            self.manager = manager
        }

        @objc func fire() {
            manager?.fire()
        }
    }
}

