 import ReactiveCocoa
 
 class UsersViewModel {
+    
+    /// The cononical list of UserViewModels vended to UsersViewController.
+    /// Should only be updated on viewModelsQueue.
     var userViewModels: [UserViewModel]? = nil
     
+    /// Data source of User objects.
     private let userController: UserController
+    
+    /// Data source of image data.
     private let imageController: ImageController
     
+    /// RAC Action that vends [UserViewModel].
+    /// At the moment we assume this will never error, although real requests would handle that case.
     private let fetchUserViewModelsAction: Action<Void, [UserViewModel], NoError>
 
+    /// Signal/Observer pair whose events represent a full reload of userViewModels.
     let reloadSignal: Signal<Void, NoError>
     private let reloadObserver: Observer<Void, NoError>
     
+    /// Signal/Observer pair whose events represent a change to some indexPaths.
     let reloadIndexPathsSignal: Signal<[NSIndexPath], NoError>
     private let reloadIndexPathsObserver: Observer<[NSIndexPath], NoError>
     
+    /// All updates to userViewModels should be performed on this queue.
+    /// TODO: should this be QueueScheduler.mainQueueScheduler because that's where userViewModels is observed?
     let viewModelsQueue = QueueScheduler(qos: QOS_CLASS_USER_INITIATED, name: "com.twocentstudios.UserList.viewmodels")
+    
+    /// A general queue for performing view model fetching and transformations.
     let workQueue = QueueScheduler(qos: QOS_CLASS_DEFAULT, name: "com.twocentstudios.UserList.work")
+    
+    /// All image requests run on this queue.
+    /// TODO: Figure out how to make this a concurrent queue.
     let imageQueue = QueueScheduler(qos: QOS_CLASS_DEFAULT, name: "com.twocentstudios.UserList.image")
     
     init(userController: UserController, imageController: ImageController) {

            }
    }
    
    func fetchUserViewModels() {
        fetchUserViewModelsAction.apply().start()
    }
    
    func activateIndexPath(indexPath: NSIndexPath) {
        guard let userViewModel = userViewModels?[indexPath.row] else { return }
        if userViewModel.shouldFetchAvatarImage() {
            self.loadUserViewModelImageProducer(userViewModel).start()
        }
    }
    
    private func loadUserViewModelImageProducer(userViewModel: UserViewModel) -> SignalProducer<(UserViewModel, [UserViewModel], [NSIndexPath]), NoError> {
        return SignalProducer<UserViewModel, NoError>(value: userViewModel)
            .observeOn(workQueue)
            .flatMap(FlattenStrategy.Latest, transform: self.loadingImageUserViewModelImageProducer)
            .observeOn(viewModelsQueue)
            .flatMap(.Latest, transform: { [unowned self] viewModel -> SignalProducer<(UserViewModel, [UserViewModel], [NSIndexPath]), NoError> in
                guard let userViewModels = self.userViewModels else { return .empty }
                return self.replaceUserViewModelProducer(viewModel, userViewModels: userViewModels)
            })
            .on(next: { [unowned self] (userViewModel, userViewModels, changedIndexPaths) in
                self.userViewModels = userViewModels
                self.reloadIndexPathsObserver.sendNext(changedIndexPaths)
            })
            .observeOn(imageQueue)
            .map { (viewModel: UserViewModel, _, _) in return viewModel }
            .flatMap(.Latest, transform: self.fetchUserViewModelImageProducer)
            .observeOn(viewModelsQueue)
            .flatMap(.Latest, transform: { [unowned self] (viewModel: UserViewModel) -> SignalProducer<(UserViewModel, [UserViewModel], [NSIndexPath]), NoError> in
                guard let userViewModels = self.userViewModels else { return .empty }
                return self.replaceUserViewModelProducer(viewModel, userViewModels: userViewModels)
            })

                }
        }
        
        /// When new values are vended by fetchUserViewModelsAction, update userViewModels on viewModelsQueue.
        fetchUserViewModelsAction.values
            .observeOn(viewModelsQueue)
            .observeNext { [unowned self] userViewModels in
