package App::Tarotplane;
our $VERSION = '2.02';
use 5.016;
use strict;
use warnings;

require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(%CARD_SORT);

use Getopt::Long;

use App::Tarotplane::Cards;
use App::Tarotplane::UI;

my $PRGNAM = 'tarotplane';
my $PRGVER = $VERSION;

my $HELP_MSG = <<END;
$PRGNAM - $PRGVER
Usage: $0 [options] file ...

Options:
 -o [<by>] --order=[<by>] Order cards alphabetically by terms or definitions
 -r        --random       Randomize order cards appear in
 -t        --terms-first  Show terms first rather than definitions
 -h        --help         Print help message and exit
 -v        --version      Print version and copyright info, then exit
END

my $VER_MSG = <<END;
$PRGNAM - $PRGVER

Copyright 2024-2026, Samuel Young

This program is free software; you may redistribute it and/or
modify it under the same terms as Perl itself.
END

my $TTY_PATH = $^O eq 'MSWin32' ? 'CONIN$' : '/dev/tty';

our %CARD_SORT = (
    None   => 0,
    Random => 1,
    Order  => 2,
);

sub init {

    my $class = shift;
    my $self = {
        Files   => [],
        Sort    => $CARD_SORT{None},
        OrderBy => '',
        First   => 'Definition',
    };

    my $order = undef;

    Getopt::Long::config('bundling');
    GetOptions(
        'order|o:s'     => \$order,
        'random|r'      => sub { $self->{Sort} = $CARD_SORT{Random} },
        'terms-first|t' => sub { $self->{First} = 'Term' },
        'help|h'        => sub { print $HELP_MSG; exit 0 },
        'version|v'     => sub { print $VER_MSG;  exit 0 },
    ) or die "Error in command line arguments\n";

    die $HELP_MSG unless @ARGV;

    $self->{Files} = [ @ARGV ];
    if (scalar(grep { $_ eq '-' } @{$self->{Files}}) > 1) {
        die "Standard input ('-') can only be passed once to the command-line\n";
    }

    if (defined $order) {

        $order = fc $order;

        if ($order eq fc 'term' or $order eq '') {
            $self->{OrderBy} = 'Term';
        } elsif ($order eq fc 'definition') {
            $self->{OrderBy} = 'Definition';
        } else {
            die "Cards must be sorted by either 'Term' or 'Definition'\n";
        }

        $self->{Sort} = $CARD_SORT{Order};

    }

    bless $self, $class;
    return $self;

}

sub run {

    my $self = shift;

    my $deck = App::Tarotplane::Cards->new(@{$self->{Files}});

    if (not -t STDIN) {
        open STDIN, '<', $TTY_PATH or die "Failed to open $TTY_PATH: $!\n";
    }

    if ($self->{Sort} == $CARD_SORT{Random}) {
        $deck->shuffle_deck();
    } elsif ($self->{Sort} == $CARD_SORT{Order}) {
        $deck->order_deck($self->{OrderBy});
    }

    my $filestr = join(" ", @{$self->{Files}});

    my $card = 0;
    my $side = $self->{First};

    my $ui = App::Tarotplane::UI->init();

    $ui->wipe();

    $ui->draw_card(
        $deck->card_side($card, $side),
        $side eq 'Term' ? 1 : 0
    );
    $ui->draw_info(
        sprintf("[%d/%d] %s", $card + 1, $deck->get('CardNum'), $filestr)
    );

    $ui->update();

    while (1) {

        my $cmd = $ui->poll();

        # Do nothing if we can't recognize the command
        next unless defined $cmd;

        if ($cmd eq 'Next') {
            $card++ if $card < $deck->get('CardNum') - 1;
            $side = $self->{First};
        } elsif ($cmd eq 'Prev') {
            $card-- if $card > 0;
            $side = $self->{First};
        } elsif ($cmd eq 'Flip') {
            $side = $side eq 'Term' ? 'Definition' : 'Term';
        } elsif ($cmd eq 'First') {
            $card = 0;
            $side = $self->{First};
        } elsif ($cmd eq 'Last') {
            $card = $deck->get('CardNum') - 1;
            $side = $self->{First};
        } elsif ($cmd eq 'Quit') {
            last;
        } elsif ($cmd eq 'Help') {
            $ui->wipe();
            $ui->draw_help();
            $ui->update();
            $ui->poll();
        }

        $ui->wipe();
        $ui->draw_card(
            $deck->card_side($card, $side),
            $side eq 'Term' ? 1 : 0
        );
        $ui->draw_info(
            sprintf("[%d/%d] %s", $card + 1, $deck->get('CardNum'), $filestr)
        );
        $ui->update();

    }

    $ui->end();

}

sub get {

    my $self = shift;
    my $get  = shift;

    return $self->{$get};

}

1;



=head1 NAME

App::Tarotplane - Curses flashcard program

=head1 SYNOPSIS

  use App::Tarotplane;

  $tarotplane = App::Tarotplane->init();
  $tarotplane->run();

=head1 DESCRIPTION

App::Tarotplane is the module that does all of the work for L<tarotplane>.
If you're looking for L<tarotplane> documentation, you should consult its
manual page instead of this one.

=head1 Object Methods

=head2 App::Tarotplane->init()

Reads @ARGV and returns an initialized App::Tarotplane object. Read the
documentation for L<tarotplane> for a list of what options are available to
tarotplane.

=head2 $tarotplane->run()

Runs tarotplane.

=head2 $tarotplane->get($get)

Get member $get from $tarotplane. The following are valid gets:

=over 4

=item Files

Array ref of supplied file arguments.

=item Sort

Sort method used, see %CARD_SORT below.

=item OrderBy

If ordering cards, what to order by. Can either be 'Term' or 'Definition'.

=item First

Which card side to display first. Can either be 'Term' or 'Definition'.

=back

get() primarily exists for testing purposes.

=head1 Global Variables

=over 4

=item $App::Tarotplane::VERSION

tarotplane version.

=item %CARD_SORT

  use App::Tarotplane qw(%CARD_SORT);

Hash map of different ways tarotplane can sort cards.

=over 4

=item None

Cards are sorted as they appear in the given files.

=item Random

Cards are sorted in random order.

=item Order

Cards are sorted in alphabetical order.

=back

=back

=head1 AUTHOR

Written by Samuel Young E<lt>L<samyoung12788@gmail.com>E<gt>.

=head1 COPYRIGHT

Copyright 2024-2026, Samuel Young

This library is free software; you may redistribute it and/or
modify it under the same terms as Perl itself.

=head1 SEE ALSO

L<tarotplane>

=cut
