//
//  SingleLineTextFieldSizer.swift
//  NetNewsWire
//
//  Created by Brent Simmons on 2/19/18.
//  Copyright © 2018 Ranchero Software. All rights reserved.
//

import AppKit

// Get the size of an NSTextField configured with a specific font with a specific size.
// Uses a cache.
// Main thready only.

@MainActor final class SingleLineTextFieldSizer {

	let font: NSFont
	private let textField: NSTextField
	private var cache = [String: NSSize]()

	/// Get the NSTextField size for text, given a font.
	static func size(for text: String, font: NSFont) -> NSSize {
		return sizer(for: font).size(for: text)
	}

	init(font: NSFont) {
		self.textField = NSTextField(labelWithString: "")
		self.textField.font = font
		self.font = font
	}

	func size(for text: String) -> NSSize {
		if let cachedSize = cache[text] {
			return cachedSize
		}

		textField.stringValue = text
		var calculatedSize = textField.fittingSize
		calculatedSize.height = ceil(calculatedSize.height)
		calculatedSize.width = ceil(calculatedSize.width)
		
		cache[text] = calculatedSize
		return calculatedSize
	}

	static private var sizers = [SingleLineTextFieldSizer]()

	static private func sizer(for font: NSFont) -> SingleLineTextFieldSizer {
		// We used to use an [NSFont: SingleLineTextFieldSizer] dictionary —
		// until, in 10.14.5, we started getting crashes with the message:
		//    Fatal error: Duplicate keys of type 'NSFont' were found in a Dictionary.
		//    This usually means either that the type violates Hashable's requirements, or
		//    that members of such a dictionary were mutated after insertion.
		// We use just an array of sizers now — which is totally fine,
		// because there’s only going to be like three of them.
		if let cachedSizer = sizers.first(where: { $0.font == font }) {
			return cachedSizer
		}

		let newSizer = SingleLineTextFieldSizer(font: font)
		sizers.append(newSizer)

		return newSizer
	}
}
