#!/usr/bin/env perl

use 5.022;
use strict;
use warnings;

$| = 1;

my $mod = 0;
while (@ARGV && $ARGV[0] =~ /^-(.+)/s) {
    my $opt = $1;
    shift @ARGV;
    last if $opt eq '-';
    $mod = $1, next if $opt =~ /^m([1-9][0-9]*)\z/;
    $mod = $1, next
        if $opt eq 'm' && @ARGV && shift(@ARGV) =~ /^([1-9][0-9]*)\z/;
    die "usage: pds_optable [-m modulus] [file]...\n";
}

while (<<>>) {
    s/^\s+//;
    my @e = split /\s+/;
    if (!@e || grep { !/^(?:0|[1-9][0-9]*)\z/ } @e) {
        print;
        next;
    }

    my $m = $mod || (@e - 1) * @e + 1;
    my $fmt = $m < 1000? '%4d': '%4x';
    print
        '+--+---', '----' x @e, "-+\n",
        '|  |   ', (map { sprintf $fmt, $_ } @e), " |\n",
        '|  +--+', '----' x @e, "-+\n",
        (map {
            my $a = $_;
            '|', sprintf($fmt, $a), ' |',
            (map { sprintf $fmt, ($a - $_) % $m } @e),
            " |\n"
        } @e),
        '+-----+', '----' x @e, "-+\n";
}

__END__

=head1 NAME

pds_optable - print difference table for planar difference sets

=head1 SYNOPSIS

  pds_optable [-m modulus] [file]...

=head1 DESCRIPTION

This example program reads lists of non-negative integer numbers, one
per line, separated by whitespace, converts them to ASCII-formatted
difference tables, and writes the results to standard output.

The modulus can be specified with an optional B<-m> parameter.
If omitted, it is calculated from the number of elements of each line,
assuming they are planar difference sets.

=head1 AUTHOR

Martin Becker, E<lt>becker-cpan-mp I<at> cozap.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2019-2023 by Martin Becker, Blaubeuren.

This library is free software; you can distribute it and/or modify it
under the terms of the Artistic License 2.0 (see the LICENSE file).

=head1 DISCLAIMER OF WARRANTY

This library is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of merchantability
or fitness for a particular purpose.

=cut
