# Copyright 2015 Kevin Ryde
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
#
# This file 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.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this file.  See the file COPYING.  If not, see
# <http://www.gnu.org/licenses/>.

package Graph::Maker::Johnson;
use 5.004;
use strict;
use base 'Graph::Maker';

use vars '$VERSION';
$VERSION = 5;

# uncomment this to run the ### lines
# use Smart::Comments;

sub _default_graph_maker {
  require Graph;
  Graph->new(@_);
}

sub init {
  my ($self, %params) = @_;

  my $N = delete($params{'N'}) || 0;
  my $K = delete($params{'K'}) || 0;
  ### $N
  ### $K

  my $graph_maker = delete($params{'graph_maker'});
  $graph_maker ||= \&_default_graph_maker;
  my $graph = $graph_maker->(%params);

  $graph->set_graph_attribute (name => "Johnson Graph $N,$K");
  my $directed = $graph->is_directed;

  my @vertices;
  my @upto = (0);
  my $pos = 0;
  for (;;) {
    ### @upto
    ### $pos
    if (++$upto[$pos] > $N) {
      if (--$pos < 0) {
        last;
      }
    } else {
      if (++$pos >= $K) {
        ### push: "@upto"
        push @vertices, [@upto];
        $pos--;

        # foreach my $o (0 .. $#upto) {
        #   my $out = $upto[$o];
        #   my $in = 1;
        #   my $i = 0;
        #   if ($
        #   foreach my $j ($
        # }
      } else {
        $upto[$pos] = $upto[$pos-1];
      }
    }
  }
  foreach my $v (@vertices) {
    $graph->add_vertex(join(',',@$v));
  }
  foreach my $from (@vertices) {
    foreach my $to (@vertices) {
      ### consider: "from=".join(',',@$from)." to=".join(',',@$to)
      my $i = 0;
      my $j = 0;
      my $count = 0;
      while ($i <= $#$from && $j <= $#$to) {
        if ($from->[$i] == $to->[$j]) {
          $count++;
          $i++;
          $j++;
        } elsif ($from->[$i] < $to->[$j]) {
          $i++;
        } else {
          $j++;
        }
      }
      ### $count
      if ($count == $K - 1) {
        my $v_from = join(',',@$from);
        my $v_to   = join(',',@$to);
        ### edge: "$v_from to $v_to"
        $graph->add_edge($v_from, $v_to);
        if ($directed) { $graph->add_edge($to, $from); }
      }
    }
  }
  return $graph;
}

Graph::Maker->add_factory_type('johnson' => __PACKAGE__);
1;

__END__

=for stopwords Ryde

=head1 NAME

Graph::Maker::Johnson - create Johnson graph

=for test_synopsis my ($graph)

=head1 SYNOPSIS

 use Graph::Maker::Johnson;
 $graph = Graph::Maker->new ('johnson', N => 8, K => 3);

=head1 DESCRIPTION

C<Graph::Maker::Johnson> creates C<Graph.pm> graphs of Johnson graphs.
Each vertex is a K-many item subsets of the integers 1 to N.  Edges are
between vertices which have just one integer different.

=head1 FUNCTIONS

=over

=item C<$graph = Graph::Maker-E<gt>new('johnson', key =E<gt> value, ...)>

The key/value parameters are

    N   =>  integer
    K   =>  integer

Other parameters are passed to C<Graph-E<gt>new()>.

=back

=head1 SEE ALSO

L<Graph::Maker>, L<Graph::Maker::BalancedTree>

=head1 LICENSE

Copyright 2015 Kevin Ryde

This file is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any later
version.

This file 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.  See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
This file.  If not, see L<http://www.gnu.org/licenses/>.

=cut
