The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
use Test::More;
use Term::ANSIColor qw(:constants colored);
use Data::Dumper;
use utf8;
use Text::CharWidth qw(mbwidth);

BEGIN {
	use_ok 'Text::UnicodeBox::Text', qw(:all);
};

# If LC_ environment variables can't see this string encoded in the proper format (i.e., called in a server context with no controlling terminal),
# then this module can't operate with Unicode or UTF-8 encoded strings.
my $skip_unicode_tests = mbwidth("象") == 2 ? 0 : 1;

my $part = BOX_STRING("Hello world");
isa_ok $part, 'Text::UnicodeBox::Text';
is $part->value, 'Hello world';
is $part->length, length('Hello world');

## align_and_pad

$part->align_and_pad(14);
is $part->value, ' ' . 'Hello world   ' . ' ', "align_and_pad() changes value in place with spaces before and after";

$part = BOX_STRING(45);
$part->align_and_pad(3);
is $part->value, ' '.' 45'.' ', "Numbers are aligned right";

$part = BOX_STRING(72.5);
$part->align_and_pad(5);
is $part->value, ' '.' 72.5'.' ', "Fractional numbers are still numbers";

## Lines

$part = BOX_STRING(
	"This is line one\n".
	"This is line two"
);
my @lines = $part->lines();
is int @lines, 2, "Part split into two lines";
is $part->longest_line_length, 16, "Longest line length";

## Split

$part = BOX_STRING("This is a very long string that needs to be split into multiple parts");

my @segments = $part->split(
	max_width => 20,
	break_words => 1,
);

is_deeply [ map { $_->value } @segments ], [
	'This is a very long ',
	'string that needs to',
	' be split into multi',
	'ple parts',
], "Split max_width => 20, break_words => 1";

## Split with color

$part = BOX_STRING(colored("This is a very long string that needs to be split into multiple parts", 'blue'));

@segments = $part->split(
	max_width => 20,
	break_words => 1,
);

is_deeply [ map { $_->value } @segments ], [
	BLUE . 'This is a very long ' . RESET,
	BLUE . 'string that needs to' . RESET,
	BLUE . ' be split into multi' . RESET,
	BLUE . 'ple parts' . RESET,
], "Split max_width => 20, break_words => 1, all one color";

## More complex styling

$part = BOX_STRING(
	colored("This is a very long ", 'blue') .
	colored("string", 'bold') .
	colored(" that needs to be split into ", 'blue') .
	colored("multiple parts", 'on_blue')
);

@segments = $part->split(
	max_width => 20,
	break_words => 1,
);

is_deeply [ map { $_->value } @segments ], [
	BLUE . 'This is a very long ' . RESET,
	BOLD . 'string' . RESET . BLUE . ' that needs to' . RESET,
	BLUE . ' be split into ' . RESET . ON_BLUE . 'multi' . RESET,
	ON_BLUE . 'ple parts' . RESET,
], "Split max_width => 20, break_words => 1, various colors and styles";

## Split without breaking words

$part = BOX_STRING("This is a very long string that needs to be split into multiple parts");

@segments = $part->split(
	max_width => 20,
);

is_deeply [ map { $_->value } @segments ], [
	'This is a very long ',
	'string that needs to',
	' be split into ',
	'multiple parts',
], "Split max_width => 20, break_words => 0";

## Split without breaking words with color

$part = BOX_STRING(colored("This is a very long string that needs to be split into multiple parts", "blue"));

@segments = $part->split(
	max_width => 20,
);

is_deeply [ map { $_->value } @segments ], [
	BLUE . 'This is a very long ' . RESET,
	BLUE . 'string that needs to' . RESET,
	BLUE . ' be split into ' . RESET,
	BLUE . 'multiple parts' . RESET,
], "Split max_width => 20, break_words => 0, all one color";

## Split unicode text

if (! $skip_unicode_tests) {
	# "I Can Eat Glass" from http://www.columbia.edu/~fdc/utf8/
	my $text = <<ENDTEXT;
Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.
私はガラスを食べられます。それは私を傷つけません。
我能吞下玻璃而不伤身体。
ᛁᚳ᛫ᛗᚨᚷ᛫ᚷᛚᚨᛋ᛫ᛖᚩᛏᚪᚾ᛫ᚩᚾᛞ᛫ᚻᛁᛏ᛫ᚾᛖ᛫ᚻᛖᚪᚱᛗᛁᚪᚧ᛫ᛗᛖ᛬
Я могу есть стекло, оно мне не вредит.
나는 유리를 먹을 수 있어요. 그래도 아프지 않아요
ENDTEXT

	$part = BOX_STRING($text);

	@lines = $part->lines();
	is int @lines, 6, "Got six lines from 'I Can Eat Glass'";

	my @got;
	foreach my $line (@lines) {
		my @segment_values;
		foreach my $segment ($line->split( max_width => 20, break_words => 1 )) {
			push @segment_values, $segment->value;
		}
		push @got, \@segment_values;
	}

	is_deeply
		\@got,
		[
			[
				"Μπορώ να φάω σπασμέν",
				"α γυαλιά χωρίς να πά",
				"θω τίποτα.",
			],
			[
				"私はガラスを食べられ",
				"ます。それは私を傷つ",
				"けません。",
			],
			[
				"我能吞下玻璃而不伤身",
				"体。",
			],
			[
				"ᛁᚳ᛫ᛗᚨᚷ᛫ᚷᛚᚨᛋ᛫ᛖᚩᛏᚪᚾ᛫ᚩᚾ",
				"ᛞ᛫ᚻᛁᛏ᛫ᚾᛖ᛫ᚻᛖᚪᚱᛗᛁᚪᚧ᛫ᛗᛖ",
				"᛬",
			],
			[
				"Я могу есть стекло, ",
				"оно мне не вредит.",
			],
			[
				"나는 유리를 먹을 수 ",
				"있어요. 그래도 아프",
				"지 않아요",
			],
		],
		"Split six lines of 'I Can Eat Glass' at 20 width";
}

done_testing;

sub print_segments {
	my @segments = @_;
	foreach my $segment (@segments) {
		foreach my $char (split //, $segment->value) {
			if (ord($char) == 27) {
				print '^';
			}
			else {
				print $char;
			}
		}
		print "\n";
	}
}