//
//  XTRequiredRectForTextCache.m
//  XTads
//
//  Created by Rune Berg on 27/11/2018.
//  Copyright © 2018 Rune Berg. All rights reserved.
//

#import "XTRequiredRectForTextCache.h"
#import "XTRequiredRectForTextCacheValue.h"
#import "XTLogger.h"
#import "XTAllocDeallocCounter.h"


@interface XTRequiredRectForTextCache ()

@property NSMutableDictionary<NSAttributedString *, XTRequiredRectForTextCacheValue *> *cache;
@property NSUInteger hitCount;
@property NSUInteger missCount;
@property NSUInteger maxSize;
@property NSUInteger outdatedCount;

@end


@implementation XTRequiredRectForTextCache

static XTLogger* logger;

static XTRequiredRectForTextCache *singletonInstance;

static NSUInteger MAX_CACHE_SIZE = 1000;

+ (void)initialize
{
	logger = [XTLogger loggerForClass:[XTRequiredRectForTextCache class]];

	if (self == [XTRequiredRectForTextCache class]) {
		singletonInstance = [XTRequiredRectForTextCache new];
	}
}

- (instancetype)init
{
	self = [super init];
	if (self) {
		_cache = [NSMutableDictionary dictionaryWithCapacity:MAX_CACHE_SIZE];
		_hitCount = 0;
		_missCount = 0;
		_maxSize = 0;
		_outdatedCount = 0;
	}
	return self;
}

+ (XTRequiredRectForTextCache *)singletonInstance
{
	return singletonInstance;
}

OVERRIDE_ALLOC_FOR_COUNTER
OVERRIDE_DEALLOC_FOR_COUNTER

+ (void)reset
{
	singletonInstance.cache = [NSMutableDictionary dictionaryWithCapacity:MAX_CACHE_SIZE];
}

- (NSSize)getSizeForText:(NSAttributedString *)text viewSize:(NSSize)viewSize
{
	XTRequiredRectForTextCacheValue *value = [self.cache objectForKey:text];
	
	//TODO !!! check len of attrStr vs value
	//TODO !!! check viewSize arg vs value
	
	BOOL hit = NO;
	if (value != nil) {
		if (NSEqualSizes(viewSize, value.viewSize)) {
			if (text.length == value.textLength) {
				// Same text in same view size and of same length
				hit = YES;
			}
		}
		if (! hit) {
			// remove outdated value
			[self.cache removeObjectForKey:text];
			self.outdatedCount += 1;
		}
	}
	
	NSSize res;
	if (hit) {
		res = value.requiredSize;
		self.hitCount += 1;
	} else {
		 res = NSZeroSize; // meaning not found
		self.missCount += 1;
	}
	
	if (self.cache.count > self.maxSize) {
		self.maxSize = self.cache.count;
	}
	
	//XT_DEF_SELNAME;
	//XT_WARN_1(@"%@", [self statsString]);
	
	return res;
}

- (void)noteSize:(NSSize)requiredSize forText:(NSAttributedString *)text viewSize:(NSSize)viewSize
{
	if (self.cache.count > MAX_CACHE_SIZE) {
		// Don't let us grow too big (obesity kills)
		[self.cache removeAllObjects];
	}
	
	XTRequiredRectForTextCacheValue *value = [XTRequiredRectForTextCacheValue new];
	value.requiredSize = requiredSize;
	value.viewSize = viewSize;
	value.textLength = text.length;

	[self.cache setObject:value forKey:text];
}

- (NSString *)statsString
{
	double hitPct = 0.0;
	if ((self.hitCount + self.missCount) >= 1) {
		double totalCount = self.hitCount + self.missCount;
		hitPct = (((double)self.hitCount) / totalCount) * 100.0;
	}
		
	NSString *res = [NSString stringWithFormat:@"hit%%=%lf hitCount=%ld missCount=%ld outdatedCount=%ld size=%ld maxSize=%ld",
					 hitPct, self.hitCount, self.missCount, self.outdatedCount, self.cache.count, self.maxSize];
	return res;
}

@end
