//
//  XTStatusLineHandler.m
//  TadsTerp
//
//  Created by Rune Berg on 16/04/14.
//  Copyright (c) 2014 Rune Berg. All rights reserved.
//

#import "XTStatusLineHandler.h"
#import "XTHtmlTag.h"
#import "XTHtmlTagTab.h"
#import "XTHtmlWhitespace.h"
#import "XTHtmlNonbreakingSpace.h"
#import "XTOutputTextParserHtml.h"
#import "XTOutputTextParserPlain.h"
#import "XTLogger.h"
#import "XTPrefs.h"


@interface XTStatusLineHandler ()

@property XTOutputTextParserHtml *outputTextParserHtml;
@property XTOutputTextParserPlain *outputTextParserPlain;

@property NSMutableString *locationTextBuffer;
@property NSMutableString *scoreTextBuffer;

@property BOOL useAlignRightMode;
@property BOOL alignRightMode;

@end


@implementation XTStatusLineHandler

static XTLogger* logger;

static NSString *oneSpace = @" "; //nbsp: @"\u00A0";


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

- (id)init
{
    self = [super init];
    if (self) {
		_outputTextParserHtml = [XTOutputTextParserHtml new];
		_outputTextParserPlain = [XTOutputTextParserPlain new];
		_locationTextBuffer = [NSMutableString stringWithString:@""];
		_scoreTextBuffer = [NSMutableString stringWithString:@""];

		// Listen to KVO events from prefs - see observeValueForKeyPath:... below
		XTPrefs *prefs = [XTPrefs prefs];
		[prefs startObservingChangesToAll:self];
		
		_outputTextParserHtml.printBrokenHtmlMarkup = prefs.printBrokenHtmlMarkup.boolValue;
		
		_htmlMode = NO;
		_useAlignRightMode = YES;
		_alignRightMode = NO;
	}
    return self;
}

- (void)dealloc
{
	XTPrefs *prefs = [XTPrefs prefs];
	[prefs stopObservingChangesToAll:self];
}

- (void)resetToDefaults
{
	[self clearStatusLine];
	self.htmlMode = NO;
}

- (void) clearStatusLine
{
	XT_TRACE_ENTRY;
	
	[self.locationTextBuffer setString:@""];
	self.locationTextField.stringValue = @"";
	[self.scoreTextBuffer setString:@""];
	self.scoreTextField.stringValue = @"";
	[[self getOutputTextParser] resetForNextCommand];
	self.alignRightMode = NO;
}


- (void)enterStatusLineMode
{
	XT_TRACE_ENTRY;

	[[self getOutputTextParser] resetForNextCommand];
	
	[self.locationTextBuffer setString:@""];
}

- (void)exitStatusLineMode
{
	XT_TRACE_ENTRY;

	NSArray *parseResultArray = [[self getOutputTextParser] flush];
	[self processParsedOutputText:parseResultArray forBuffer:self.locationTextBuffer append:YES];

	if (! [[self.locationTextField stringValue] isEqualToString:[self locationTextBuffer]]) {
		[self.locationTextField setStringValue:[self locationTextBuffer]];
	}

	self.alignRightMode = NO;
}

//TODO rename ...forLocation
- (void)append:(NSString *)string
{
	XT_DEF_SELNAME;
	XT_TRACE_1(@"\"%@\"", string);

	NSArray *parseResultArray = [[self getOutputTextParser] parse:string];
	[self processParsedOutputText:parseResultArray forBuffer:self.locationTextBuffer append:YES];
}

- (void)showScore:(NSString *)scoreString
{
	XT_DEF_SELNAME;
	XT_TRACE_1(@"\"%@\"", scoreString);

	[[self getOutputTextParser] resetForNextCommand];
	
	NSArray *parseResultArray1 = [[self getOutputTextParser] parse:scoreString];
	NSArray *parseResultArray2 = [[self getOutputTextParser] flush];
	NSMutableArray *parseResultArray = [NSMutableArray arrayWithArray:parseResultArray1];
	[parseResultArray addObjectsFromArray:parseResultArray2];

	[self processParsedOutputText:parseResultArray forBuffer:self.scoreTextBuffer append:NO];
	
	if (! [[self.scoreTextField stringValue] isEqualToString:self.scoreTextBuffer]) {
		[self.scoreTextField setStringValue:self.scoreTextBuffer];
	}
}

- (void)processParsedOutputText:(NSArray *)parseResultArray forBuffer:(NSMutableString *)buffer append:(BOOL)append
{
	XT_DEF_SELNAME;
	//XT_TRACE_1(@"\"%lu\" elements", parseResultArray.count);
	
	if (parseResultArray.count >= 1 && ! append) {
		[buffer setString:@""];
	}
	
	for (id parseResult in parseResultArray) {
		
		NSString *newText = nil;
		
		if ([parseResult isKindOfClass:[NSString class]]) {
			
			newText = parseResult;
			
		} else if ([parseResult isKindOfClass:[XTHtmlTag class]]) {
			
			//TODO exp: this is a experimental, hacky solution for a common usage pattern:
			if (self.useAlignRightMode && [parseResult isKindOfClass:[XTHtmlTagTab class]]) {
				self.alignRightMode = NO;
				XTHtmlTagTab *tagTab = parseResult;
				if (! tagTab.closing) {
					if ([tagTab hasAttribute:@"align" withCaseInsensitiveValue:@"right"]) {
						self.alignRightMode = YES;
					}
				}
			}
			
		} else if ([parseResult isKindOfClass:[XTHtmlWhitespace class]]) {
			
			XTHtmlWhitespace *whitespace = (XTHtmlWhitespace *)parseResult;
			NSUInteger textLen = whitespace.text.length;
			if (whitespace.text == nil || textLen == 1) {
				// Common enough to optimize
				newText = oneSpace;
			} else {
				NSMutableString *tempText = [NSMutableString new];
				for (NSUInteger i = 0; i < textLen; i++) {
					[tempText appendString:oneSpace]; // any ws char becomes 1 space
				}
				newText = tempText;
			}
			
		} else if ([parseResult isKindOfClass:[XTHtmlNonbreakingSpace class]]) {
			
			newText = oneSpace;
			
		} else {
			
			NSString *className;
			if (parseResult == nil) {
				className = @"nil";
			} else {
				className = NSStringFromClass([parseResult class]);
			}
			XT_ERROR_1(@"parse result element of unknown class \"%@\"", className);
		}

		if (newText != nil) {
			if (self.useAlignRightMode && self.alignRightMode) {
				[self.scoreTextBuffer appendString:newText];
			} else {
				[buffer appendString:newText];
			}
		}
	}
}

- (id<XTOutputTextParserProtocol>)getOutputTextParser
{
	id<XTOutputTextParserProtocol> res = (self.htmlMode ? self.outputTextParserHtml : self.outputTextParserPlain);
	return res;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
					  ofObject:(id)object
						change:(NSDictionary *)change
					   context:(void *)context
{
	XT_DEF_SELNAME;
	XT_TRACE_1(@"keyPath=\"%@\"", keyPath);
	
	XTPrefs *prefs = [XTPrefs prefs];
	self.outputTextParserHtml.printBrokenHtmlMarkup = prefs.printBrokenHtmlMarkup.boolValue;
}

@end
