# +==========================================================================+
# || Copyright (C) 1999 - 2010 by Christian Kuelker                         ||
# ||                                                                        ||
# || License: GNU General Public License - GNU GPL - version 2              ||
# ||          or (at your opinion) any later version                        ||
# +==========================================================================+
# ID:       $Id: Task.pm 4770 2010-02-17 18:45:25Z christian-guest $
# Revision: $Revision: 4770 $
# Head URL: $HeadURL$
# Date:     $Date: 2010-02-17 19:45:25 +0100 (Wed, 17 Feb 2010) $
# Source:   $Source$

package CipUX::Task;

use 5.008001;
use strict;
use warnings;
use utf8;
use Carp;
use Class::Std;
use CipUX::Object::Action::Create;
use CipUX::Object::Action::Destroy;
use CipUX::Object::Action::List;
use CipUX::Object::Action::Attribute::List;
use CipUX::Object::Action::Attribute::Change;
use Data::Dumper;
use English qw( -no_match_vars );
use Log::Log4perl qw(:easy);
use Readonly;
use Scalar::Util qw(looks_like_number);    # core since Perl 5.8
use Term::ReadKey;

use base qw(CipUX);
{                                          # BEGIN CLASS

    use version; our $VERSION = qv('3.4.0.7');
    use re 'taint';    # Keep data captured by parens tainted
    delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};    # Make %ENV safe

    # +======================================================================+
    # || CONST                                                              ||
    # +======================================================================+
    Readonly::Scalar my $EMPTY_STRING => q{};

    # +======================================================================+
    # || OBJECT                                                             ||
    # +======================================================================+
    my %task_api_cfg : ATTR( :get<task_api_cfg> );

    # +======================================================================+
    # || GLOBAL                                                             ||
    # +======================================================================+

    # +======================================================================+
    # || CONSTRUCTOR                                                        ||
    # +======================================================================+
    sub BUILD {

        # +------------------------------------------------------------------+
        # | API
        my ( $self, $obj_id, $arg_r ) = @_;

        # add prefix for cfg, if needed
        my $pref
            = exists $arg_r->{pref}
            ? $self->l( $arg_r->{pref} )
            : $EMPTY_STRING;

        my $cache_dir
            = exists $arg_r->{cache_dir}
            ? $self->l( $arg_r->{cache_dir} )
            : $EMPTY_STRING;

        # +------------------------------------------------------------------+
        # | prepare

        # +------------------------------------------------------------------+
        # | main
        my $cfg_hr = $self->cfg(
            { 'sub' => 'task', pref => $pref, cache_dir => $cache_dir } );

        $task_api_cfg{$obj_id} = $cfg_hr->{task_api};

        undef $cfg_hr;

        # +------------------------------------------------------------------+
        # | API
        return;
    }

    # +======================================================================+
    # || DESTRUCTOR                                                         ||
    # +======================================================================+
    sub DEMOLISH {

        # +------------------------------------------------------------------+
        # | API
        my ( $self, $ident ) = @_;

        # +------------------------------------------------------------------+
        # | main
        delete $task_api_cfg{$ident};

        # +------------------------------------------------------------------+
        # | API
        return;

    }

    # +======================================================================+
    # || open module features                                               ||
    # +======================================================================+

    # +======================================================================+
    # || task                                                               ||
    # +======================================================================+
    sub task {

        #API
        # $opject, see below
        my ( $self, $arg_r ) = @_;

        my $mode
            = exists $arg_r->{mode}
            ? $self->l( $arg_r->{mode} )
            : $self->perr('mode');

        my $script
            = exists $arg_r->{script}
            ? $self->l( $arg_r->{script} )
            : $self->perr('script');

        my $task
            = exists $arg_r->{task}
            ? $self->l( $arg_r->{task} )
            : $self->perr('task');

        my $cfg_task_api_hr = $task_api_cfg{ ident $self};

        my %task_api = %{$cfg_task_api_hr};

        my $action
            = exists $arg_r->{action}
            ? $self->l( $arg_r->{action} )
            : $task_api{$task}{action};

        my $attr_hr
            = exists $arg_r->{attr_hr}
            ? $self->h( $arg_r->{attr_hr} )
            : $self->perr('attr_hr');

        # +------------------------------------------------------------------+
        # | main
        my $logger = get_logger(__PACKAGE__);

        $logger->debug('BEGIN');
        $logger->debug( '> mode   : ', $mode );
        $logger->debug( '> script : ', $script );
        $logger->debug( '> action : ', $action );
        $logger->debug( '> task   : ', $task );

        #$logger->debug( '> attr_hr : ', {filter=>\&Dumper, value=>$attr_hr});

        # test if given task is a valid task
        if ( not defined( $task_api{$task}{object} ) ) {
            my $msg = 'Given task is not valid! ';
            $msg .= '(Not defined in configuration file.) ';
            $msg .= 'Did you write it correct? ';
            $msg .= '(use cipux_task_client -l to see all valid tasks.) ';
            $msg .= 'The task you gave was:';
            $self->exc( { msg => $msg, value => $task } );
        } ## end if ( not defined( $task_api...

        my @type = @{ $task_api{$task}{object} };
        foreach my $type (@type) {
            if ( defined($type) ) {
                my $msg = "task called:";
                $logger->debug( $msg . q{: }, $task );
                $msg = "task has obj type:";
                $logger->debug( $msg . q{: }, $type );
            }
            else {
                my $msg = 'object type undef for task:';
                $self->exc( { msg => $msg, value => $task } );
            }

            # +-------------------------------------------------------------+
            # | create_object_action                                        |
            # +-------------------------------------------------------------+

            # A-Z task actions
            if ( $action eq 'create_object_action' ) {

                my $object
                    = exists $arg_r->{object}
                    ? $self->l( $arg_r->{object} )
                    : $self->perr('object');

                my $cipux        = new CipUX::Object::Action::Create();
                my $overwrite_hr = undef;

                if ( defined( $task_api{$task}{overwrite} ) ) {
                    $overwrite_hr = $task_api{$task}{overwrite};

                    $logger->debug('got overwrite from cipux-task.conf');
                    $logger->debug( 'overwrite_hr: ',
                        { filter => \&Dumper, value => $overwrite_hr } );
                }
                else {
                    $logger->debug('got NO overwrite from cipux-task.conf');
                }
                my $return_hr = $cipux->create_object_action(
                    {
                        action       => $action,
                        type         => $type,
                        object       => $object,
                        attr_hr      => $attr_hr,
                        overwrite_hr => $overwrite_hr,
                    }
                );

                # execute additional tasks as post hook
                if ( exists $task_api{$task}{task}{post} ) {
                    $logger->debug('Execute post task');
                    $logger->debug("> object $object");
                    $logger->debug("> task $task");

                    $self->snd_task(
                        {
                            object       => $object,
                            post_task_hr => $task_api{$task}{task}{post}
                        }
                    );
                }

                # create_object_action return (main task)
                my $status_hr = {
                    status    => 'OK',
                    type      => 'href',
                    taskres_r => $return_hr,
                    ltarget   => 'NULL',
                };

                # if there is a doggy in cipux-task.conf we let the dog run
                if ( exists $task_api{$task}{dog}{post} ) {

                    $logger->debug('dog def exists, try exec (start)');

                    $self->exec_task_dog(
                        {
                            dog_hr       => $task_api{$task}{dog}{post},
                            object       => $object,
                            overwrite_hr => {},
                        }
                    );

                    $logger->debug('dog def exists, try exec (end)');

                }
                else {

                    $logger->debug('no dog section in cipux-task.conf');

                }

                return $status_hr;

            } ## end if ( $action eq 'create_object_action')

            # +-------------------------------------------------------------+
            # | destroy_object_action                                       |
            # +-------------------------------------------------------------+
            elsif ( $action eq 'destroy_object_action' ) {

                my $object
                    = exists $arg_r->{object}
                    ? $self->l( $arg_r->{object} )
                    : $self->perr('object');

                my $cipux = CipUX::Object::Action::Destroy->new();

                my $return_hr = $cipux->destroy_object_action(
                    {
                        action  => $action,
                        type    => $type,
                        object  => $object,
                        attr_hr => {},
                    }
                );

                # execute additional tasks as post hook
                if ( exists $task_api{$task}{task}{post} ) {
                    $logger->debug('Execute post task');
                    $logger->debug("> object $object");
                    $logger->debug("> task $task");

                    $self->snd_task(
                        {
                            object       => $object,
                            post_task_hr => $task_api{$task}{task}{post}
                        }
                    );

                }

                # destroy_object_action return
                my $status_hr = {
                    status    => 'OK',
                    type      => 'href',
                    taskres_r => $return_hr,
                    ltarget   => 'NULL',
                };

                # if there is a doggy in cipux-task.conf we let the dog run
                if ( exists $task_api{$task}{dog}{post} ) {

                    $logger->debug('dog def exists, try exec (start)');

                    $self->exec_task_dog(
                        {
                            dog_hr       => $task_api{$task}{dog}{post},
                            object       => $object,
                            overwrite_hr => {},
                        }
                    );

                    $logger->debug('dog def exists, try exec (end)');

                }
                else {

                    $logger->debug('no dog section in cipux-task.conf');

                }

                return $status_hr;
            } ## end elsif ( $action eq 'destroy_object_action')

            # +-------------------------------------------------------------+
            # | list_object_action                                         |
            # +-------------------------------------------------------------+
            elsif ( $action eq 'list_object_action' ) {

                my $scope = 'all';

                if ( not defined( $task_api{$task}{filter} ) ) {
                    my $msg = 'The filter section in configuration file ';
                    $msg .= "is not defined. ";
                    $msg .= 'Please check that the configuration is up to';
                    $msg .= 'date and that there is a [\'filter\' => {] ';
                    $msg .= 'section in the task:';
                    $self->exc( { msg => $msg, value => $task } );
                } ## end if ( not defined( $task_api...

                my %filter = %{ $task_api{$task}{filter} };

                my $cipux = CipUX::Object::Action::List->new();

                my $return_hr = $cipux->list_object_action(
                    {
                        action    => $action,
                        type      => $type,
                        attr_hr   => {},
                        filter_hr => \%filter
                    }
                );

                #print "MODE $mode\n";
                if ( $mode eq 'shell' ) {
                    foreach my $key ( sort keys %$return_hr ) {

                        #print "$key\t".$return_hr->{$key}."\n";
                        print "$key\n";
                    }
                } ## end if ( $mode eq 'shell' )

                my $ltarget
                    = ( exists $task_api{$task}{ltarget} )
                    ? $task_api{$task}{ltarget}
                    : 'NULL';
                $logger->debug("ltarget [$ltarget]");

                # list_object_action return
                my $status_hr = {
                    status    => 'OK',
                    type      => 'href',
                    taskres_r => $return_hr,
                    ltarget   => $ltarget,
                };

                # if there is a doggy in cipux-task.conf we let the dog run
                if ( exists $task_api{$task}{dog}{post} ) {

                    $logger->debug('dog def exists, try exec (start)');

                    $self->exec_task_dog(
                        {
                            dog_hr       => $task_api{$task}{dog}{post},
                            object       => undef,
                            overwrite_hr => {},
                        }
                    );

                    $logger->debug('dog def exists, try exec (end)');

                }
                else {

                    $logger->debug('no dog section in cipux-task.conf');

                }

                return $status_hr;

            } ## end elsif ( $action eq 'list_object_action')

            # +-------------------------------------------------------------+
            # | list_object_attribute_action                               |
            # +-------------------------------------------------------------+
            elsif ($action eq 'list_object_attribute_action'
                or $action eq 'list_all_attribute_action' )
            {

                # we do need an object only for list_object_...
                # if it is not given via CLI we would
                # make a last resort to get from cipux-task.conf
                # $task_api{$task}{taskobject}
                my $object = undef;
                if ( $action eq 'list_object_attribute_action' ) {

                    $object
                        = (     exists $arg_r->{object}
                            and defined $arg_r->{object}
                            and $arg_r->{object} ne $EMPTY_STRING )
                        ? $self->l( $arg_r->{object} )
                        : ( exists $task_api{$task}{taskobject}
                            and defined $task_api{$task}{taskobject} )
                        ? $self->l( $task_api{$task}{taskobject} )
                        : $self->perr('object');

                    my $msg = 'Parameter "object" is not defined in task';
                    if ( not defined $object ) {
                        $self->exc( { msg => $msg, value => $task } );
                    }
                    $msg = 'Parameter "object" is empty in task!';
                    $msg .= ' On command line please supply -o or --object.';
                    $msg .= ' The command was:';
                    if ( $object eq $EMPTY_STRING ) {
                        $self->exc( { msg => $msg, value => $task } );
                    }
                } ## end if ( $action eq 'list_object_attribute_action')

                if ( not defined( $task_api{$task}{filter} ) ) {
                    my $msg = 'The filter section in configuration file ';
                    $msg .= "is not defined. ";
                    $msg .= 'Please check that the configuration is up to';
                    $msg .= 'date and that there is a [\'filter\' => {] ';
                    $msg .= 'section in the task:';
                    $self->exc( { msg => $msg, value => $task } );
                } ## end if ( not defined( $task_api...
                my %filter = %{ $task_api{$task}{filter} };

                if ( not defined( $task_api{$task}{target} ) ) {
                    my $msg = 'The target section in configuration file ';
                    $msg .= "is not defined. ";
                    $msg .= 'Please check that the configuration is up to';
                    $msg .= 'date and that there is a [\'target\' => {] ';
                    $msg .= 'section in the task:';
                    $self->exc( { msg => $msg, value => $task } );
                } ## end if ( not defined( $task_api...
                my %target = %{ $task_api{$task}{target} };

                my $scope = $task_api{$task}{scope};
                if ( not defined($scope) ) {
                    my $msg = "No scope defined in cfg for task";
                    $self->exc( { msg => $msg, value => $task } );
                }
                if ( $scope eq $EMPTY_STRING ) {
                    my $msg = "Empty scope in cfg for task";
                    $self->exc( { msg => $msg, value => $task } );
                }
                $logger->debug( 'scope1: ', $scope );

                my $cipux = CipUX::Object::Action::Attribute::List->new();

                my $return_hr = $cipux->list_object_attribute_action(
                    {
                        action    => $action,
                        type      => $type,
                        object    => $object,
                        scope     => $scope,
                        filter_hr => \%filter,
                        target_hr => \%target,
                        attr_hr   => $attr_hr
                    }
                ) || {};

                my $status1_hr = {
                    status    => 'OK',
                    type      => 'href',
                    taskres_r => $return_hr,
                };

                # 'taskres_r' => {
                #     'admins' => {
                #         'cn' => [
                #             'admins'
                #         ],
                #         'memberUid' => [
                #             'cipadmin',
                #             'angmer',
                #             'berta',
                #             'myadmin',
                #             'willi'
                #        ]
                #    }
                # },
                my @object = ();

                #print Dumper( \@object );

                # execute a subtask to get more data
                if (
                        exists $task_api{$task}{subtarget}
                    and defined $task_api{$task}{subtarget}
                    and ref $task_api{$task}{subtarget} eq 'HASH'
                    and exists $task_api{$task}{subfilter}
                    and defined $task_api{$task}{subfilter}
                    and ref $task_api{$task}{subfilter} eq 'HASH'

                    )
                {

                    $logger->debug('execute a subtask to get more data');
                    my @target = ();

                    # cycle over cipux_objects of targets
                    foreach my $o ( keys %{ $task_api{$task}{target} } ) {
                        foreach my $t (
                            sort
                            keys %{ $task_api{$task}{target}->{$o} }
                            )
                        {
                            $logger->debug(
                                "add target [$t] for cipux object [$o]");
                            push @target, $t;
                        }
                    }

                    foreach my $key1 ( keys %{$return_hr} ) {
                        $logger->debug("get key1 [$key1] from return_hr");
                        foreach my $key2 ( keys %{ $return_hr->{$key1} } ) {
                            $logger->debug("get key2 [$key2] from return_hr");

                            # next of not target (memberUid)
                            next if not grep { $_ =~ $key2 } @target;
                            $logger->debug("this is a target [$key2]");
                            push @object, @{ $return_hr->{$key1}->{$key2} };
                        }
                    }
                    %target    = %{ $task_api{$task}{subtarget} };
                    %filter    = %{ $task_api{$task}{subfilter} };
                    $return_hr = $cipux->list_object_attribute_action(
                        {
                            action    => $action,
                            type      => $type,
                            object    => '*',        #$object,
                            scope     => $scope,
                            filter_hr => \%filter,
                            target_hr => \%target,
                            attr_hr   => $attr_hr
                        }
                    ) || {};

                    $logger->debug('remove not apropriate id');
                    $logger->debug(
                        'positive list has ' . scalar @object . ' objects' );

                    # if we have a subtarget, we would like to delete
                    # unneeded oid
                    if ( scalar @object > 0 ) {    # sub target print and weed
                        $logger->debug('we have to filter output');
                        foreach my $id ( sort keys %{$return_hr} ) {
                            if ( grep { $_ eq $id } @object ) {
                                $logger->debug("id [$id] is OK");
                            }
                            else {
                                $logger->debug("delete id [$id]");
                                delete $return_hr->{$id};
                            }
                        }
                    }
                    else {
                        $logger->debug('we have to delete output');
                        $return_hr = {};
                    }
                }
                else {
                    $logger->debug('no subtasks executed');
                }

                #print "MODE $mode\n";
                if ( $mode eq 'shell' ) {

                    my $print_target = {};
                    foreach my $obj ( sort keys %target )
                    {    # cipux_share.group, ...
                        $logger->debug( 'object: ', $obj );
                        foreach my $attr ( sort keys %{ $target{$obj} } )
                        {    # memberUid
                            $logger->debug( 'attribute: ', $attr );
                            $print_target->{$attr} = 1;
                        }
                    } ## end foreach my $obj ( sort keys...

                    foreach my $id ( sort keys %{$return_hr} ) {
                        print $id;
                        foreach my $attr ( sort keys %{ $return_hr->{$id} } )
                        {
                            if ( $print_target->{$attr} ) {

                                #print "\t".$attr;
                                foreach my $value (
                                    @{ $return_hr->{$id}->{$attr} } )
                                {
                                    print "\t" . $value;
                                }
                            } ## end if ( $print_target->{$attr...
                        } ## end foreach my $attr ( sort keys...
                        print "\n";
                    } ## end foreach my $id ( sort keys ...

                } ## end if ( $mode eq 'shell' )

                my $ltarget
                    = ( exists $task_api{$task}{ltarget} )
                    ? $task_api{$task}{ltarget}
                    : 'NULL';
                $logger->debug("ltarget [$ltarget]");

                # list_object_attribute_action
                my $status_hr = {
                    status    => 'OK',
                    type      => 'href',
                    taskres_r => $return_hr,
                    ltarget   => $ltarget,
                };

                # if there is a doggy in cipux-task.conf we let the dog run
                if ( exists $task_api{$task}{dog}{post} ) {

                    $logger->debug('dog def exists, try exec (start)');

                    $self->exec_task_dog(
                        {
                            dog_hr       => $task_api{$task}{dog}{post},
                            object       => $object,
                            overwrite_hr => {},
                        }
                    );

                    $logger->debug('dog def exists, try exec (end)');

                }
                else {

                    $logger->debug('no dog section in cipux-task.conf');

                }

                return $status_hr;

            } ## end elsif ( $action eq 'list_object_attribute_action'...

            # +-------------------------------------------------------------+
            # | change_object_attribute_action                            |
            # +-------------------------------------------------------------+
            elsif ( $action eq 'change_object_attribute_action' ) {

                $logger->debug( ' . this is: ', $action );

                # API
                my $object
                    = exists $arg_r->{object}
                    ? $self->l( $arg_r->{object} )
                    : $self->perr('object');

                # get target value from CLI: -x value=VALUE from CLI
                my $target_value = $attr_hr->{value};

                if ( not defined $object or $object eq $EMPTY_STRING ) {
                    my $msg = 'Parameter "object" was not given or is empty';
                    $msg .= ' in task!';
                    $msg .= ' On command line please supply -o or --object.';
                    $msg .= ' The command was:';
                    $self->exc( { msg => $msg, value => $task } );
                }

                # if we get empty attr_hr and no value=X via
                # call or CLI, give up.
                if ( not defined $target_value
                    and scalar keys( %{$attr_hr} ) < 1 )
                {
                    if (
                            $mode eq 'shell'
                        and $task =~ m{^cipux_task_change_}smx
                        and $task =~ m{_password_interactive$}smx

                        )
                    {

                        my $p1 = $self->password_prompt(
                            { prompt => 'Enter new password: ' } );
                        my $p2 = $self->password_prompt(
                            { prompt => 'Enter same password again: ' } );
                        if ( $p1 eq $p2 ) {

                            $target_value = $p1;

                            #$attr_hr->{userPassword} = [$p1];
                            $attr_hr->{value} = $p1;
                        }
                        else {
                            croak '(EXCEPTION): Passwords are not equal!';
                        }

                    }
                    else {

                        my $msg = 'Parameter "value" was not given';
                        $msg .= ' in task!';
                        $msg .= ' On command line please supply';
                        $msg .= ' -x value=VALUE or';
                        $msg .= ' --mattrvalue value=VALUE.';
                        $msg .= ' The command was:';

                        $self->exc( { msg => $msg, value => $task } );
                    }
                }

                $logger->debug( '> object: ',     $object );
                $logger->debug( 'target_value: ', $target_value );

                # need filter section
                if ( not defined( $task_api{$task}{filter} ) ) {
                    my $msg = 'The filter section in configuration file ';
                    $msg .= "cfg is not defined. ";
                    $msg .= 'Please check that the configuration is up to';
                    $msg .= 'date and that there is a [\'filter\' => {} ';
                    $msg .= 'section in the task:';
                    $self->exc( { msg => $msg, value => $task } );
                } ## end if ( not defined( $task_api...
                my %filter = %{ $task_api{$task}{filter} };

                $logger->debug( 'hash filter: ',
                    { filter => \&Dumper, value => \%filter } );

                # need attr section
                if ( not defined( $task_api{$task}{target} ) ) {
                    my $msg = 'The target section in configuration file ';
                    $msg .= "cfg is not defined. ";
                    $msg .= 'Please check that the configuration is up to';
                    $msg .= 'date and that there is a [\'target\' => {] ';
                    $msg .= 'section in the task:';
                    $self->exc( { msg => $msg, value => $task } );
                } ## end if ( not defined( $task_api...
                my %target = %{ $task_api{$task}{target} };

                $logger->debug( 'hash target: ',
                    { filter => \&Dumper, value => \%target } );

                # need changes section
                my %changes = %{ $task_api{$task}{changes} };

                $logger->debug( 'hash changes: ',
                    { filter => \&Dumper, value => \%changes } );
                $logger->debug( 'hash attr_hr: ',
                    { filter => \&Dumper, value => $attr_hr } );

                # need scope
                my $scope = $task_api{$task}{scope};
                if ( not defined($scope) ) {
                    my $msg = "No scope defined in cfg for task";
                    $self->exc( { msg => $msg, value => $task } );
                }

                # check for overwrite (default values) if $value is empty
                if ( not defined $target_value ) {
                    $logger->debug('TODO');
                    $logger->debug(
                        'target value not defined, using overwrite');
                    $logger->debug( 'type: ', $type );
                    if ( defined %{ $task_api{$task}{overwrite} } ) {
                        my %overwrite = %{ $task_api{$task}{overwrite} };

                        $logger->debug(
                            'hash overwrite: ',
                            {
                                filter => \&Dumper,
                                value  => \%overwrite
                            }
                        );

                        # Example:
                        # %overwrite = (
                        #     'cipux_cat_module_object' => {
                        #         'cipuxIsEnabled' => 'TRUE'
                        #      }
                        # );
                        foreach my $o ( keys %overwrite ) {
                            $logger->debug( 'o: ', $o );
                            foreach my $k ( keys %{ $overwrite{$o} } ) {
                                $logger->debug( 'k: ', $k );
                                $attr_hr->{$k} = $overwrite{$o}->{$k};
                            }

                        } ## end foreach my $o ( keys %overwrite)
                    }
                    else {
                        $logger->debug('WARNING: empty value and overwrite!');
                    }
                } ## end if ( not defined $value)

                $logger->debug('will call change');
                $logger->debug( 'action      :', $action );
                $logger->debug( 'type        :', $type );
                $logger->debug( 'object      :', $object );
                $logger->debug( 'target_value:', $target_value );
                $logger->debug( 'attr_hr     : ',
                    { filter => \&Dumper, value => $attr_hr } );
                $logger->debug( 'scope:', $scope );
                $logger->debug( 'hash filter  : ',
                    { filter => \&Dumper, value => \%filter } );
                $logger->debug( 'hash changes: ',
                    { filter => \&Dumper, value => \%changes } );
                $logger->debug( 'hash target : ',
                    { filter => \&Dumper, value => \%target } );

                my $cipux = CipUX::Object::Action::Attribute::Change->new();

                my $return_hr = $cipux->change_object_attribute_action(
                    {
                        action     => $action,
                        type       => $type,
                        object     => $object,
                        value      => $target_value,
                        attr_hr    => $attr_hr,
                        scope      => $scope,
                        filter_hr  => \%filter,
                        changes_hr => \%changes,
                        target_hr  => \%target,
                    }
                );

             #if ( $debug > 128 and defined($return_hr) ) {
             #
             #$self->var_dump( { var_r => $return_hr, name => 'return_hr' } );
             # }
             #else {
             #    $logger->debug('did return nothing!');
             #}

                # change_object_attribute_action return
                my $status_hr = {
                    status    => 'OK',
                    type      => 'href',
                    taskres_r => $return_hr,
                    ltarget   => 'NULL',
                };

                # if there is a doggy in cipux-task.conf we let the dog run
                if ( exists $task_api{$task}{dog}{post} ) {

                    $logger->debug('dog def exists, try exec (start)');

                    $self->exec_task_dog(
                        {
                            dog_hr       => $task_api{$task}{dog}{post},
                            object       => $object,
                            overwrite_hr => {},
                        }
                    );

                    $logger->debug('dog def exists, try exec (end)');

                }
                else {

                    $logger->debug('no dog section in cipux-task.conf');

                }

                return $status_hr;

            } ## end elsif ( $action eq 'change_object_attribute_action')

            # +-------------------------------------------------------------+
            # | decision_on_object_attribute_action                       |
            # +-------------------------------------------------------------+
            elsif ( $action eq 'decision_on_object_attribute_action' ) {

                # TODO
            }
            elsif ( $action eq 'optain_attribute' ) {

            }

            else {
                my $msg = "unknown CipUX action [$action] for task:";
                $self->exc( { msg => $msg, value => $task } );
            }
        } ## end foreach my $type (@type)

        # here come task without LDAP

        if ( $action eq 'special' ) {
            my $msg = 'execute special task';
            $logger->debug( $msg . q{: }, $task );
            if ( $mode eq 'shell' ) {
                my $msg = 'This is probably not a number. ';
                $msg .= 'Please use only numbers!';
                ReadMode('normal');
                print 'Input 1st summand: ';
                my $r1 = ReadLine 0;
                my $s1 = $self->l($r1);
                if ( not looks_like_number($s1) ) {    # Scalar::Util
                    $self->exc( { msg => $msg } );
                }
                print 'Input 2nd summand: ';
                my $r2 = ReadLine 0;
                my $s2 = $self->l($r2);
                if ( not looks_like_number($s2) ) {    # Scalar::Util
                    $self->exc( { msg => $msg } );
                }
                my $sum = $s1 + $s2;
                print 'Result: ' . $sum . "\n";
                return $sum;
            }
            else {
                if ( $task eq 'cipux_task_sum' ) {
                    my $s1
                        = ref $attr_hr->{summand1} eq 'ARRAY'
                        ? $attr_hr->{summand1}->[0]
                        : $attr_hr->{summand1};
                    my $s2
                        = ref $attr_hr->{summand2} eq 'ARRAY'
                        ? $attr_hr->{summand2}->[0]
                        : $attr_hr->{summand2};

                    my $sum = $s1 + $s2;

                    # no LDAP task return
                    return {
                        status    => 'OK',
                        type      => 'aref',
                        taskres_r => [$sum],
                        ltarget   => 'NULL',
                    };
                } ## end if ( $task eq 'cipux_task_sum')
            } ## end else [ if ( $mode eq 'shell' )
        } ## end if ( $action eq 'special')
    } ## end sub task

    # +======================================================================+
    # || list_task                                                          ||
    # +======================================================================+

    sub list_task {

        # API
        my ( $self, $arg_r ) = @_;

        # +------------------------------------------------------------------+
        # | prepare
        my $logger = get_logger(__PACKAGE__);
        $logger->debug('BEGIN');

        my $cfg_task_api_hr = $task_api_cfg{ ident $self};

        my @return;

        my $cfg_hr = $cfg_task_api_hr;

        # list all object
        #        $logger->debug('cfg_hr: ', $cfg_hr  );

        foreach my $name ( sort keys %{$cfg_hr} ) {
            $logger->debug( 'task: ', $name );
            push( @return, $name );
        }

        return \@return;

    } ## end sub list_task

    # +======================================================================+
    # || exec_task_dog                                                      ||
    # +======================================================================+

    sub exec_task_dog {

        # +------------------------------------------------------------------+
        # | API
        my ( $self, $arg_r ) = @_;

        my $object
            = exists $arg_r->{object}
            ? $self->l( $arg_r->{object} )
            : $self->perr('object');

        my $dog_hr
            = exists $arg_r->{dog_hr}
            ? $self->h( $arg_r->{dog_hr} )
            : $self->perr('dog_hr');

        my $overwrite_hr
            = exists $arg_r->{overwrite_hr}
            ? $self->h( $arg_r->{overwrite_hr} )
            : $self->perr('overwrite_hr');

        my $logger = get_logger(__PACKAGE__);
        $logger->debug('Check if CipUX::Dog is installed ... ');

        # if CipUX::Dog is installed, we use it
        eval { require CipUX::Dog; };

        if ( not $EVAL_ERROR ) {

            $logger->debug('... CipUX::Dog is installed');
            my $dog = CipUX::Dog->new(
                {
                    dog_hr       => $dog_hr,
                    object       => $object,
                    overwrite_hr => $overwrite_hr,
                }
            );

            $logger->debug('execute the dog');

            $dog->bite();    # exec files system command

        }
        else {

            $logger->debug(
                '... no, CipUX::Dog not installed. Will not run the dog.');
        }

        return;

    }

    sub snd_task {

        # +------------------------------------------------------------------+
        # | API
        my ( $self, $arg_r ) = @_;

        my $object
            = exists $arg_r->{object}
            ? $self->l( $arg_r->{object} )
            : $self->perr('object');

        my $post_task_hr
            = exists $arg_r->{post_task_hr}
            ? $self->h( $arg_r->{post_task_hr} )
            : $self->perr('post_task_hr');

        my $logger = get_logger(__PACKAGE__);
        $logger->debug("object: $object");
        $logger->debug( 'post_task_hr: ',
            { filter => \&Dumper, value => $post_task_hr } );

        # +------------------------------------------------------------------+
        # | main
        # 'task'   => {
        #     'post' => {
        #         'cipux_task_add_member_to_role_account' => {
        #             'mode' => 'exception',
        #             'attr_hr' => {
        #                 object => "$m",          # role
        #                 value  => '@object@',    # member
        #             },
        #         },
        #     },
        # },

        my $return_hr = {};
        my %post      = %{$post_task_hr};

        $logger->debug( 'post: ', { filter => \&Dumper, value => \%post } );

        foreach my $task ( sort keys %post ) {

            my $attr_hr = $post{$task}->{attr_hr};

            # fill in the objetcs
            foreach my $key ( sort keys %{$attr_hr} ) {
                my $value = $attr_hr->{$key};
                $logger->debug("attr_hr before '$key'=>'$value'");
                $value =~ s/\@object\@/$object/gsmx;
                $logger->debug("attr_hr after '$key'=>'$value'");
                $attr_hr->{$key} = $value;
            }

            # for all post tasks
            $logger->debug("task: $task");
            $logger->debug("object: $object");
            $logger->debug( 'attr_hr',
                { filter => \&Dumper, value => $attr_hr } );

            my $return_r = $self->task(
                {
                    script  => __PACKAGE__,
                    task    => $task,
                    mode    => 'rpc',
                    object  => $attr_hr->{object},
                    attr_hr => $attr_hr,
                }
            );
            if ( $return_r->{status} eq 'OK' ) {
                $logger->debug('2nd task return OK');
            }
            else {
                $logger->debug('2nd task return FALSE');
            }
            $return_hr->{$task} = $return_r;

        }
        return $return_hr;
    }

}    # END INSIDE-OUT CLASS

1;

=pod

=head1 NAME

CipUX::Task - Task layer class for CipUX

=head1 VERSION

version 3.4.0.7


=head1 SYNOPSIS

  use CipUX::Task;

=head1 DESCRIPTION

Provides the functions for the XML-RPC daemon and the CipUX shell commands.

=head1 ABSTRACT

The CipUX task library combines the CipUX LDAP objects and the file system.

=head1 SUBROUTINES/METHODS

The following functions will be exported by CipUX::Task.

=head2 new

Constructor

B<Syntax:>

  my $cipux_task = CipUX::Task->new();
  my $cipux_task = CipUX::Task->new( { pref=>cipux-task.cfgperl } );


B<Description:>

I<pref>

Configuration files may be provided for convenience but is not needed. If no
configuration file was provided the default configuration file will be loaded.
This is meant to work in a single server scenario and multi server settings.

=head2 list_task

List CipUX Task Library commands.

B<Syntax:>

 $cipux->list_task({ });

=head1 DIAGNOSTICS

TODO

=head1 CONFIGURATION AND ENVIRONMENT

TODO

=head1 DEPENDENCIES

Carp
Class::Std
CipUX::Object::Action::Create
CipUX::Object::Action::Destroy
CipUX::Object::Action::List
CipUX::Object::Action::Attribute::List
CipUX::Object::Action::Attribute::Change
Data::Dumper
English
Log::Log4perl
Readonly
Scalar::Util
Term::ReadKey


=head1 INCOMPATIBILITIES

Not known.

=head1 BUGS AND LIMITATIONS

Not known.

=head1 SEE ALSO

See the CipUX webpage and the manual at L<http://www.cipux.org>

See the mailing list L<http://sympa.cipworx.org/wws/info/cipux-devel>

=head1 AUTHOR

Christian Kuelker  E<lt>christian.kuelker@cipworx.orgE<gt>

=head1 LICENSE AND COPYRIGHT

Copyright (C) 1999 - 2009 by Christian Kuelker

This program 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, or (at
your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA

=cut
