//
//  NSTimer+Rx.swift
//
//  Created by Ivan Bruel on 20/07/16.
//  Copyright © 2016 Faber Ventures. All rights reserved.
//

import Foundation
import RxSwift

public extension Reactive where Base: Timer {

  static var timer: Observable<Void> {
    return timer(1.0)
  }

  static func timer(_ time: TimeInterval) -> Observable<Void> {
    return Observable<Void>.create { observer in
      observer.onNext(())
      let timer = Timer.rx.schedule(repeatInterval: time) {
        observer.onNext(())
      }
      return Disposables.create {
        observer.onCompleted()
        timer.invalidate()
      }
    }
  }
}

private extension Reactive where Base: Timer {
  /*
   Creates and schedules a one-time `NSTimer` instance.

   - Parameters:
   - delay: The delay before execution.
   - handler: A closure to execute after `delay`.
   - Returns: The newly-created `NSTimer` instance.
   */
  static func schedule(delay: TimeInterval, handler: @escaping ()->()) -> Timer {
    let fireDate = delay + CFAbsoluteTimeGetCurrent()
    let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, 0, 0, 0) { theTimer in
      handler()
    }
    
    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
    return timer!
  }
  
  /*
   Creates and schedules a repeating `NSTimer` instance.

   - Parameters:
   - repeatInterval: The interval (in seconds) between each execution of
   `handler`. Note that individual calls may be delayed; subsequent calls
   to `handler` will be based on the time the timer was created.
   - handler: A closure to execute at each `repeatInterval`.
   - Returns: The newly-created `NSTimer` instance.
   */
  static func schedule(repeatInterval interval: TimeInterval, handler: @escaping () -> Void)
    -> Timer {
      let fireDate = interval + CFAbsoluteTimeGetCurrent()
      let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, interval, 0, 0) {
        theTimer in
        handler()
      }
      
      CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
      return timer!
  }
}
