#!/usr/bin/perl
use strict;
use warnings;

use Graph;
use GD::Arrow;
use GD::Graph::Polar;
use Math::Trig;

# Data model for the graph.
my $graph_data = [
    [1],    # 0 talks to 1.
    [0,2],  # 1 talks to 0 and 2 - a mediator.
    [1],    # 2 talks to 1.
    [],     # 3 doesn't talk, even to itself.
    [4],    # 4 talks to itself.
            # And nobody talks to 3 or 4.
    [6,7],  # 5 talks to all friends.
    [5,7],  # 6 talks to all friends. 
    [5,6],  # 7 talks to all friends. 
];

# Graph object!
my $graph = Graph->new;

# Populate the graph.
my $vertex = 0; # Initial vertex id.
for my $row (@$graph_data) {
    my $weight = 0; # Initial vertex weight

    # Make edges.
    for my $neighbor (@$row) {
        $graph->add_edge($vertex, $neighbor);
        $weight++; # Tally the vertex weight.
    }

    # Set the vertex weight.
    $graph->set_vertex_weight($vertex, $weight);

    # Move on to the next vertex...
    $vertex++;
}

# Plot bounds.
my $size = 450;
my $radius = 2; # TODO This should be max weight.
my $ring = 0.5; # 2 ticks for every weight.

# Chart object!
my $chart = GD::Graph::Polar->new(
    rgbfile => '/usr/X11/share/X11/rgb.txt',
    size => $size,
    radius => $radius + 1,
    ticks => ($radius + 1) * 2,
);
# Add axis labels
$chart->addString($radius + 1, $_, $_) for 0, 90, 180, 270;

# Data model for the chart given as [r, t, c].
my $chart_data = []; # TODO Make this graph attributes.
for my $vertex ($graph->vertices) {
    my $weight = $graph->get_vertex_attribute($vertex, 'weight');
    my $theta = theta(); # TODO Compute based on neighbors.

    my $color = 'blue';
    my $label = sprintf '%d:%d,%s', $vertex, $weight, $theta;

    $chart_data->[$vertex] = [
        $weight, $theta,
        $color, $label
    ];
}

# Populate the chart.
for (@$chart_data) { # TODO Do this by vertices.
    my ($r, $t, $c, $l) = @$_;

    # Reverse and pad heaviest and lightest with a ring.
    $r = $radius - $r + $ring;

    # Point
    $chart->color($c);
    $chart->addPoint($r => $t);

    # Label
    $chart->color('black');
    $chart->addString($r => $t, $l);

    # TODO Plot an arrow from vertex to its neighbors.
    my ($x0, $y0) = p2r($r, $t);
    my $arrow = GD::Arrow::Full->new(
        -X1    => 10,
        -Y1    => 10,
        -X2    => $size / 2,
        -Y2    => $size / 2,
        -WIDTH => 5,
    );
#warn"$arrow on $chart->{object} at $r, $t => $x0, $y0\n";
    $chart->{object}->filledPolygon($arrow, $chart->color('black'));
}

# Make a visualization file.
my $file = "$0.png";
open my $fh, ">$file" or die "Can't write to $file";
binmode $fh, ':raw';
print $fh $chart->draw;
close $fh;

sub theta {
    return int(rand 359);
}

sub p2r {
    my($r, $t) = @_;
    return $r * cos(deg2rad($t)), $r * sin(deg2rad($t));
}

__END__

=head1 TO DO

# Choose random colors with
use Color::Rgb; @colors = $rgb->names;

* Vertex weight => Clustering, Color

* Cluster rendering: Heaviest with most neighbors = 0 relative degrees, on same
shell, to other heavies on either side (modulo "bunching" factor).

* Orbiting though time animation
