//
//  XTTextStorageBatcher.m
//  XTads
//
//  Created by Rune Berg on 17/05/2019.
//  Copyright © 2019 Rune Berg. All rights reserved.
//

#import "XTTextStorageBatcher.h"
#import "XTStringUtils.h"
#import "XTLogger.h"
#import "XTMutableAttributedStringHelper.h"
#import "XTAllocDeallocCounter.h"


@interface XTTextStorageBatcher ()

@property NSMutableArray<NSMutableAttributedString *> *batchedAttrStringArray;

@end


@implementation XTTextStorageBatcher

static XTLogger* logger;

static NSUInteger CAPACITY = 100;
static NSUInteger BATCH_LIMIT = 90;

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

OVERRIDE_ALLOC_FOR_COUNTER
OVERRIDE_DEALLOC_FOR_COUNTER

- (instancetype)init
{
	self = [super init];
	if (self) {
		_batchedAttrStringArray = [NSMutableArray arrayWithCapacity:CAPACITY];
	}
	return self;
}

- (BOOL)append:(NSAttributedString *)attrString
{
	NSMutableAttributedString *mutAttrString = [self toMutable:attrString];
	[self.batchedAttrStringArray addObject:mutAttrString];
	
	NSUInteger totalLength = [self lengthOfRemainingBatchedText];
	
	BOOL res;
	if (totalLength > BATCH_LIMIT) {
		res = YES;
	} else {
		res = NO;
		// A <tab id=...> requires immediate handling, so counts as "over batch limit"
		NSArray<XTHtmlTagTab *> * tagTabArray = [XTMutableAttributedStringHelper getTabTagsForString:attrString];
		for (XTHtmlTagTab *tagTab in tagTabArray) {
			if ([tagTab isForId]) {
				res = YES;
				break;
			}
		}
	}
	return res;
}

- (void)insert:(NSAttributedString *)attrString atIndex:(NSUInteger)idx
{
	NSMutableAttributedString *mutAttrString = [self toMutable:attrString];
	[self.batchedAttrStringArray insertObject:mutAttrString atIndex:idx];
}

- (NSAttributedString *)getBatchedString
{
	NSAttributedString *res = nil;
	if (self.batchedAttrStringArray.count >= 1) {
		res = [self getBatchedStringToIndex:(self.batchedAttrStringArray.count - 1)];
	}
	return res;
}

- (NSUInteger)getBatchedSubStringCount
{
	return self.batchedAttrStringArray.count;
}

//TODO !!! if we can, use immutable in params/retvals

- (NSAttributedString *)getBatchedSubStringAtIndex:(NSUInteger)index
{
	NSAttributedString *res;
	if (index < self.batchedAttrStringArray.count) {
		res = self.batchedAttrStringArray[index];
	} else {
		XT_DEF_SELNAME;
		XT_WARN_1(@"index %lu is outside batchedAttrStringSuffixArray", index);
		res = nil;
	}
	return res;
}

- (NSArray<NSMutableAttributedString *> *)getBatchedSubStringsToIndex:(NSUInteger)index
{
	NSRange range = NSMakeRange(0, 1 + index);
		//TODO !!! what if no content?
	NSArray<NSMutableAttributedString *> *res = [self.batchedAttrStringArray subarrayWithRange:range];
	return res;
}

- (void)pruneToIndex:(NSUInteger)index
{
	//XT_DEF_SELNAME;
	
	NSUInteger numToRemove = index + 1;
	NSRange rangeToRemove = NSMakeRange(0, numToRemove);
	[self.batchedAttrStringArray removeObjectsInRange:rangeToRemove];
}

- (NSArray<NSMutableAttributedString *>*)flush
{
	//XT_WARN_ENTRY;

	NSRange range = NSMakeRange(0, self.batchedAttrStringArray.count);
	NSArray<NSMutableAttributedString *>* res = [self.batchedAttrStringArray subarrayWithRange:range];
	[self clearState];
	return res;
}

- (BOOL)hasContents
{
	BOOL res = (self.batchedAttrStringArray.count >= 1);
	return res;
}

- (void)removeTrailingWhitespace
{
	NSUInteger count = self.batchedAttrStringArray.count;
	for (NSInteger idx = count - 1; idx >= 0; idx--) {
		NSMutableAttributedString *mutAttrStr = self.batchedAttrStringArray[idx];
		NSRange range = [XTStringUtils findRangeOfTrailingWhitespaceInLastParagraph:mutAttrStr.string];
		if (range.location != NSNotFound && range.length >= 1) {
			[mutAttrStr deleteCharactersInRange:range];
			if (range.location >= 1) {
				// only part of mutAttrStr was whitespace and deleted
				break;
			}
		} else {
			// No trailing whitespace - we're done
			break;
		}
	}
}

- (void)reset
{
	[self clearState];
}

- (NSUInteger)lengthOfRemainingBatchedText
{
	NSUInteger res = 0;
	for (NSAttributedString *attrStringIter in self.batchedAttrStringArray) {
		res += attrStringIter.length;
	}
	return res;
}

- (void)clearState
{
	[self.batchedAttrStringArray removeAllObjects];
}

- (NSAttributedString *)getBatchedStringToIndex:(NSUInteger)idxInclusive
{
	NSAttributedString *res = nil;
	if (self.batchedAttrStringArray.count >= 1) {
		NSMutableAttributedString *mutableAttrStr = [NSMutableAttributedString new];
		for (NSUInteger idx = 0; idx <= idxInclusive; idx += 1) {
			NSAttributedString *attrString = self.batchedAttrStringArray[idx];
			[mutableAttrStr appendAttributedString:attrString];
		}
		res = [[NSAttributedString alloc] initWithAttributedString:mutableAttrStr];
	}
	return res;
}

- (NSMutableAttributedString *)toMutable:(NSAttributedString *)attrString
{
	NSMutableAttributedString *mutAttrAtring;
	if ([attrString isKindOfClass:[NSMutableAttributedString class]]) {
		mutAttrAtring = (NSMutableAttributedString *)attrString;
	} else {
		mutAttrAtring = [NSMutableAttributedString new];
		[mutAttrAtring appendAttributedString:attrString];
	}
	return mutAttrAtring;
}

@end
