package Ledger::Posting;
BEGIN {
  $Ledger::Posting::VERSION = '0.01';
}

use 5.010;
use Log::Any '$log';
use Moo;

# VERSION

my $reset_line = sub { $_[0]->line(undef) };

has account => (is => 'rw', trigger => $reset_line);
has amount => (is => 'rw', trigger => $reset_line); # [scalar, unit]
has is_virtual => (is => 'rw', trigger => $reset_line);
has virtual_must_balance => (is => 'rw', trigger => $reset_line);
has tx => (is => 'rw');
has line => (is => 'rw');

our $re_scalar    = qr/(?:[+-]?[\d,]+(?:.\d+)?)/x;
our $re_cmdity    = qr/(?:\$|[A-Za-z_]+)/x;
our $re_amount    = qr/(?:
                           (?:(?<cmdity>$re_cmdity)\s*(?<scalar>$re_scalar))|
                           (?:(?<scalar>$re_scalar)\s*(?<cmdity>$re_cmdity))|
                           (?:(?<scalar>$re_scalar))
                       )/x;

sub BUILD {
    my ($self, $args) = @_;
    my $amt = $self->amount;
    if (defined($amt) && !ref($amt)) {
        $self->amount( $self->_parse_amount($self->amount) );
    }
    # re-set here because of trigger
    if (!defined($self->line)) {
        $self->line($args->{line});
    }
}

sub _parse_amount {
    my ($self, $amt) = @_;
    $amt =~ $re_amount or die "Invalid amount syntax: $amt";
    my $scalar = $+{scalar};
    my $cmdity = $+{cmdity} // "";
    $scalar =~ s/,//g;
    [$scalar+0, $cmdity];
}

sub format_amount {
    my ($self, $amt) = @_;
    $amt //= $self->amount;
    $amt->[0] . (length($amt->[1]) ? " $amt->[1]" : "");
}

sub as_string {
    my ($self) = @_;
    if (defined $self->line) {
        $self->tx->journal->raw_lines->[ $self->line ];
    } else {
        my ($o, $c);
        if ($self->is_virtual) {
            if ($self->virtual_must_balance) {
                ($o, $c) = ("[", "]");
            } else {
                ($o, $c) = ("(", ")");
            }
        } else {
            ($o, $c) = ("", "");
        }

        " $o".$self->account.$c.
            ($self->amount ? "  ".$self->format_amount() : "").
                "\n";
    }
}

sub seq {
    # XXX
}

1;
# ABSTRACT: Represent a Ledger posting in a transaction


=pod

=head1 NAME

Ledger::Posting - Represent a Ledger posting in a transaction

=head1 VERSION

version 0.01

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 ATTRIBUTES

=head2 account => STR

=head2 amount => NUM

=head2 commodity => STR

=head2 tx => OBJECT

Pointer to transaction object.

=head2 line => INT

=head1 METHODS

=for Pod::Coverage BUILD

=head2 new(...)

=head2 $p->seq()

Sequence of this posting in the transaction (1 for first, 2 for second, and so
on).

=head2 $p->as_string()

=head1 AUTHOR

Steven Haryanto <stevenharyanto@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Steven Haryanto.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut


__END__