         updatePlayer(playIfNeeded: touch?.phase == .ended)
     }
     
+    @objc fileprivate func playPauseButtonAction(button: UIButton) {
+        if self.player.rate == 0 {
+            // possible to not work
+            // CMTIME_COMPARE_INLINE not supported in swift
+            if self.player.currentTime() == self.player.currentItem?.duration {
+                // if the video has ended, seeking to initial time and playing it again
+                // in one word, replay!
+                self.player.seek(to: kCMTimeZero, completionHandler: { (done: Bool) in
+                    self.player.play()
+                })
+            } else {
+                self.player.play()
+            }
+        } else {
+            self.player.pause()
+        }
+    }
+    
+    //MARK: observer kvo
+    
     override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
         if CMTIME_IS_VALID((self.player.currentItem?.duration)!) && !CMTIME_IS_INDEFINITE((self.player.currentItem?.duration)!) {
             self.player.currentItem?.removeObserver(self, forKeyPath: SHVideoPlayerConstants.ObserverKey.duration)

        })
    }
    
    @objc fileprivate func sliderTapAction(gesture: UITapGestureRecognizer) {
        if (self.slider?.isHighlighted)! { return }
        var isPlaying = self.player.rate > 0
        var trackRect = self.slider?.trackRect(forBounds: (self.slider?.bounds)!)
        var thumbRect = self.slider?.thumbRect(forBounds: (self.slider?.bounds)!, trackRect: trackRect!, value: 0)
        var thumbWidth = thumbRect?.size.width
        var point = gesture.location(in: self.slider)
        var ratio = 0.0
        if point.x > thumbWidth! / 2 { ratio = 0.0 }
        else if point.x > ((self.slider?.bounds.size.width)! - thumbWidth! / 2) {
            ratio  = 1.0
        } else {
            ratio = Double(Float((point.x - thumbWidth! / 2) / (self.slider?.bounds.size.width)! - thumbWidth!))
        }
        var del = ratio * Double((self.slider?.maximumValue)! - (self.slider?.minimumValue)!)
        var value = (self.slider?.maximumValue)! + Float(del);
        self.slider?.setValue(value, animated: true)
        updatePlayer(playIfNeeded: isPlaying)
    }
    


class SHVideoPlayerScrubber: NSObject {
    
    fileprivate var player: AVPlayer
    fileprivate var slider: UISlider
    
    fileprivate var currentTimeLabel: UILabel
    fileprivate var durationLabel: UILabel
    fileprivate var remainingTimeLabel: UILabel
    fileprivate var playPauseButton: UIButton
    
    fileprivate var timeObserver: Any?
    
    fileprivate var playAfterDrag: Bool = true
    fileprivate var framesPerSecond: Float = 0.0
    
    init(with player:AVPlayer, slider: UISlider, currentTimeLabel: UILabel, durationLabel: UILabel, remainingTimeLabel: UILabel, playPauseButton: UIButton) {
        self.player = player
        self.slider = slider
        self.currentTimeLabel = currentTimeLabel
        self.durationLabel = durationLabel
        self.remainingTimeLabel = remainingTimeLabel
        self.playPauseButton = playPauseButton
    }
    
    open func initComponents() {
        self.setUpPlayer()
        self.setSliderTapAction()
        self.setSliderValueChangeAction()
        self.setPlayPauseButtonAction()
    }
    
    fileprivate func setUpPlayer() {
        self.player.pause()
        removeTimeObserver()
        self.framesPerSecond = nominalFrameRateForPlayer()
        setupTimeObserver()
        updateCurrentTimeLabelWithTime(time: 0)
        var duration = self.player.currentItem?.duration
        if !CMTIME_IS_VALID(duration!) || CMTIME_IS_INDEFINITE(duration!) {
            self.player.currentItem?.addObserver(self, forKeyPath: SHVideoPlayerConstants.ObserverKey.duration, options: .new, context: nil)
        }
    }
    
    fileprivate func setSliderTapAction() {
        if self.slider == nil { return }
        let gesture = UITapGestureRecognizer(target: self, action: #selector(sliderTapAction))
        slider.addGestureRecognizer(gesture)
    }
    
    fileprivate func setSliderValueChangeAction() {
        slider.addTarget(self, action: #selector(sliderValueChangeAction), for: .valueChanged)
    }
    
    fileprivate func setPlayPauseButtonAction() {
        playPauseButton.addTarget(self, action: #selector(playPauseButtonAction), for: .touchUpInside)
    }
    
    fileprivate func setupTimeObserver() {
