{
package Workflow::Aline::Robot;
    
    use IO::Extended ':all';

    use Class::Listener;

    our $VERBOSITY = 3;

    Class::Maker::class
    {
	isa => [qw( Class::Listener )],

	public =>
	{
	    ref => [qw( aline )],

	    number => [qw(stage verbosity)],
	},
    };

    sub _preinit : method
    {
	my $this = shift;

	$this->verbosity( $VERBOSITY );

	$this->stage( undef ); # works in all stages
    }

    sub if_active : method
    {
	my $this = shift;

	my $ok=0;

	if( not defined $this->stage )
	{
	    $ok = 1;
	}
	elsif( $this->stage == $this->aline->current_stage )
	{
	    $ok = 1;
	}
	return $ok;
    }

package Workflow::Aline::Robot::Mkdir;
    
    use IO::Extended ':all';

    use Class::Listener;

    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],
    };

    sub _on_dir : method
    {
	my $this = shift;

	my $event = shift;	

	my $conveyor_belt = shift;

	my $dir = shift;

	$dir->mkpath;

	return undef;
    }

package Workflow::Aline::Robot::Decorator;

    use strict;

    use IO::Extended ':all';


    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],
    };

    use IO::Extended qw(:all);

    sub _on_file : method
    {
	my $this = shift;

	my ( $event, $conveyor_belt, $src, $dst ) = @_;

        return unless $dst->stringify =~ /\.(pl|pm|pm\.tmpl)$/i;

	println "decorate" if $this->verbosity > 2;
	
	indn;
	
	println $dst if $this->verbosity > 2;
	
	indn;
	
	println "execute" if $this->verbosity > 2;

	if( $this->if_active )
	{
	    if( my $txt = $this->_exec_comp( @_ ) )
	    {
		println "prepend" if $this->verbosity > 2;

		$this->_prepend( $dst, $txt );
	    }
	}
	else
	{
	    println "This robot is not active in this stage";
	}

	indb;

	indb;

	return undef;
    }

    sub _exec_comp
    {
	my $this = shift;
	
	my $event = shift;
	
	my $conveyor_belt = shift;
	
	my $src = shift;
	
	my $dst = shift;
	
	my $anon_comp = eval 
	{ 
	    $Workflow::Aline::mason_interp->make_component( comp_source => '<& /maslib/defaults.mas:codecopyright &>' ) 
	};
	
	die $@ if $@;
	
	my $buffer;
	
	$Workflow::Aline::mason_interp->out_method( \$buffer );

	eval
	{
	    $Workflow::Aline::mason_interp->exec( $anon_comp );
	};
	die $@ if $@;
	
	return $buffer;
    }

    sub _prepend
    {
	my $this = shift;

	my $filename = shift;
	
	my @buffer;

	    local *FILE;

	    open( FILE, $filename ) or die "cannot open $filename";

 	    @buffer = <FILE>;

	    close( FILE );

	    open( FILE, ">".$filename ) or die "cannot open $filename";

	    if( $buffer[0] =~ /\#!/ )
	    {
		println "shebang detectored and preserved" if $this->verbosity > 2;

		my $shebang = shift @buffer; 

		print FILE $shebang, @_, @buffer or die "cannot write $filename";
	    }
	    else
	    {
		print FILE @_, @buffer or die "cannot write $filename";
	    }

	    close FILE or die "cannot close $filename";
    }

package Workflow::Aline::Robot::Copy;

    use strict;

    use IO::Extended ':all';


    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],
    };

    use File::Copy;
    
    sub _on_file : method
    {
	my $this = shift;

	my $event = shift;
	
	my $conveyor_belt = shift;

	my $src = shift;

	my $dst = shift;


	println "cp" if $this->verbosity > 1;
	
	indn;
	 
	if( $this->verbosity > 2 )
	{
	    println $dst;
	}
   
	if( $this->if_active )
	{	    
	    copy( $src."", $dst."" ) or die "$!: src=$src, dst=$dst";
	    
	    $conveyor_belt->master->Class::Listener::signal( 'copy', $src, $dst );
	    
	    println "done" if $this->verbosity > 2;
	}
	else
	{
	    println "This robot is not active in this stage";
	}
	    
	indb;

	return undef;
    }

package Workflow::Aline::Robot::Skip;

    use strict;

    use IO::Extended qw(:all);

    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],

	public =>
	{
	    ref => [qw( when )],
	}
    };

    sub _on_dir : method
    {
	goto &_on_file;
    }
    
    sub _on_file : method
    {	
	my $this = shift;

	my $event = shift;
	
	my $conveyor_belt = shift;

	my $src = shift;


	println "skip" if $this->verbosity > 2;
	
	indn;

	if( $this->if_active )
	{
	    printl "decision: " if $this->verbosity > 2;

	    if( $this->when->( $this, $event, $conveyor_belt, $src ) )
	    {
		print "yes\n" if $this->verbosity > 2;

		indb;

		return 1;
	    }
	    else
	    {
		print "no\n" if $this->verbosity > 2;
	    }
	}
	else
	{
	    println "This robot is not active in this stage" if $this->verbosity > 2;
	}
	
	indb;

	# returning undef aborts the conveyorbelt -> what we want from skip !

	return undef;
    }

package Workflow::Aline::Robot::Podchecker;

    use strict;

    use IO::Extended qw(:all);

    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],
    };
    
    sub _on_file : method
    {	
	my $this = shift;

	my $event = shift;
	
	my $conveyor_belt = shift;

	my $src = shift;

	my $dst = shift;
	
	println 'podcheck' if $this->verbosity > 1;

	indn;

	if( $this->if_active )
	{	    
	    return unless $dst->stringify =~ /tmpl|pm$/;
	
	    println qx{podchecker $dst} if $this->verbosity > 2;
	}
	else
	{
	    println "This robot is not active in this stage";
	}

	indb;

	return undef;
    }

package Workflow::Aline::Robot::Template;

    use strict;

    use IO::Extended qw(:all);

    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],

	public =>
	{
	    ref => [qw( detector )],
	},
    };

    sub test_detector : method
    {
	my $this = shift;

	my $src = shift;

	my $dst = shift;

	return 1 if $this->detector->( $src, $dst );
    }

    sub _on_file : method
    {
	my $this = shift;

	my $event = shift;
	
	my $conveyor_belt = shift;

	my $src = shift;

	my $dst = shift;

	my $comp_dir_unix = Path::Class::File->new( $dst )->relative( $conveyor_belt->master->comp_dir->absolute )->as_foreign( 'Unix' );
	
	return unless $this->test_detector( $src, $dst );
	
	println "mason component" if $this->verbosity > 1;

	indn; #
	
	if( $this->if_active )
	{	    
	    if( $this->verbosity > 2 )
	    {
		println $_ for ( $dst, $conveyor_belt->master->comp_dir->absolute, $comp_dir_unix );
	    }
	    
	    unless( $conveyor_belt->master->is_testrun )
	    {
		my $buffer;
                		
		indn; ##
		
  		println "executing component '$comp_dir_unix'" if $this->verbosity > 1;
		
		$Workflow::Aline::mason_interp->out_method( \$buffer );
		
		eval
		{
		    $Workflow::Aline::mason_interp->exec( '/'.$comp_dir_unix );	
		};
		die $@ if $@;
		
		indn; ###
		
		warn "WARNING: empty component output" and next unless length( $buffer );
		
		println "output file '$dst'" if $this->verbosity > 2;
		
		$this->_write( $dst, \$buffer );

		$conveyor_belt->Class::Listener::signal( 'copy', $src, $dst );
		
		# Create template output copy file
		
		$dst =~ s/\.tmpl$//;
		
		println "output copy '$dst'" if $this->verbosity > 2;
		
		$this->_write( $dst, \$buffer );
		
		$conveyor_belt->Class::Listener::signal( 'copy', $src, $dst );
		
		println "component output written" if $this->verbosity > 2;
		
		indb; ###
		
		indb; ##
	    }
	}
	else
	{
	    println "This robot is not active in this stage";
	}

	indb; #

	return undef;
    }

    sub _write
    {
	my $this = shift;

	my $filename = shift;
	
	my $buffer = shift;

	    local *RESULT;

	    open( RESULT, "> ".$filename ) or die "cannot open $filename";
	    
	    print RESULT $$buffer or die "cannot write $filename";
	    
	    close RESULT or die "cannot close $filename";
    }

package Workflow::Aline::Robot::Eval;

    use IO::Extended qw(:all);
    
    Class::Maker::class
    {
	isa => [qw( Workflow::Aline::Robot )],

	public =>
	{
	    string => [qw( code_text )],

	    bool => [qw( modify_inc )],

	    array => [qw( add_to_inc )],
	},

	default => 
	{
	    modify_inc => 0,
	},
    };

    sub _on_post_session : method
    {
	my $this = shift;

	my $event = shift;
	
	my $conveyor_belt = shift;

	println "eval perl";

	indn;

	if( $this->if_active )
	{
	    if( $this->modify_inc )
	    {
		unshift @INC, $conveyor_belt->sprintf_current_target_dir( $conveyor_belt->master->current_stage )->absolute->stringify;
	    }

	    if( $this->add_to_inc )
	    {
		unshift @INC, $this->add_to_inc;
	    }
	    
	    eval $this->code_text;
	
	    die $@ if $@;
	}
	else
	{
	    println "This robot is not active in this stage";
	}

	indb;

#	printfln "Loaded post-publish module Data::Type VERSION %s", Data::Type->VERSION();

	return undef;
    };

package Workflow::Aline::Robot::Finalize;

    use IO::Extended qw(:all);
    

    Class::Maker::class 
    { 
	isa => [qw(Workflow::Aline::Robot)] 
    };

    sub _on_close
    {
	my $this = shift;

	my $event = shift;

	my $conveyor_belt = shift;


	println "finalize";

	indn;

	if( $this->if_active )
	{
	    my $fin_file = $conveyor_belt->target_dir->file( 'finalize.pl' );
	    
	    if( -e $fin_file->stringify )
	    {
		my $lev = ind;

		indn;

		printfln "finalize" if $this->verbosity > 1;

		indn;

		printfln "load file %s", $fin_file->stringify if $this->verbosity > 2;

		open( CODE, $fin_file->stringify );

		printfln "chdir %s", $conveyor_belt->target_dir if $this->verbosity > 2;

		chdir( $conveyor_belt->target_dir );

		println "eval code" if $this->verbosity > 2;

		my $result = eval join( '', <CODE> );
		
		indn; println "" if $this->verbosity > 2;

		if( $this->verbosity > 2 )
		{
		    println "success" if defined $result;
		}

		warnfln "execution failed: %s", $! || $@ unless defined $result;

		ind( $lev );
	    }
	}
	else
	{
	    println "This robot is not active in this stage";
	}

	indb;

	return undef;
    }
}

1;