#!/usr/bin/perl

package JMX::Jmx4Perl::J4psh::CompletionHandler;

use strict;
use File::Spec;
use Data::Dumper;

=head1 NAME 

JMX::Jmx4Perl::J4psh::CompletionHandler - Custom completion routines for readline.

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=cut


sub new { 
    my $class = shift;
    my $context = shift || die "No context object given";
    my $self = {
                context => $context
               };
    bless $self,(ref($class) || $class);
    return $self;
}

sub files_extended {
    my $self = shift;
    return sub {
        my $term = shift;
        my $cmpl = shift;
        my $filter = undef;
        
        $term->suppress_completion_append_character();
        
        use File::Spec;
        my @path = File::Spec->splitdir($cmpl->{str} || ".");
        my $dir = File::Spec->catdir(@path[0..$#path-1]);
        my $lookup_dir = $dir;
        if ($dir =~ /^\~(.*)/) {
            my $user = $1 || "";
            $lookup_dir = glob("~$user");
        }
        my $file = $path[$#path];
        $file = '' unless $cmpl->{str};
        my $flen = length($file);
        
        my @files = ();
        $lookup_dir = length($lookup_dir) ? $lookup_dir : ".";
        if (opendir(DIR, $lookup_dir)) {
            if ($filter) {
                @files = grep { substr($_,0,$flen) eq $file && $file =~ $filter } readdir DIR;
            } else {
                @files = grep { substr($_,0,$flen) eq $file } readdir DIR;
            }
            closedir DIR;
            # eradicate dotfiles unless user's file begins with a dot
            @files = grep { /^[^.]/ } @files unless $file =~ /^\./;
            # reformat filenames to be exactly as user typed
            my @ret = ();
            for my $file (@files) {
                $file .= "/" if -d $lookup_dir . "/" . $file;
                $file = $dir eq '/' ? "/$file" : "$dir/$file" if length($dir);
                push @ret,$file;
        }
            return \@ret;
        } else {
            $term->completemsg("Couldn't read dir: $!\n");
            return [];
        }
    }
}

sub servers {
    my $self = shift;
    return sub {
        my ($term,$cmpl) = @_;
        my $context = $self->{context};
        my $server_list = $context->servers->list;
        return [] unless @$server_list;
        my $str = $cmpl->{str} || "";
        my $len = length($str);
        return [ grep { substr($_,0,$len) eq $str }  map { $_->{name} } @$server_list  ];
    }
}

# Complete on mbean names
sub mbeans {
    my $self = shift;
    my %args = @_;
    my $attr;
    return sub {
        my ($term,$cmpl) = @_;
        $term->suppress_completion_escape();
        my $all = $args{all};
        my $domain = $args{domain};
        #$term->{debug_complete}=5;
        my $context = $self->{context};
        my $mbeans = $context->mbeans_by_domain;
        my $str = $cmpl->{str} || "";
        my $len = length($str);
        if ($domain) {
            my $attrs = $mbeans->{$domain};
            return [] unless $attrs;
            my @kv = map { $_->{string} } @$attrs;
            return [ map { $_ } grep { substr($_,0,$len) eq $str } @kv ];
        } else {
            ($domain,$attr) = split(/:/,$str,2);
            if ($attr || $str =~ /:$/) {
                # Complete on attributes
                my $attrs = $mbeans->{$domain};
                return [] unless $attrs;
                my @kv = map { $_->{string} } @$attrs;
                if ($attr) {
                    return [ map { $domain . ":" . $_ } grep { substr($_,0,length($attr)) eq $attr } @kv ];
                } else {
                    return [ map { $domain . ":" . $_} @kv ];
                }            
            } else {
                # Complete on domains
                my $domains = $str ? [ grep { substr($_,0,$len) eq $str } keys %$mbeans ] : [ keys %$mbeans ];
                if ($all) {
                    $term->suppress_completion_append_character();
                }
                return $domains;
            }
        }
    };
}

sub mbean_attributes {
    return shift->_complete_attr_op(shift,"attr");
}

sub mbean_operations {
    return shift->_complete_attr_op(shift,"op");
}

sub _complete_attr_op {
    my $self = shift;
    my $m_info = shift;
    my $what = shift;
    my $attr;
    #print "> ",Dumper($m_info->{info}->{attr});
    return sub {
        my ($term,$cmpl) = @_;
        $term->suppress_completion_escape();
        my $attrs = $m_info->{info}->{$what};
        #$term->{debug_complete}=5;
        my $context = $self->{context};
        my $str = $cmpl->{str} || "";
        my $len = length($str);
        return [ grep { substr($_,0,$len) eq $str } keys %$attrs ];
    }; 
}


# Method for completing based on key=value for an 
# arbitrary order of key, value pairs
sub _complete_props {
    my $self = shift;
    # List of MBeans for this domain
    my $mbeans_ref = shift;
    my @mbeans = ( @{$mbeans_ref} );
    my $input = shift;
    my $context = $self->{context};
    # Get all already completed
    my @parts = split /,/,$input;
    my $last = pop @parts;
    # Filter out already set types
    for my $p (@parts) {
        my ($k,$v) = split /=/m,$p,2;
        @mbeans = grep { $_->{props}->{$k} eq $v } @mbeans;
    }
    
}

=head1 LICENSE

This file is part of jmx4perl.

Jmx4perl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

jmx4perl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with jmx4perl.  If not, see <http://www.gnu.org/licenses/>.

A commercial license is available as well. Please contact roland@cpan.org for
further details.

=head1 PROFESSIONAL SERVICES

Just in case you need professional support for this module (or Nagios or JMX in
general), you might want to have a look at
http://www.consol.com/opensource/nagios/. Contact roland.huss@consol.de for
further information (or use the contact form at http://www.consol.com/contact/)

=head1 AUTHOR

roland@cpan.org

=cut


1;