//
// 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 "XTStringUtils.h"
#import "XTLogger.h"
#import "XTAllocDeallocCounter.h"
@interface XTHtmlLinebreakHandler2 ()
@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"
];
}
OVERRIDE_ALLOC_FOR_COUNTER
OVERRIDE_DEALLOC_FOR_COUNTER
- (id)init
{
self = [super init];
if (self) {
_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
}
return self;
}
- (void)resetForNextCommand
{
_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
}
- (NSString *)handleTagBr:(NSInteger)height
{
[logger trace:@"handleTagBr (state %ld): %ld", self.state, height];
if (height < 0) {
//
==
height = 1;
}
NSUInteger numberOfNewlines;
XTHtmlLinebreakHandler2State oldState = self.state;
switch (self.state) {
case XT_LINEBREAKHANDLER2_AT_START_OF_LINE:
// fall through
case XT_LINEBREAKHANDLER2_AT_START_OF_TABLE_CELL:
//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;
}
if (oldState == XT_LINEBREAKHANDLER2_AT_START_OF_TABLE_CELL && numberOfNewlines == 0) {
_state = oldState;
} else {
_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
}
return [self stringOfNewlines:numberOfNewlines];
}
- (void)handleTagPOpen
{
if (_state == XT_LINEBREAKHANDLER2_AT_START_OF_TABLE_CELL) {
_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
}
}
- (NSString *)handleTagPClose
{
return nil;
}
- (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;
case XT_LINEBREAKHANDLER2_AT_START_OF_TABLE_CELL:
_state = XT_LINEBREAKHANDLER2_AFTER_TAB_START_OF_LINE;
//TODO !!! exp. need new state?
break;
default:
[logger error:@"handleTagTab unexpected state %d", self.state];
//TODO handle error
break;
}
//TODO rm return type? no - defer space for tabs... see gold.gam initial loc
return @"";
}
- (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 {
BOOL endsWithNewlineZwsp = [text hasSuffix:@"\n" ZERO_WIDTH_SPACE];
if (! endsWithNewlineZwsp) {
_state = XT_LINEBREAKHANDLER2_IN_TEXT;
} else {
int brkpt = 1;
}
}
}
}
//TODO missing from diagram
//TODO better name
//TODO distinguish between open and close?
- (NSString *)handleBlockLevelNewline:(XTHtmlTag *)tag
{
NSString *res = nil;
if ([tag isBlockLevel]) {
if (_state == XT_LINEBREAKHANDLER2_IN_TEXT) {
res = @"\n";
}
if (_state != XT_LINEBREAKHANDLER2_AT_START_OF_TABLE_CELL) {
_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
}
} else {
//TODO log error
}
return res;
}
//TODO missing from diagram
- (void)handleTableClose
{
// A starts a new "line"
_state = XT_LINEBREAKHANDLER2_AT_START_OF_LINE;
}
//TODO missing from diagram
- (void)handleTdOpen
{
// A table cell