#!/usr/local/bin/perl

use strict;
use v5.8.1;

use warnings;
use Getopt::Long;
use Pod::Usage;
use Data::Dumper;
use Sys::Hostname ();
use UNIVERSAL::require;
use Best [ [ qw/YAML::XS YAML::Syck YAML/ ], qw/Dump/ ];

my $options;
my $DEBUG;

BEGIN {
	$options={};
	$Getopt::Long::ignorecase=0;
	GetOptions ($options, qw/
		HOST=s 
		port=i 
		alias=s
		state_name|state=s
		INC|inc:s@
		inc_=s
		Utility=s
		debug
		Display
		help
		output|out=s
		/);
}

	my $args = [@ARGV];
	if (exists $options->{debug}) {
		$DEBUG = 1;
		_DEBUG_log($options);
		_DEBUG_log($args);
	}

	$options->{help} 		and	pod2usage(1);

	$options->{alias} ||= 'POEIKCd';
	$options->{port} ||= 47225;
	
	### state_name vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	$options->{state_name} ||= '';


	if (exists $options->{Utility}) {
		my $commoand = $options->{Utility};
		$commoand = $options->{Utility};
		$options->{state_name} = 'm';
		@{$args} = ('POEIKCdaemon::Utility', $commoand, @{$args});
		$options->{output} ||= 'd';
		_DEBUG_log($args);
	}

	if (exists $options->{INC}) {
		my @inc;
		@inc = 
#			map {s/~/$ENV{HOME}/;$_} 
			map {split(/:/=>$_)} 
			map {ref $_ ? @{$_} : $_} 
			($options->{INC});
		$options->{state_name} = 'm';
		@{$args} = (qw(POEIKCdaemon::Utility unshift_INC), @inc);
		$options->{output} ||= 'd';
		_DEBUG_log($args);
	}

	if (exists $options->{inc_}) {
		my $commoand = $options->{inc_};
		$commoand = 
			$commoand =~ /^del$|^delete$|^delete_INC$/ ? 'delete_INC' :
			$commoand =~ /^reset$|^reset_INC$/ ? 'reset_INC' : $commoand;
		$options->{state_name} = 'm';
		@{$args} = ('POEIKCdaemon::Utility', $commoand, @{$args});
		$options->{output} ||= 'd';
		_DEBUG_log($args);
	}

	$options->{state_name} = 
		$options->{state_name} =~ /^method|^m$/ 	? 'method_respond' : 
		$options->{state_name} =~ /^function|^f$/ 	? 'function_respond' : 
		$options->{state_name} =~ /^eval/ 			? 'eval_respond' : 
		$options->{state_name} =~ /^event|^e$/ 		? 'event_respond' : 
		(@{$args} == 1 and $args->[0] eq 'stop') 	? 'stop_respond' :
		$options->{state_name};

	$options->{state_name} 	or 	pod2usage(1);
	$options->{state_name} eq 'stop_respond' 
		and not($options->{HOST}) and pod2usage(1);

	###^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	$options->{HOST} ||= '127.0.0.1';

	if( Proc::ProcessTable->use ){
		for my $ps( @{Proc::ProcessTable->new->table} ) {
			if ($ps->{fname} eq 'poikc'){
				$ps->{cmndline} =~ /poikc/;
				$0 = $ps->{fname}. $';
			}
		}
	}

	if (exists $options->{debug}) {
		_DEBUG_log($options);
		_DEBUG_log($options->{HOST});
		_DEBUG_log($options->{port});
		_DEBUG_log($args);
	}

	use POE::Component::IKC::ClientLite;
	my ($name) = join('_'=>Sys::Hostname::hostname, ($0 =~ /(\w+)/g), $$);
	my $ikc = create_ikc_client(
		ip   => $options->{HOST},
		port => $options->{port},
		name => $name,
	);
	$ikc or do{
		printf "%s\n\n",$POE::Component::IKC::ClientLite::error; 
		exit;
	};

	my $state_name = $options->{alias}.'/'.$options->{state_name};

	$DEBUG and _DEBUG_log($state_name, $args);

	if ($DEBUG or exists $options->{Display}){
		my $param = ref $args ? Dumper($args): $args;
		$param =~ s/\s+//g;
		$param =~ s/\$VAR1=//g;
		$param =~ s/;//g;
		printf "\n# \$ikc_client->post_respond( '%s' => %s );\n\n",$state_name => $param ;
	}

	my $ret = $ikc->post_respond($state_name => $args);
	$ikc->error and die($ikc->error);
	if (my $r = ref $ret) {
		if ( $options->{output} and $options->{output} =~ /^H[YD]$/i and  $r eq 'HASH'){
			$options->{output} =~ s/^H//i;
			my %ret = %{$ret};
			my $max = 0;
			for(sort keys %ret){length($_) > $max and $max = length($_);}
			my $format = "%-${max}s= %s";
			for(sort keys %ret){printf $format, $_, output($ret{$_})}
			print "\n";
		}else{
			print(output($ret));
		}
	}else{
		print(output($ret));
	}

sub output {
	$DEBUG and _DEBUG_log(join "\t"=> caller(1));
	return unless @_;
	for ($options->{output} || ()) {
		/^D$|^Dumper$/i	and return Dumper(@_);
		/^Y$|^YAML$/i  	and return Dump(@_);
	}
	return @_; # YAML
}

sub _DEBUG_log {
	$DEBUG or return;
	Date::Calc->use or return;
	#YAML->use or return;
	my ($pack, $file, $line, $subroutine) = caller(0);
	my $levels_up = 0 ;
	($pack, $file, $line, ) = caller($levels_up);
	$levels_up++;
	(undef, undef, undef, $subroutine, ) = caller($levels_up);
	{
		(undef, undef, undef, $subroutine, ) = caller($levels_up);
		if(defined $subroutine and $subroutine eq "(eval)") {
		    $levels_up++;
		    redo;
		}
		$subroutine = "main::" unless $subroutine;
	}
	my $log_header = sprintf "[DEBUG %04d/%02d/%02d %02d:%02d:%02d %s %d %s %d %s] - ",
			Date::Calc::Today_and_Now() , $ENV{HOSTNAME}, $$, $file, $line, $subroutine;
	my @data = @_;
	print(
		$log_header, (join "\t" => map {
			ref($_) ? Dumper($_) : 
			defined $_ ? $_ : "`'" ; 
		} @data ),"\n"
	);
}


__END__

=head1 NAME

poikc - POK IKC (poeikcd) Client

=head1 SYNOPSIS

  poikc -H hostname [options] args...
  poikc -H remote_hostname -p=47225 -a=POEIKCd -s=m -o=y MyClass my_method args...

Options:

    -H  --HOST=s         : default 127.0.0.1 

    -p  --port=#         : Port number to use for connection.
                           default 47225 

    -a  --alias=s        : session alias
                           default POEIKCd 
                           eg)
                             -a=my_session_ailas

    -s  --state_name=s   : state_name (method_respond | function_respond |
                           event_respond | eval_respond | stop_respond)
                           eg)
                             -s=m | -s=f | -s=e | -s=eval
                             -state_name=my_event_name

    -I  --INC=s          : specify @INC/#include directory
                           eg1) -I ~/lib:/mylib/ or -I ~/lib -I /foo/lib/
                           eg2) poikc -I '$ENV{HOME}/lib'


    --inc_=delete ~/lib  : deletes from @INC.
    --inc_=reset         : @INC is reset.

    --Utility=s          : POEIKCdaemon::Utility It is shortcut.
                          eg) poikc -U=get_VERSION
                          -U=get_stay, -U=get_load, -U=get_H_INC, -U=get_E_ENV

    -o  --output|out=s   : output method 
                          -o y | -output=YAML
                          -o d | -output=Dumper   (Data::Dumper)

    -Display             : The parameter given to post_respond is confirm.

    -h  --help

@INC Operation

	poikc  -I                     ( print Dumper \@INC )
	poikc  -I ./t                 ( unshift @INC, './t' )
	poikc --inc_=delete ./t       ( @INC = grep {$_ ne './t'} @INC )
	poikc --inc_=reset

pokikcd server stop  ( Please specify a host name.)

    poikc -H=hostname stop 

eg:

    poikc -s=e -o=y alias my_method args1 args2
    poikc -U get_VERSION
    poikc -o d -U publish_IKC my_alias_name my_package_name
    poikc -o d -U publish_IKC my_alias_name _list event_1 event_2 ..
    poikc -s=function_respond LWP::Simple get http://search.cpan.org/~suzuki/
    poikc -s=eval_respond 'scalar `ps ux`'


=head1 DESCRIPTION

poikc is POE IKC (L<poeikcd>) Client 

=head1 AUTHOR

Yuji Suzuki E<lt>yuji.suzuki.perl@gmail.comE<gt>

=head1 LICENSE

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

=head1 SEE ALSO

L<poeikcd>
L<POE::Component::IKC::ClientLite>

=cut
