package Lib;
use strict; use warnings;

use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
use Data::Alias;

use Exporter;
use base 'Exporter';
our @EXPORT = qw(qt lines joinlines tsv D order hash2json say pairs $a $b equal for1 for2 Last may_deref set set_add set_get set_del set_key is_int);

our $Last;

sub qt {
	my ($txt) = @_;
	for ($txt) { s/^\n//; s/[ \t]*$//; }
	my ($indent) = $txt =~ /^(\s*)/;
	$txt =~ s/^$indent//gm;
	return $txt;
}

sub tsv {
	return [map { splittabs($_) } @{lines($_[0])}];
}

sub splittabs {
	return [split /\t/, $_[0]];
}

sub lines {
	return [split /\n/, $_[0]];
}

sub joinlines {
	return join "", map "$_\n", @{$_[0]};
}

sub D ($) {
	return Dumper(@_);
}

sub say {
	print "@_\n";
}

sub test {
	my $x = qt qq{
		Hello world.
		This is nice.
	};
	$x eq "Hello world.\nThis is nice.\n"
	  or die "qt failed:\n$x.";

	my $rows = tsv(<<End);
animal	legs
dog	4
man	2
cat	4
snail	0
ant	6
spider	8
octopus	8
End
	@$rows == 8 && "@{$rows->[3]}" eq "cat 4"
	  or die "tsv failed:\n", D($rows);
}

sub order {
	my ($fields) = @_;
	my $i = 0;
	return {map {$_, $i++} @$fields};
}

sub hash2json {
	my ($hash) = @_;
	my $str = join ",", map {"$_:$hash->{$_}"} sort keys %$hash;
	return $str;
}


sub pairs (&@) {
	my ($sub) = shift;
	local $Last = 0;
	$_ = 0;
	while (alias { ($a, $b) = splice @_, 0, 2 }) {
		$sub->($a, $b, $_);
		last if $Last;
		++$_;
	}
}

sub equal {
	my ($a, $b) = @_;
	if (defined $a && defined $b) {
		return $a eq $b;
	}
	return (!defined $a && !defined $b);
}

sub for1 (&@) {
	my ($sub) = shift;
	local $Last = 0;
	for (0..$#_) {
		$a = $_[$_];
		$sub->($a, $_);
		last if $Last;
	}
}

sub for2 (&\@\@) {
	my ($sub, $as, $bs) = @_;
	local $Last = 0;
	for (0..$#$as) {
		$a = $as->[$_];
		$b = $bs->[$_];
		$sub->($a, $b, $_);
		last if $Last;
	}
}

sub Last {
	$Last = 1;
}

sub may_deref {
	my ($x) = @_;
	if (wantarray) {
		if (ref $x eq "ARRAY") {
			return @$x;
		} else {
			# TODO fix, this might fail
			return %$x;
		}
	} else {
		return $x;
	}
}

sub set {
	my %set = map {set_key($_) => $_} @_;
	return may_deref(\%set);
}

sub set_add {
	my ($set, $a) = @_;
	$set->{set_key($a)} = $a;
}

sub set_get {
	my ($set, $a) = @_;
	return $set->{set_get($a)};
}

sub set_del {
	my ($set, $a) = @_;
	delete $set->{set_key($a)};
}

sub set_key {
	my ($a) = @_;
	return ref $a ? 0+$a : $a;
}

sub is_int {
	# TODO this is a bit bogus
	my ($x) = @_;
	return abs($x - int $x) < 1e-9;
}

#	my $pkg = caller;
#	no strict 'refs';
#	while ((${"${pkg}::a"}, ${"${pkg}::b"}) = splice @_, 0, 2) {

1
