#!perl
#
# foodratio - calculate ingredient ratios

use 5.26.0;
use warnings;
use Food::Ratio;
use Getopt::Long 'GetOptions';

my ( $mass, @ratio_args, @weigh_args );
GetOptions(
    'mass=f' => sub {
        die "foodratio: mass must be a positive number\n" unless $_[1] > 0;
        $mass = $_[1];
    },
    'ratio=s' => sub {
        my ( $key, $value ) = split ':', $_[1], 2;
        die "foodratio: ratio key must be 'id' or 'group'\n"
          unless $key eq 'id' or $key eq 'group';
        @ratio_args = ( $key, $value );
    },
    'weigh=s' => sub {
        my ( $key, $value ) = split ':', $_[1], 2;
        die "foodratio: weigh key must be 'id' or 'group'\n"
          unless $key eq 'id' or $key eq 'group';
        @weigh_args = ( $key, $value );
    },
) or exit 64;

my $fr = Food::Ratio->new;

while ( my $line = readline ) {
    last if $line =~ m/^-/;    # so we can `foodratio | foodratio`
    chomp $line;
    my ( $mass, $name, @rest ) = split ' ', $line;
    # probably the 2nd column is ratios, assume name is in next column
    $name = shift @rest if $name =~ m/[%]/;
    $fr->add( $mass, $name, @rest );
}
$fr->ratio(@ratio_args);

$fr->weigh( $mass, @weigh_args ) if defined $mass;

print $fr->string;

__END__

=head1 NAME

foodratio - calculate ingredient ratios

=head1 SYNOPSIS

  $ cat recipe
  1 egg   wet
  2 water wet
  4 flour dry
  $ foodratio recipe
  $ foodratio --ratio id:flour recipe
  $ foodratio --mass 55 --weigh group:wet recipe

=head1 DESCRIPTION

Given a list of measurements of ingredients, foodratio will calculate
the ratio between those various inputs, optionally using some ingredient
(or group of ingredients) as the ratio key. The weights can be
recalculated based on the measurement of a particular ingredient.

The input should be in columns, with the mass (or whatever measurement)
as the first column. This must be a strictly positive number. If the
second column contains C<%> it will be ignored, on the presumption that
that is a ratio. Thus the name (id) of the ingredient will come from
either the second or third column. The remainder of the columns, if
any, will be treated as group names that collect ingredients into
groups, e.g. a custom C<flour> group for recipes with different types
of flour, or so forth.

Lines beginning with C<-> are ignored; this allows C<foodratio> output
to be piped to C<foodratio>.

=head2 Options

=over 4

=item B<mass> I<positive-number>

Sets the mass for the B<weigh> method; ingredient measurements will be
recalculated based on this amount.

=item B<ratio> I<key:value>

Sets the ingredient or ingredient group to use as the key value for
the ratio calculation, e.g. flour in a bread recipe and not the
default total mass. I<key> must be C<id> or C<group>.

By default the ratio is taken from the total of the ingredients.

=item B<weigh> I<key:value>

Sets the ingredient or ingredient group to use as the basis for the
B<mass> argument.

By default the weight is taken from the total of the ingredients.

=back

=head1 EXAMPLES

Given a file containing

  160 cornmeal flour dry
  150 flour flour dry
  11 bpowder dry
  3.5 salt dry
  30 sugar dry
  250 milk wet
  70 oil fat wet
  58 egg wet

one may weigh an egg and discover that it is 55 grams, and rescale the
recipe based on that

  $ foodratio cornbread    | grep cornmeal
  160     21.84%  cornmeal        flour   dry
  $ foodratio --mass 55 --weigh id:egg cornbread  | grep cornmeal
  151.7   21.84%  cornmeal        flour   dry

and know to use 152 grams of cornmeal instead of 160. To preserve the
ratios (e.g. based on the flour, as is typical in baking) also add the
I<--ratio> option:

  $ foodratio --mass 55 --weigh id:egg --ratio group:flour cornbread
  ...

=head1 SEE ALSO

L<Food::Ratio>

=head1 COPYRIGHT AND LICENSE

Copyright 2022 Jeremy Mates

This program is distributed under the (Revised) BSD License:
L<https://opensource.org/licenses/BSD-3-Clause>

=cut