#!/usr/bin/env raku
use v6.d;

use JavaScript::D3;

my %*SUB-MAIN-OPTS = :named-anywhere;

my %nameToFunc =
        'bar-chart' => &js-d3-bar-chart,
        'bubble-chart' => &js-d3-bubble-chart,
        'date-list-plot' => &js-d3-date-list-plot,
        'density2d-chart' => &js-d3-density2d-chart,
        'histogram' => &js-d3-histogram,
        'list-line-plot' => &js-d3-list-line-plot,
        'list-plot' => &js-d3-list-plot,
        'random-koch-curve' => &js-d3-random-koch-curve,
        'random-mandala' => &js-d3-random-mandala,
        'random-mondrian' => &js-d3-random-mondrian,
        'random-scribble' => &js-d3-random-scribble,
        'heatmap' => &js-d3-heatmap-plot,
        'heatmap-plot' => &js-d3-heatmap-plot,
        'matrix-plot' => &js-d3-matrix-plot,
        'chessboard' => &js-d3-chessboard,
        'spirograph' => &js-d3-spirograph;

#| Generates HTML document code with D3.js plots or charts.
multi sub MAIN(Str $cmd, #= Graphics command.
               *@points is copy, #= Data points.
               UInt :w(:$width) = 800, #= Width of the plot. (0 for Whatever.)
               UInt :h(:$height) = 600, #= Height of the plot. (0 for Whatever.)
               Str :t(:$title) = '', #= Title of the plot.
               Str :$x-label = '', #= Label of the X-axis. If Whatever, then no label is placed.
               Str :$y-label = '', #= Label of the Y-axis. If Whatever, then no label is placed.
               Str :$background = 'white', #= Image background color
               Str :$color = 'steelblue', #= Color.
               Bool :$grid-lines = False, #= Should grid lines be drawn or not?
               UInt :$margins = 40, #= Size of the top, bottom, left, and right margins.
               Str :$format = 'html', #= Output format, one of 'jupyter' or 'html'.
               ) {

    die "The first argument is expected to be one of { %nameToFunc.keys }"
    unless %nameToFunc{$cmd}:exists;

    my &func = %nameToFunc{$cmd};

    my %args = :$width, :$height,
               :$title,
               :$x-label, :$y-label,
               :$background,
               :$color,
               :$grid-lines,
               :$margins,
               :$format;

    my $res = do given $cmd {
        when 'random-mondrian' { &func(|%args); }
        when 'random-koch-curve' { &func(@points.head, |%args); }
        when 'spirograph' {
            my $k = @points[0] // 3/4;
            my $l = @points[1] // 5/9;
            &func(:$k, :$l, |%args); }
        default { &func(@points, |%args); }
    }

    say $res.subst('<body>', "<body style=\"background-color:$background;\">");
}

#| Generates HTML document code with D3.js plots or charts by splitting a string of data points.
multi sub MAIN(Str $cmd, #= Graphics command.
               Str $words, #= String with data points.
               UInt :w(:$width) is copy = 800, #= Width of the plot. (0 for Whatever.)
               UInt :h(:$height) is copy = 600, #= Height of the plot. (0 for Whatever.)
               Str :t(:$title) = '', #= Title of the plot.
               Str :$x-label = '', #= Label of the X-axis. If Whatever, then no label is placed.
               Str :$y-label = '', #= Label of the Y-axis. If Whatever, then no label is placed.
               Str :$background = 'white', #= Image background color
               Str :$color = 'steelblue', #= Color.
               Bool :$grid-lines = False, #= Should grid lines be drawn or not?
               Str :$format = 'html', #= Output format, one of 'jupyter' or 'html'.
               ) {

    # It is better to extend the signature of js-d3-chessboard to handle lists of strings.
    # (Not just single string argument.)
    if $cmd ∈ <chessboard> {
        say
                js-d3-chessboard($words,
                        width => ($width ?? $width !! Whatever),
                        height => ($height ?? $height !! Whatever),
                        :$title,
                        :$background,
                        :$format);
        return;
    }

    my @data;
    if $words.contains(',') {
        @data = $words.split(/\s/)>>.split(/','/)>>.Numeric;
    } else {
        @data = $words.split(/\D/)>>.Numeric;
    }

    MAIN($cmd,
            @data,
            :$width, :$height,
            :$title,
            :$x-label, :$y-label,
            :$background,
            :$color,
            :$grid-lines,
            :$format);
}

#| Generates HTML document code with D3.js plots or charts from pipeline input.
multi sub MAIN(
        Str $cmd, #= Graphics command.
        UInt :w(:$width) = 800, #= Width of the plot. (0 for Whatever.)
        UInt :h(:$height) = 600, #= Height of the plot. (0 for Whatever.)
        Str :t(:$title) = '', #= Title of the plot.
        Str :$x-label = '', #= Label of the X-axis. If Whatever, then no label is placed.
        Str :$y-label = '', #= Label of the Y-axis. If Whatever, then no label is placed.
        Str :$background = 'white', #= Image background color
        Str :$color = 'steelblue', #= Color.
        Bool :$grid-lines = False, #= Should grid lines be drawn or not?
        Str :$format = 'html', #= Output format, one of 'jupyter' or 'html'.
               ) {
    my $words = lines.join(' ');
    MAIN($cmd,
            $words,
            :$width, :$height,
            :$title,
            :$x-label, :$y-label,
            :$background,
            :$color,
            :$grid-lines,
            :$format);
}