package File::Monitor::Lite;

use 5.8.6;
our $VERSION = '0.652003';
use strict;
use warnings;
use File::Spec::Functions ':ALL';
use File::Find::Rule;
use File::Monitor;
use base 'Class::Accessor::Fast';
__PACKAGE__->mk_accessors( 
qw(
   monitor 
   watch_list
));
	

sub new {
    my $class = shift;
    my $self = {@_};
    bless $self, $class;
    $self->_init;
    return $self;
}

sub _init{
    my $self = shift;
    -d $self->{in} or die "invalid director\n";
    $self->{in}=rel2abs($self->{in});
    my %w_list = 
        map{$_ => 1}
        File::Find::Rule
            ->file()
            ->name($self->{name})
            ->in($self->{in});
    $self->watch_list(\%w_list);
    $self->monitor(new File::Monitor);
    $self->monitor->watch($_)for keys %w_list;
    $self->monitor->scan;
    $self->{observed}=[keys %w_list];
    $self->{created}=[];
    $self->{deleted}=[];
    $self->{modified}=[];
    1;
}



sub check {
    my $self = shift;
    my $w_list=$self->watch_list;
    my @new_file_list = 
        File::Find::Rule
        ->file()
        ->name($self->{name})
        ->in($self->{in});
    my @new_files = grep { not exists $$w_list{$_} } @new_file_list;
    my @changes = $self->monitor->scan;
    my @deleted_files = 
        map{$_->name}
        grep{$_->deleted} @changes;
    my @modified_files = 
        map{$_->name}
        grep{not $_->deleted} @changes;

    # update waching list
    foreach(@new_files){
        $$w_list{$_}=1;
        $self->monitor->watch($_);
    }
    # unwatch deleted files
    foreach(@deleted_files){
        $self->monitor->unwatch($_);
        delete $$w_list{$_};
    }
    $self->monitor->scan;       
    # do a scan first before next check
    # else next check $self->monitor cannot find differences


    $self->{watch_list}=($w_list);
    $self->{created}= [@new_files];
    $self->{modified}=[@modified_files];
    $self->{observed}=[ keys %$w_list];
    $self->{deleted}= [@deleted_files];
    $self->{anychange}= (
      scalar(@new_files)+
      scalar(@modified_files)+
      scalar(@deleted_files)) ? 1 : 0;

    1;
}
sub created {
    my $self = shift;
    #return () unless @{$self->{created}};
    return sort @{$self->{created}};
}
sub modified {
    my $self = shift;
    return sort @{$self->{modified}};
}
sub observed {
    my $self = shift;
    return sort @{$self->{observed}};
}
sub deleted {
    my $self = shift;
    return sort @{$self->{deleted}};
}
sub anychange{
    my $self = shift;
    return $self->{anychange};
}

# Preloaded methods go here.

1;
__END__
# Below is stub documentation for your module. You'd better edit it!

=head1 NAME

File::Monitor::Lite - Monitor file changes

=head1 SYNOPSIS

  use File::Monitor::Lite;
  
  my $monitor = File::Monitor::Lite->new (
      in => '.',
      name => '*.html',
  );

  while ($monitor->check() and sleep 1){
      my @deleted_files = $monitor->deleted;
      my @modified_files = $monitor->modified;
      my @created_files = $monitor->created;
      my @observing_files = $monitor->observed;
      `do blah..` if $monitor->anychange;
  }


=head1 DESCRIPTION

This is another implementaion of File::Monitor. While File::Monitor cannot detect file creation (unless you declare file name first), I use File::Find::Rule to rescan files every time when $monitor->check() is executed. To use this module, just follow synopsis above.

Currently one cannot change file observing rules. To do so, create another monitor object with new rules.

    $m1=File::Monitor::Lite->new(
        name => '*.html',
        in => '.',
    );
    $m1->check();
    #blah...
    $m2=File::Monitor::Lite->new(
        name => '*.css',
        in => '.',
    );
    $m2->check();
    #blah...

=head1 INTERFACE

=over

=item C< new ( args ) >

Create a new C<File::Monitor::Lite> object. 
    
    my $monitor = File::Monitor::Lite->new(
        in => '.',
        name => '*.mp3',
    );

The syntax is inherited from L<File::Find::Rule>. It will applied on L<File::Find::Rule> as

    File::Find::Rule
        ->file()
        ->name('*.mp3')
        ->in('.');

As described in L<File::Find::Rule>, name can be globs or regular expressions.

    name => '*.pm',                     # a simple glob
    name => qr/.+\.pm$/,                # regex
    name => ['*.mp3', qr/.+\.ogg$/],    # array of rules
    name => @rules,

=item C< check() >

Check if any file recognized by File::Find::Rule has changed (created, modified, deleted.) The usage is simple:

    $monitor->check();

=item C< created >

Returns an array of file names which has been created since last check.

=item C< modified >

Returns an array of file names which has been modified since last check.

=item C< deleted >

Returns an array of file names which has been deleted since last check.

=item C< observed >

Returns an array of file names which monitor is observing at.

=back

=head1 SEE ALSO

L<File::Find::Rule>, L<File::Monitor>

=head1 AUTHOR

dryman, E<lt>idryman@gmail.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2011 by dryman

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.


=cut