//
//  XTHtmlLinebreakHandler2.m
//  TadsTerp
//
//  Created by Rune Berg on 11/05/14.
//  Copyright (c) 2014 Rune Berg. All rights reserved.
//

#import "XTHtmlLinebreakHandler2.h"
#import "XTHtmlTagBr.h"
#import "XTHtmlTagP.h"
#import "XTHtmlTagTab.h"
#import "XTLogger.h"


@interface XTHtmlLinebreakHandler2 ()

@property NSUInteger divDepth;
	//TODO hackish - consider proper "tag stack handling"

@end


@implementation XTHtmlLinebreakHandler2

static XTLogger* logger;
static NSArray *newlinesStringsCache;

+ (void)initialize
{
	logger = [XTLogger loggerForClass:[XTHtmlLinebreakHandler2 class]];
	newlinesStringsCache = @[@"", @"\n", @"\n\n", @"\n\n\n", @"\n\n\n\n"];
}

- (id)init
{
    self = [super init];
    if (self) {
		_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
		_divDepth = 0;
    }
    return self;
}

- (void)resetForNextCommand
{
	_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
	_divDepth = 0;
}

- (NSString *)handleTagBr:(NSInteger)height
{

	[logger trace:@"handleTagBr (state %ld): %ld", self.state, height];
	
	if (height < 0) {
		// <br> == <br height=1>
		height = 1;
	}
	
	NSUInteger numberOfNewlines;
	
	switch (self.state) {
		case XT_LINEBREAKHANDLER2_AT_START_OF_LINE:
			//TODO simplify:
			if (height == 0) {
				numberOfNewlines = 0;
			} else if (height == 1) {
				numberOfNewlines = 1;
			} else {
				numberOfNewlines = height;
			}
			break;
		case XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE:
			if (height <= 1) {
				numberOfNewlines = 0;
			} else {
				numberOfNewlines = height + 1;
			}
			break;
		case XT_LINEBREAKHANDLER2_IN_TEXT:
			if (height == 0) {
				numberOfNewlines = 1;
			} else if (height == 1) {
				numberOfNewlines = 1;
			} else {
				numberOfNewlines = height + 1;
			}
			break;
		default:
			[logger error:@"handleTagBr unexpected state %d", self.state];
			//TODO handle error
			break;
	}

	_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;

	return [self stringOfNewlines:numberOfNewlines];
}

//TODO rm if not used
- (NSString *)handleTagP
{
	[logger trace:@"handleTagP (state %ld)", self.state];

	NSUInteger numberOfNewlines;
	switch (self.state) {
		case XT_LINEBREAKHANDLER2_AT_START_OF_LINE:
			numberOfNewlines = 1;
			break;
		case XT_LINEBREAKHANDLER2_IN_TEXT:
			numberOfNewlines = 2;
			break;
		case XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE:
			numberOfNewlines = 1;
			break;
		default:
			numberOfNewlines = 1;
			[logger error:@"handleTagP unexpected state %d", self.state];
			//TODO handle error
	}
	
	_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
	return [self stringOfNewlines:numberOfNewlines];
}

/*TODO rm
- (NSString *)handleStartDiv
{
	//TODO update diagram

	[logger trace:@"handleStartDiv (state %ld)", self.state];
	
	NSUInteger numberOfNewlines;
	switch (self.state) {
		case XT_LINEBREAKHANDLER2_AT_START_OF_LINE:
			numberOfNewlines = 0;
			break;
		case XT_LINEBREAKHANDLER2_IN_TEXT:
			numberOfNewlines = 1;
			break;
		case XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE:
			numberOfNewlines = 0;
			break;
		default:
			numberOfNewlines = 1;
			[logger error:@"handleStartDiv unexpected state %d", self.state];
			//TODO handle error
	}
	
	self.divDepth += 1;
	_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
	return [self stringOfNewlines:numberOfNewlines];
}

- (NSString *)handleEndDiv;
{
	//TODO update diagram
	
	[logger trace:@"handleEndDiv (state %ld)", self.state];
	
	NSUInteger numberOfNewlines;
	switch (self.state) {
		case XT_LINEBREAKHANDLER2_AT_START_OF_LINE:
			numberOfNewlines = 0;
			break;
		case XT_LINEBREAKHANDLER2_IN_TEXT:
			numberOfNewlines = 1;
			break;
		case XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE:
			numberOfNewlines = 0;
			break;
		default:
			numberOfNewlines = 1;
			[logger error:@"handleEndDiv unexpected state %d", self.state];
			//TODO handle error
	}

	if (self.divDepth >= 1) {
		self.divDepth -= 1;
		_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
	} else {
		numberOfNewlines = 0;
	}
	
	return [self stringOfNewlines:numberOfNewlines];
}*/

- (NSString *)handleTagTab
{
	switch (self.state) {
		case XT_LINEBREAKHANDLER2_AT_START_OF_LINE:
			_state = XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE;
			break;
		case XT_LINEBREAKHANDLER2_IN_TEXT:
			// stay in current state
			break;
		case XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE:
			// stay in current state
			break;
		default:
			[logger error:@"handleTagTab unexpected state %d", self.state];
			//TODO handle error
	}
	//TODO rm return type? no - defer space for tabs... see gold.gam initial loc
	return @"";
}

//TODO unit test
- (NSString *)handleEndLi
{
	_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
	return @"\n";
}

- (void)handleText:(NSString *)text
{
	if (text != nil && text.length >= 1) {
		BOOL endsWithNewline = [text hasSuffix:@"\n"];
		if (endsWithNewline) {
			_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
		} else {
			_state = XT_LINEBREAKHANDLER2_IN_TEXT;
		}
	}
}

//TODO missing from diagram
//TODO better name
//TODO distinguish between open and close?
- (NSString *)handleBlockLevelNewline:(XTHtmlTag *)tag
{
	NSString *res = nil;
	
	if ([tag isBlockLevel]) {
		if (self.state == XT_LINEBREAKHANDLER2_IN_TEXT) {
			res = @"\n";
		}
		_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
	} else {
		//TODO log error
	}
	
	return res;
}


//-------------------------------

- (NSString *)stringOfNewlines:(NSUInteger)numberOfNewlines
{
	NSString *res;
	if (numberOfNewlines < newlinesStringsCache.count) {
		res = newlinesStringsCache[numberOfNewlines];
	} else {
		NSMutableString *tempRes = [NSMutableString string];
		while (numberOfNewlines-- > 0) {
			[tempRes appendString:@"\n"];
		}
		res = tempRes;
	}
	return res;
}

@end
