<commit_before>//
//  MacAppStatus.swift
//
//  Copyright ©2016 <NAME>. This file is licensed under the ISC license.
//

import Cocoa
import Networking
import ReactiveSwift
import Rc2Common
import MJLLogger

///used to update the progress display for an operation
struct ProgressUpdate {
	///possible stages of progress update
	enum Stage {
		case start, value, completed, failed
	}
	/// the stage of progress represented by this update
	let stage: Stage
	/// for a .value stage, a description to display to the user
	let message: String?
	/// for a .value stage, the percent complete (0...1) or -1 if indeterminate/not applicable
	let value: Double
	/// for a .failed stage, the error that caused the failure
	let error: Rc2Error?
	/// for a .start stage, determines if user interaction should be disabled
	let disableInput: Bool

	init(_ stage: Stage, message: String? = nil, value: Double = -1, error: Rc2Error? = nil, disableInput: Bool = true) {
		self.stage = stage
		self.message = message
		self.value = value
		self.error = error
		self.disableInput = disableInput
	}
}

/// represents the status of a session/window pair
class MacAppStatus {
	/// a signal to observe to receive progress updates
	let progressSignal: Signal<ProgressUpdate, Never>
	/// a signal to know if the status is busy
	let busySignal: Signal<Bool, Never>
	/// callback to get the window for a particular session
	public let getWindow: (Session?) -> NSWindow?
	/// queue used for changes to the current operation
	private let _statusQueue = DispatchQueue(label: "io.rc2.statusQueue", qos: .userInitiated)
	/// tracks if an operation is in progress, and to eventually support canceling
//	private var currentDisposable: Disposable? {
//		get {
//			var disp: Disposable?
//			_statusQueue.sync { disp = _currentDisposable }
//			return disp
//		}
//		set { _statusQueue.sync { _currentDisposable = newValue } }
//	}
	/// underlying value that should always be interacted with via currentDisposable which is thread-safe
	private var _currentDisposable: Disposable?
	/// tne name of the current action to display in completed/canceled status messages
	private var currentActionName: String?
	/// observer for sending progress updates
	private let progressObserver: Signal<ProgressUpdate, Never>.Observer
	/// observer for sending busy events
	private let busyObserver: Signal<Bool, Never>.Observer

	@objc dynamic var busy: Bool {
		var result = false
		_statusQueue.sync { result = _currentDisposable != nil }
		return result
	}

	init(windowAccessor: @escaping (Session?) -> NSWindow?) {
		getWindow = windowAccessor
		(progressSignal, progressObserver) = Signal<ProgressUpdate, Never>.pipe()
		(busySignal, busyObserver) = Signal<Bool, Never>.pipe()
	}

	/// called when a signal producer to display progress is started
	///
	/// - Parameters:
	///   - name: the name of the action being started
	///   - disposable: the disposable for the action that is starting
	fileprivate func actionStarting(name: String, disposable: Disposable, determinate: Bool) {
		Log.info("starting action \(name)", .app)
		// FIXME: if debugging, this can happen after action is finished and the assert will fail
		_statusQueue.sync {
			assert(nil == _currentDisposable)
			currentActionName = name
			_currentDisposable = disposable
			progressObserver.send(value: ProgressUpdate(.start, message: currentActionName, value: determinate ? 0 : -1))
			busyObserver.send(value: true)
		}<commit_msg>commented out assert that was causing crash<commit_after>//
//  MacAppStatus.swift
//
//  Copyright ©2016 <NAME>. This file is licensed under the ISC license.
//

import Cocoa
import Networking
import ReactiveSwift
import Rc2Common
import MJLLogger

///used to update the progress display for an operation
struct ProgressUpdate {
	///possible stages of progress update
	enum Stage {
		case start, value, completed, failed
	}
	/// the stage of progress represented by this update
	let stage: Stage
	/// for a .value stage, a description to display to the user
	let message: String?
	/// for a .value stage, the percent complete (0...1) or -1 if indeterminate/not applicable
	let value: Double
	/// for a .failed stage, the error that caused the failure
	let error: Rc2Error?
	/// for a .start stage, determines if user interaction should be disabled
	let disableInput: Bool

	init(_ stage: Stage, message: String? = nil, value: Double = -1, error: Rc2Error? = nil, disableInput: Bool = true) {
		self.stage = stage
		self.message = message
		self.value = value
		self.error = error
		self.disableInput = disableInput
	}
}

/// represents the status of a session/window pair
class MacAppStatus {
	/// a signal to observe to receive progress updates
	let progressSignal: Signal<ProgressUpdate, Never>
	/// a signal to know if the status is busy
	let busySignal: Signal<Bool, Never>
	/// callback to get the window for a particular session
	public let getWindow: (Session?) -> NSWindow?
	/// queue used for changes to the current operation
	private let _statusQueue = DispatchQueue(label: "io.rc2.statusQueue", qos: .userInitiated)
	/// tracks if an operation is in progress, and to eventually support canceling
//	private var currentDisposable: Disposable? {
//		get {
//			var disp: Disposable?
//			_statusQueue.sync { disp = _currentDisposable }
//			return disp
//		}
//		set { _statusQueue.sync { _currentDisposable = newValue } }
//	}
	/// underlying value that should always be interacted with via currentDisposable which is thread-safe
	private var _currentDisposable: Disposable?
	/// tne name of the current action to display in completed/canceled status messages
	private var currentActionName: String?
	/// observer for sending progress updates
	private let progressObserver: Signal<ProgressUpdate, Never>.Observer
	/// observer for sending busy events
	private let busyObserver: Signal<Bool, Never>.Observer

	@objc dynamic var busy: Bool {
		var result = false
		_statusQueue.sync { result = _currentDisposable != nil }
		return result
	}

	init(windowAccessor: @escaping (Session?) -> NSWindow?) {
		getWindow = windowAccessor
		(progressSignal, progressObserver) = Signal<ProgressUpdate, Never>.pipe()
		(busySignal, busyObserver) = Signal<Bool, Never>.pipe()
	}

	/// called when a signal producer to display progress is started
	///
	/// - Parameters:
	///   - name: the name of the action being started
	///   - disposable: the disposable for the action that is starting
	fileprivate func actionStarting(name: String, disposable: Disposable, determinate: Bool) {
		Log.info("starting action \(name)", .app)
		// FIXME: if debugging, this can happen after action is finished and the assert will fail
		_statusQueue.sync {
			// FIXME: why was this assert here, and why was it failing. Does it need to be fixed?
			// assert(nil == _currentDisposable)
			currentActionName = name
			_currentDisposable = disposable
			progressObserver.send(value: ProgressUpdate(.start, message: currentActionName, value: determinate ? 0 : -1))
			busyObserver.send(value: true)
		}
{'fraction_non_alphanumeric': 0.09266628766344515, 'fraction_numerical': 0.003979533826037522, 'mean_word_length': 3.780570652173913, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3941188', 'n_tokens_mistral': 2071, 'n_tokens_neox': 1928, 'n_words': 791}