//
//  XTAllocDeallocCounter.m
//  XTads
//
//  Created by Rune Berg on 08/07/2017.
//  Copyright © 2017 Rune Berg. All rights reserved.
//

#import "XTAllocDeallocCounter.h"
#import "XTLogger.h"


@interface XTAllocDeallocCounter ()

@property (atomic) NSMutableDictionary *allocsByClassName;
@property (atomic) NSMutableDictionary *deallocsByClassName;

@end


@implementation XTAllocDeallocCounter

static XTLogger* logger;

static XTAllocDeallocCounter* singletonInstance;

+ (void)initialize
{
	logger = [XTLogger loggerForClass:[XTAllocDeallocCounter class]];
	singletonInstance = [XTAllocDeallocCounter new];
}

+ (instancetype)instance
{
	return singletonInstance;
}

- (instancetype)init
{
	self = [super init];
	if (self) {
		_allocsByClassName = [NSMutableDictionary dictionary];
		_deallocsByClassName = [NSMutableDictionary dictionary];
	}
	return self;
}

- (void)countAllocOf:(id)object
{
	//XT_DEF_SELNAME;
	//XT_WARN_1(@"%@", NSStringFromClass([object class]));
	
	[self incCounter:self.allocsByClassName of:object];
}

- (void)countDeallocOf:(id)object
{
	//XT_DEF_SELNAME;
	//XT_WARN_1(@"%@", NSStringFromClass([object class]));
	
	[self incCounter:self.deallocsByClassName of:object];
}

- (void)incCounter:(NSMutableDictionary *)countByClassName of:(id)object
{
	NSString *className = NSStringFromClass([object class]);
	
	NSNumber *countObj = [countByClassName objectForKey:className];
	
	NSUInteger count;
	if (countObj != nil) {
		count = countObj.unsignedIntegerValue;
	} else {
		count = 0;
	}
	count += 1;
	countObj = [NSNumber numberWithUnsignedInteger:count];
	
	[countByClassName setObject:countObj forKey:className];
}

- (NSUInteger)getStatsForClassName:(NSString *)className
{
	NSUInteger res = 0;
	
	NSNumber *allocCountObj = [singletonInstance.allocsByClassName objectForKey:className];
	if (allocCountObj != nil) {
		res = allocCountObj.unsignedIntegerValue;
	}
	
	NSNumber *deallocCountObj = [singletonInstance.deallocsByClassName objectForKey:className];
	if (deallocCountObj != nil) {
		res -= deallocCountObj.unsignedIntegerValue;
	}
	
	return res;
}

- (void)showStatsFiltered:(BOOL)filtered
{
	XT_DEF_SELNAME;
	
	for (NSString *className in [self.allocsByClassName.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
		NSNumber *countAllocsObj = [self.allocsByClassName objectForKey:className];
		NSUInteger countAllocs = (countAllocsObj == nil ? 0 : countAllocsObj.unsignedIntegerValue);
		NSNumber *countDeallocsObj = [self.deallocsByClassName objectForKey:className];
		NSUInteger countDeallocs = (countDeallocsObj == nil ? 0 : countDeallocsObj.unsignedIntegerValue);
		NSUInteger countAlive = countAllocs - countDeallocs;
		if (! filtered || countAlive > 1) {
			XT_WARN_4(@"%@: %lu (a: %lu, d: %lu)", className, countAlive, countAllocs, countDeallocs);
		}
	}
}

+ (void)showStats
{
	[singletonInstance showStatsFiltered:NO];
}

+ (void)showStatsFiltered
{
	[singletonInstance showStatsFiltered:YES];
}

@end
