//
//  XTFontUtils.m
//  XTads
//
//  Created by Rune Berg on 24/04/15.
//  Copyright (c) 2015 Rune Berg. All rights reserved.
//

#import "XTFontUtils.h"
#import "XTStringUtils.h"
#import "XTLogger.h"


@implementation XTFontUtils

static XTLogger* logger;

static XTFontUtils *singletonInstance;

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

+ (id)fontUtils
{
	return singletonInstance;
}

- (NSFont *)boldVersionOfFont:(NSFont *)font
{
	// See http://www.cocoabuilder.com/archive/cocoa/133618-nsfont-bold.html
	
	NSFontManager *nsfontManager = [NSFontManager sharedFontManager];
	NSFont* boldFont = [nsfontManager convertFont:font toHaveTrait:NSBoldFontMask];
	if (boldFont == font) {
		// original font has no bold version, so try a different approach
		boldFont = [nsfontManager convertWeight:YES ofFont:font];
	}
	return boldFont;
}

- (CGFloat)defaultTextLineHeight:(NSFont *)font;
{
	NSLayoutManager *layoutMgr = [NSLayoutManager new];
	CGFloat res = [layoutMgr defaultLineHeightForFont:font];
	//CGFloat dbo = [layoutMgr defaultBaselineOffsetForFont:font];
		//TODO use?
	return res;
}

- (CGFloat)defaultWidthOfString:(NSString *)string inFont:(NSFont *)font;
{
	// See http://stackoverflow.com/questions/3692143/cocoa-get-string-width-in-pixels-from-font
	
	NSDictionary *attrsDict = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
	NSSize size = [string sizeWithAttributes:attrsDict];
	CGFloat width = size.width;
	if (! font.isFixedPitch) {
		//TODO exp rm'd: width = width * (1.185);  // because sizeWithAttributes doesn't seem to work quite right
	}
	
	width = ceil(width); // round up to a whole number
	
	return width;
}

//TODO test w/ nbsp
- (CGFloat)widthOfLongestIndivisibleWordInTextStorage:(NSTextStorage *)textStorage
										layoutManager:(NSLayoutManager *)layoutManagerRemoveXXX //TODO rm
									numCharsInLongest:(NSUInteger *)numCharsInLongest
{
	XT_DEF_SELNAME;
	
	NSSize viewSize = NSMakeSize(10000.0, 10000.0);
	
	CGFloat widthOfLongest = 0.0;
	
	//TODO make member field or sep class?
	NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
	NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:NSMakeSize(10000.0, 10000.0)];
	[layoutManager addTextContainer:textContainer];
	[textStorage addLayoutManager:layoutManager];
									  
	NSString *string = [textStorage string];
	NSUInteger stringLen = [string length];
	NSCharacterSet *breakingWhitespaceCharSet = [XTStringUtils breakingWhitespaceCharSet];
	
	BOOL isInWord = NO;
	
	NSUInteger currentWordStartIdx = 0;
	NSUInteger currentWordEndIdx = 0;
	NSUInteger lengthOfWidest = 0;
	
	for (NSUInteger i = 0; i < stringLen; i++) {
		unichar ch = [string characterAtIndex:i];
		BOOL chIsBreakingWhitespace = [breakingWhitespaceCharSet characterIsMember:ch];
		if (! isInWord) {
			if (! chIsBreakingWhitespace) {
				// starting a word
				currentWordStartIdx = i;
				currentWordEndIdx = i;
				isInWord = YES;
			}
		} else {
			if (chIsBreakingWhitespace) {
				// ending a word
				NSUInteger lengthOfCurrent = currentWordEndIdx - currentWordStartIdx + 1;
				
				NSSize size = [self requiredRectForTextStorage:textStorage
														 range:NSMakeRange(currentWordStartIdx, lengthOfCurrent)
												 forViewOfSize:viewSize];
							   
				CGFloat widthOfCurrent = size.width;
				if (widthOfCurrent > widthOfLongest) {
					widthOfLongest = widthOfCurrent;
					lengthOfWidest = lengthOfCurrent;
				}
				isInWord = NO;
			} else {
				currentWordEndIdx = i;
			}
		}
	}
	
	if (isInWord) {
		NSUInteger lengthOfCurrent = currentWordEndIdx - currentWordStartIdx + 1;
		
		NSSize size = [self requiredRectForTextStorage:textStorage
												 range:NSMakeRange(currentWordStartIdx, lengthOfCurrent)
										 forViewOfSize:viewSize];
		
		CGFloat widthOfCurrent = size.width;
		if (widthOfCurrent > widthOfLongest) {
			widthOfLongest = widthOfCurrent;
			lengthOfWidest = lengthOfCurrent;
		}
	}

	[textStorage removeLayoutManager:layoutManager];
	
	widthOfLongest = ceil(widthOfLongest);
	XT_TRACE_2(@"-> %f (%lu)", widthOfLongest, lengthOfWidest);
	
	*numCharsInLongest = lengthOfWidest;
	return widthOfLongest;
}

- (CGFloat)widthOfLongestLineInTextStorage:(NSTextStorage *)textStorage
{
	//XT_DEF_SELNAME;
	
	NSString *string = [textStorage string];
	
	NSSize size = [self requiredRectForTextStorage:textStorage
											 range:[XTStringUtils rangeOfLongestLineIn:string]
									 forViewOfSize:NSMakeSize(10000.0, 10000.0)];
	return size.width;
}

- (CGFloat)heightOfText:(NSTextView *)textView
{
	CGFloat fullWidth = textView.bounds.size.width;
	CGFloat usableWidth = textView.bounds.size.width;
	NSSize inset = textView.textContainerInset;
	CGFloat totalInsetWidth = inset.width * 2.0;  // both lhs and rhs
	usableWidth = fullWidth - totalInsetWidth;
	if (usableWidth < totalInsetWidth) {
		usableWidth = totalInsetWidth;
	}
	if (usableWidth <= 0.0) {
		usableWidth = 16.0;
	}
	
	NSTextStorage *textStorage = [textView textStorage];

	NSSize size = [self requiredRectForTextStorage:[textView textStorage]
											 range:NSMakeRange(0, textStorage.length)
									 forViewOfSize:NSMakeSize(usableWidth, 10000.0)];
	
	return size.height;
}

- (NSSize)requiredRectForTextStorage:(NSTextStorage *)textStorage
							   range:(NSRange)range
					   forViewOfSize:(NSSize)viewSize {
	
	NSLayoutManager *tempLayoutManager = [[NSLayoutManager alloc] init];
	NSTextContainer *tempTextContainer = [[NSTextContainer alloc] initWithSize:viewSize];
	[tempLayoutManager addTextContainer:tempTextContainer];
	[textStorage addLayoutManager:tempLayoutManager];

	NSRect res = [tempLayoutManager boundingRectForGlyphRange:range inTextContainer:tempTextContainer];
	res.size.width = ceil(res.size.width);
	res.size.height = ceil(res.size.height);
	
	[tempLayoutManager removeTextContainerAtIndex:0];
	[textStorage removeLayoutManager:tempLayoutManager];
	
	return res.size;
}

@end
