package App::Pimpd::Shell;
use strict;

BEGIN {
  use Exporter;
  use vars qw(@ISA @EXPORT);
  @ISA = qw(Exporter);
  @EXPORT = qw(
    spawn_shell
  );
}

use App::Pimpd;
use App::Pimpd::Doc;
use App::Pimpd::Info;
use App::Pimpd::Player;
use App::Pimpd::Commands;
use App::Pimpd::Transfer;
use App::Pimpd::Collection::Album;
use App::Pimpd::Collection::Search;
use App::Pimpd::Playlist;
use App::Pimpd::Playlist::Favorite;
use App::Pimpd::Playlist::Randomize;
use App::Pimpd::Playlist::Search;
use App::Pimpd::Validate;
use Term::ExtendedColor qw(fg);
use Term::ReadLine; # Term::ReadLine::Gnu prefered
use File::LsColor qw(ls_color);

my $opts;
sub spawn_shell {
  my $option = shift;
  my($cmd, $arg, @cmd_args); # for later use


  #print help('shell');


  $opts = {

    'randomize'      => sub {
      if(!defined($_[0])) {
        $_[0] = 100;
      }
      elsif(defined($_[0]) and $_[0] !~ /^\d+$/m) {
        print STDERR "Need a valid integer\n";
        $_[0] = 100;
      }
      print 'Adding ' . fg('bold', @_) . " random tracks...\n";
      my @random = randomize(@_);

#      print $_->artist for @random;
#      print "$_\n" for @random;
      clear_playlist();
      add_to_playlist(@random);
      print "$_\n" for map { ls_color($_) } @random;
    },


    'randomalbum'   => sub {
      $_[0] = 10 if(!$_[0]);
      print 'Adding ' . fg('bold', $_[0]) . " random albums...\n\n";
      my @albums = randomize_albums($_[0]);

      my $old = undef;
      for(@albums) {
        my($album_dir) = $_ =~ m|(.+)/.+|m;
        if($old ne $album_dir) {
          print "> $album_dir\n";
          $old = $album_dir;
        }
      }
      print "\n";
      clear_playlist();
      add_to_playlist(@albums);
    },


    'playlist'       => sub {
      if(empty_playlist()) {
        print STDERR "Playlist is empty\n";
        return 1;
      }
      show_playlist();
      print fg('bold', ' >'), '> ', current(), "\n";
    },


    'love'           => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      add_to_favlist(@_);
    },

    'loved?'          => sub {
      if(already_loved($mpd->current->file)) {
        printf("%s, %s by %s is loved.\n",
          fg('bold', 'Yes'),
          fg($c[10], $mpd->current->title),
          fg($c[2],  fg('bold', $mpd->current->artist)),
        );
      }
      else {
        printf("%s, %s by %s is not loved yet.\n",
          fg('bold', 'No'),
          fg($c[10], $mpd->current->title),
          fg($c[2],  fg('bold', $mpd->current->artist)),
        );
      }
    },

    'unlove'            => sub {
      if(!@_) {
        print help('unlove');
        return;
      }
      remove_favorite(@_);
    },

    'track'           => sub {
      $_[0] = 1 if $_[0] !~ /^\d+$/m;
      play_pos_from_playlist(@_);
    },

    'copy'            => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      cp($config{target_directory});
    },

    'copya'      => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      cp_album($config{target_directory});
    },

    # FIXME
    'copy-list'       => sub { cp_list(@_); },

    'info'               => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      info();
    },

    'monitor'         => sub {
      if(empty_playlist()) {
        print STDERR "Playlist is empty - there's nothing to monitor\n";
        return 1;
      }
      #monitor();
      #FIXME
    },

    'sartist'         => sub {
      my $artist = join(' ', @_);
      if(!$artist) {
        print help('sartist');
        return;
      }
      add_to_playlist(search_db_artist($artist));
    },

    'salbum'          => sub {
      my $album = join(' ', @_);
      if(!$album) {
        print help('salbum');
        return;
      }
      add_to_playlist(search_db_album($album));
    },

    'stitle'          => sub {
      my $title = join(' ', @_);
      if(!$title) {
        print help('stitle');
        return;
      }

      my @result = search_db_title($title);
      if(@result) {
        print "$_\n" for @result;
        add_to_playlist(@result);
      }
      else {
        printf("No titles matching '%s'\n",
          fg($c[5], $title),
        );
      }
    },

    'sany'            => sub {
      my $search = join(' ', @_);
      if(!$search) {
        print help('sany');
        return;
      }
      add_to_playlist(search_db_quick($search));
    },

    'splaylist'       => sub {
      my $search = join(' ', @_);
      if(!$search) {
        print help('splaylist');
        return;
      }
      print "$_\n" for values %{ search_playlist($search) };
      my $result = search_playlist($search);
      if(scalar(keys(%{ $result })) > 0) {
        print "$_\n" for values %{ $result };
        queue( keys % { search_playlist($search) } );
      }
      else {
        print "No match\n";
      }
    },

    'slove'           => sub {
      my $search = join(' ', @_);
      my @files = search_favlist($search);
      print "$_\n" for @files;
      add_to_playlist(@files);
    },


    'sap'             => sub {
      my $search = join(' ', @_);
      if(!$search) {
        print help('slove');
        return;
      }
      my @result = search_all_playlists($search);
      print "$_\n" for @result;
      add_to_playlist(@result);
    },


    'albums'          => sub {
      if(empty_playlist() and !@_) {
        print STDERR "Nothing is playing, and no argument supplied\n";
        return 1;
      }
      my $artist = join(' ', @_);
      print "$_\n" for albums_by_artist($artist);
    },

    'songs'           => sub {
      printf "%s\n", ls_color($_->file) for songs_on_album(@_);
#      printf "%s\n", $_->title for songs_on_album(@_);
    },

    'add-album'       => sub {
      add_to_playlist( map{ $_->file } get_album_songs(@_));
    },
    'lsplaylists'     => sub { print "$_\n" for list_all_playlists(); },
    'add'             => sub {

      if($_[0] eq 'songs') {
        local $\ = "\n";
        my @songs = map { $_->file } songs_on_album();
        printf("Adding %d songs from %s\n",
          scalar(@songs), fg('bold', $mpd->current->album),
        );
        add_to_playlist(@songs);
      }

      elsif($_[0] eq 'slove') {
        shift @_; # so we can grab the PATTERN
        my @result = search_favlist(@_);

        if(scalar(@result) > 0) {
          print "$_\n" for @result;

          add_to_playlist(@result);
          printf("\nAdded %s loved %s matching '%s'\n",
            fg('bold', scalar(@result)),
            (scalar(@result) > 1) ? 'songs' : 'song',
            fg($c[4], fg('bold', $_[0])),
          );
        }
        else {
          printf("No songs matching '%s' were found\n",
            fg($c[4], fg('bold', $_[0])),
          );
        }
      }

      else {
        add_playlist(@_);
      }
    },

    'next'            => sub {
      if(empty_playlist()) {
        print STDERR "Playlist is empty!\n";
        return 1;
      }
      next_track();
      print current() . "\n";
    },

    'previous'        => sub {
      if(empty_playlist()) {
        print STDERR "Playlist is empty!\n";
        return 1;
      }
      previous_track();
      print current() . "\n";
    },

    'pause'           => sub {
      toggle_pause();
      print $mpd->status->state . "\n";
    },

    'shuffle'         => sub {
      $mpd->playlist->shuffle;
      print "New playlist version is " .$mpd->status->playlist . "\n"
    },

    'np'              => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      print current() . "\n";
    },

    'nprt'            => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      np_realtime();
    },

    'queue'            => sub {
      if(invalid_playlist_pos(@_)) {
        printf("No such song%s\n", (@_ < 1) ? 's' : '');
        return 1;
      }
      queue(@_);
    },

    'random'           => sub {
      $mpd->random;
      my $status =  ($mpd->status->random)
        ? "Random: " . fg('bold', 'On')
        : "Random: " . fg('bold', 'Off');
      print "$status\n";
    },

    'repeat'           => sub {
      $mpd->repeat;
      my $status = ($mpd->status->repeat)
        ? "Repeat: " . fg('bold', 'On')
        : "Repeat: " . fg('bold', 'Off');
      print "$status\n";
    },

    'stats'            => sub { stats(); },
    'status'           => sub { print status(), "\n"; },

    'randomtrack'      => sub {
      play_pos_from_playlist(random_track_in_playlist());
      print current(), "\n";
    },

    'external'         => sub { songs_in_playlist(@_); },
    'clear'            => sub { clear_playlist() },
    'crop'             => sub { $mpd->playlist->crop; },
    'stop'             => sub { stop(); },
    'kill'             => sub { player_destruct(); },
    'play'             => sub {
      if(empty_playlist()) {
        print STDERR "Nothing is playing - playlist is empty\n";
        return 1;
      }
      play();
    },

    'delete-album'     => \&delete_album,
    'stats'            => sub { App::Pimpd::Info::stats() },

    'rmalbum'          => sub { remove_album_from_playlist(@_); },
    'exit'             => sub { exit(0); },
    ':q'               => sub { exit(0); },
    'help'             => sub {
      if( defined($opts->{$_[0]}) ) {
        print help($_[0]);
      }
      else {
        print help('shell');
      }
    },
  };

  while(1) {
    #print fg($c[6], 'pimpd'), fg('bold', '> ');

    #chomp(my $choice = <STDIN>);
    my @available_cmd = keys(%{$opts});
    push(@available_cmd, 'shell');

    my $term = Term::ReadLine->new('pimpd2');
    my $attr = $term->Attribs;

    $attr->{completion_function} = sub {
      my($text, $line, $start) = @_;
      return @available_cmd;
    };

    $attr->{autolist} = 0;
    $attr->{maxcomplete} = 0;
    # Sane keymap please.
    $term->set_keymap('vi');

    my $choice;

    while(1) {
      $choice = $term->readline(fg($c[6], 'pimpd') . fg('bold', '> '));
      $term->addhistory($choice) if $choice =~ /\S/m;

      ($cmd) = $choice =~ m/^(\S+)/m;
      ($arg) = $choice =~ m/\s+(.+)$/m;
      @cmd_args  = split(/\s+/m, $arg);

      if(defined($opts->{$cmd})) {
        $mpd->play;
        $opts->{$cmd}->(@cmd_args);
      }
      else {
        $opts->{help}->();
        print STDERR "No such option '", fg($c[5], $cmd), "'.\n";
      }
    }
  }
  exit(0);
}



1;

__END__

=pod

=head1 NAME

App::Pimpd::Shell - Pimpd interactive shell

=head1 SYNOPSIS

    use App::Pimpd;
    use App::Pimpd::Shell;

    spawn_shell();

=head1 DESCRIPTION

App::Pimpd::Shell contains the definitions set up for an interactive shell with
tabcompletion support that can handle most of this programs options.

=head1 EXPORTS

=over

=item spawn_shell()

Spawn the shell.

=back

=head1 SEE ALSO

App::Pimpd

=head1 AUTHOR

  Magnus Woldrich
  CPAN ID: WOLDRICH
  m@japh.se
  http://japh.se

=head1 COPYRIGHT

Copyright (C) 2010, 2011 Magnus Woldrich. All right reserved.
This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut