 public class Twist: NSObject, AVAudioPlayerDelegate {
     public static let defaultPlayer = Twist()
     
-    // Public Variables
+    // MARK: Public Variables
     public var repeatMode: TwistRepeatMode = .None
     public var shuffle: Bool = false
     public var dataSource: TwistDataSource?
     public var delegate: TwistDelegate?
     
-    // Public getters, private setters
+    // MARK: Public getters, Private setters
     private(set) public var currentState = TwistState.Waiting
     private(set) public var currentIndex: Int = 0
     private(set) public var currentPlayerItem: AVPlayerItem?
 
-    // Private variables
+    // MARK: Private variables
     var player: AVPlayer?
     var preConfigured: Bool = false
     var interruptedWhilePlaying: Bool = false
     var mediaItem: MediaItem?
     var periodicObserver: AnyObject?
     
-    func preAction() {
-        self.preConfigured = true
-        self.player = AVPlayer()
-        self.registerAudioSession()
-        self.registerListeners()
-        self.setupRemoteCommandTargets()
-    }
-    
-    func registerListener(selector: Selector, notification: String) {
-        NSNotificationCenter.defaultCenter().addObserver(
-            self, selector: selector, name: notification, object: nil
-        )
-    }
-    
-    func registerListeners() {
-        registerListener(#selector(Twist.playerItemDidReachEnd(_:)), notification: AVPlayerItemDidPlayToEndTimeNotification)
-        registerListener(#selector(Twist.playerItemFailedToPlayEndTime(_:)), notification: AVPlayerItemFailedToPlayToEndTimeNotification)
-        registerListener(#selector(Twist.playerItemPlaybackStall(_:)), notification: AVPlayerItemPlaybackStalledNotification)
-        registerListener(#selector(Twist.interruption(_:)), notification: AVAudioSessionInterruptionNotification)
-        registerListener(#selector(Twist.routeChange(_:)), notification: AVAudioSessionRouteChangeNotification)
-    }
-    
-    func setupRemoteCommandTargets() {
-        let commandCenter = MPRemoteCommandCenter.sharedCommandCenter()
-        commandCenter.nextTrackCommand.addTarget(self, action: #selector(Twist.next))
-        commandCenter.previousTrackCommand.addTarget(self, action: #selector(Twist.previous))
-        commandCenter.playCommand.addTarget(self, action: #selector(Twist.play(_:)))
-        commandCenter.pauseCommand.addTarget(self, action: #selector(Twist.pause))
-        commandCenter.togglePlayPauseCommand.addTarget(self, action: #selector(Twist.togglePlayPause))
-    }
-    
-    func playerItemDidReachEnd(notification: NSNotification) {
-        self.next()
-    }
-    
-    func playerItemFailedToPlayEndTime(notification: NSNotification) {
-        self.next()
-    }
-    
-    func playerItemPlaybackStall(notification: NSNotification) {
-        debug("playback stalled")
-    }
-    
-    func interruption(notification: NSNotification) {
-        if  let notificationType = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt,
-            let interruptionType = AVAudioSessionInterruptionType(rawValue: notificationType) {
-            switch interruptionType {
-            case .Began:
-                self.interruptedWhilePlaying = (self.currentState == .Playing)
-                self.pause()
-            case .Ended:
-                if self.interruptedWhilePlaying {
-                    self.interruptedWhilePlaying = false
-                    self.play()
-                }
-            }
-        }
-    }
-    
-    func routeChange(notification: NSNotification) {
-        if  let notificationType = notification.userInfo?[AVAudioSessionRouteChangeReasonKey] as? UInt,
-            let reason = AVAudioSessionRouteChangeReason(rawValue: notificationType) {
-            switch reason {
-            case .OldDeviceUnavailable:
-                self.pause()
-                debug("Route changed and paused")
-            default:
-                debug("Route changed but no need to pause: \(notificationType.description)")
-            }
-        }
-    }
-    
-    func registerAudioSession() {
-        let audioSession = AVAudioSession.sharedInstance()
-        UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
-        
-        if audioSession.category != AVAudioSessionCategoryPlayback {
-            let device = UIDevice.currentDevice()
-            if device.multitaskingSupported {
-                do {
-                    try audioSession.setCategory(AVAudioSessionCategoryPlayback)
-                } catch let error as NSError {
-                    debug("Set Category error: \(error.localizedDescription)")
-                }
-                do {
-                    try audioSession.setActive(true)
-                } catch let error as NSError {
-                    debug("Set active error: \(error.localizedDescription)")
-                }
-            }
-        } else {
-            debug("Unable to register background playback")
-        }
-    }
-
-    public func togglePlayPause() {
-        if self.currentState == .Playing {
-            self.pause()
-        } else {
-            self.play()
-        }
-    }
-
+    // MARK: Public API
+
+    public var hasNextItem: Bool {
+        return self.currentIndex < self.dataSource!.twistNumberOfItems() - 1
+    }
+
+    public var hasPreviousItem: Bool {
+        return self.currentIndex != 0
+    }
+    
+    public var isPlayable: Bool {
+        guard let dataSource = self.dataSource else { return false }
+        return dataSource.twistNumberOfItems() > 0
+    }
+    
     public func play(index: Int = 0) {
-        if !isPlayable() {
+        if !isPlayable {
             debug("Player called but player not in playable state, doing nothing.")
             return
         }
         
-        if !preConfigured { self.preAction() }
+        if !preConfigured { self.configurePlayer() }
         
         if self.currentPlayerItem == nil {
             debug("Creating new AVPlayerItem")

        }
    }
    
    func cleanupCurrentItem() {
        self.currentState = .Waiting
        self.currentPlayerItem?.removeObserver(self, forKeyPath: kStatusKey)

            self.triggerPlaybackStateChanged()
        }
    }
    
    public func pause() {
        if !isPlayable { return }
        
        if self.currentState == .Playing {
            debug("Pausing current item")
            self.player?.pause()
