#!/usr/bin/env perl

use strict;
use warnings;
use Math::DifferenceSet::Planar 1.000;

use constant PDS => Math::DifferenceSet::Planar::;

$| = 1;

my $USAGE = "usage: pds_planes [-l|-L|-g|-z|-Z] [-D database] (p n|order|-)\n";

my $type = 1;
my $prin = 0;
my $db   = undef;
my $read = 0;
while (@ARGV && $ARGV[0] =~ /^-(.+)/s) {
    my $opt = $1;
    shift @ARGV;
    last                       if '-' eq $opt;
    $type = 1, $prin = 0, next if 'l' eq $opt;
    $type = 2, $prin = 0, next if 'g' eq $opt;
    $type = 0, $prin = 0, next if 'z' eq $opt;
    $type = 1, $prin = 1, next if 'L' eq $opt;
    $type = 0, $prin = 1, next if 'Z' eq $opt;
    $db   = shift(@ARGV), next if 'D' eq $opt && @ARGV;
    $db   = $1,           next if $opt =~ /^D(.+)s/;
    die $USAGE;
}
if (@ARGV == 1 && $ARGV[0] eq '-') {
    $read = 1;
}
elsif (@ARGV < 1 || 2 < @ARGV  || grep {!/^[1-9][0-9]*\z/} @ARGV) {
    die $USAGE;
}

Math::DifferenceSet::Planar->set_database($db) if defined $db;

if ($read) {
    while (<STDIN>) {
        s/^\s+//;
        my @e = split /\s+/;

        die "integer numbers separated by whitespace expected\n"
            if !@e || grep { !/^(?:0|[1-9][0-9]*)\z/ } @e;

        my $s0 = Math::DifferenceSet::Planar->from_elements(@e);
        process($s0);
    }
}
else {
    my $s0 = PDS->new(@ARGV);
    process($s0);
}

sub process {
    my ($s0) = @_;

    my $it =
        $prin?
            ($type?
                $s0->iterate_principal_planes:
                $s0->iterate_principal_planes_zc
            ):
            ($type? $s0->iterate_planes: $s0->iterate_planes_zc);
    while (my $s = $it->()) {
        my $t = $type == 2? $s->gap_canonize: $s;
        my @e = $t->elements_sorted;
        print "@e\n";
    }
}

__END__

=head1 NAME

pds_planes - enumerate planar difference set planes of a same order

=head1 SYNOPSIS

  pds_planes [-l|-L|-g|-z|-Z] [-D database] p n
  pds_planes [-l|-L|-g|-z|-Z] [-D database] order
  pds_planes [-l|-L|-g|-z|-Z] [-D database] -

=head1 DESCRIPTION

This example program writes planar difference sets of a given order
to standard output.  The order can be specified as a prime number and
an exponent, or as a prime power.  The output will be lines with one
representative difference set per line, for all planes of the given order.

A single dash argument instead of an order makes the tool read planar
difference sets from standard input and generate all planes of their
respective order.

Option C<-l> specifies lex-canonical (i.e. lexically smallest) sets as
plane representatives.  This is the default.

Option C<-L> specifies lex-canonical sets as plane representatives and
limits the output to principal planes.

Option C<-g> specifies gap-canonical (i.e. lexically smallest when large
take priority over small elements) sets as plane representatives.

Option C<-z> specifies zeta-canonical sets as plane representatives.

Option C<-Z> specifies zeta-canonical sets as plane representatives and
limits the output to principal planes.

Parameter C<-D> specifies an alternate sample database.

=head1 BUGS AND LIMITATIONS

If an order is specified, possible orders are limited to those of sample
sets in the database.

If no order is specified and input is not planar difference sets, errors
will likely be reported, but behaviour is undefined.

=head1 AUTHOR

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

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2019-2024 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).

The licence grants freedom for related software development but does
not cover incorporating code or documentation into AI training material.
Please contact the copyright holder if you want to use the library whole
or in part for other purposes than stated in the licence.

=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
