<commit_before># --
# Kernel/Modules/AdminProcessManagement.pm - process management
# Copyright (C) 2001-2015 OTRS AG, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Modules::AdminProcessManagement;
## nofilter(TidyAll::Plugin::OTRS::Perl::Dumper)

use strict;
use warnings;
use Data::Dumper;

use Kernel::System::YAML;

use Kernel::System::JSON;
use Kernel::System::DynamicField;
use Kernel::System::ProcessManagement::DB::Entity;
use Kernel::System::ProcessManagement::DB::Activity;
use Kernel::System::ProcessManagement::DB::ActivityDialog;
use Kernel::System::ProcessManagement::DB::Process;
use Kernel::System::ProcessManagement::DB::Process::State;
use Kernel::System::ProcessManagement::DB::Transition;
use Kernel::System::ProcessManagement::DB::TransitionAction;

use Kernel::System::VariableCheck qw(:all);

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {%Param};
    bless( $Self, $Type );

    # check all needed objects
    for my $Needed (
        qw(ParamObject DBObject LayoutObject ConfigObject LogObject MainObject EncodeObject)
        )
    {
        if ( !$Self->{$Needed} ) {
            $Self->{LayoutObject}->FatalError( Message => "Got no $Needed!" );
        }
    }

    # create additional objects
    $Self->{JSONObject}         = Kernel::System::JSON->new( %{$Self} );
    $Self->{DynamicFieldObject} = Kernel::System::DynamicField->new( %{$Self} );
    $Self->{YAMLObject}         = Kernel::System::YAML->new( %{$Self} );
    $Self->{ProcessObject}      = Kernel::System::ProcessManagement::DB::Process->new( %{$Self} );
    $Self->{EntityObject}       = Kernel::System::ProcessManagement::DB::Entity->new( %{$Self} );
    $Self->{ActivityObject}     = Kernel::System::ProcessManagement::DB::Activity->new( %{$Self} );

    $Self->{ActivityDialogObject} = Kernel::System::ProcessManagement::DB::ActivityDialog->new( %{$Self} );

    $Self->{StateObject} = Kernel::System::ProcessManagement::DB::Process::State->new( %{$Self} );

    $Self->{TransitionObject} = Kernel::System::ProcessManagement::DB::Transition->new( %{$Self} );

    $Self->{TransitionActionObject} = Kernel::System::ProcessManagement::DB::TransitionAction->new( %{$Self} );

    return $Self;
}

sub Run {
    my ( $Self, %Param ) = @_;

    $Self->{Subaction} = $Self->{ParamObject}->GetParam( Param => 'Subaction' ) || '';

    my $ProcessID = $Self->{ParamObject}->GetParam( Param => 'ID' )       || '';
    my $EntityID  = $Self->{ParamObject}->GetParam( Param => 'EntityID' ) || '';

    # get the list of updated or deleted entities
    my $EntitySyncStateList = $Self->{EntityObject}->EntitySyncStateList(
        UserID => $Self->{UserID}
    );

    my $SynchronizeMessage
        = 'Process Management information from database is not in sync with the system configuration, please synchronize all processes.';

    if ( IsArrayRefWithData($EntitySyncStateList) ) {

        # create a notification if system is not up to date
        $Param{NotifyData} = [
            {
                Info => $SynchronizeMessage,
            },
        ];
    }

    # ------------------------------------------------------------ #
    # ProcessImport
    # ------------------------------------------------------------ #
    if ( $Self->{Subaction} eq 'ProcessImport' ) {

        # challenge token check for write action
        $Self->{LayoutObject}->ChallengeTokenCheck();

        my $FormID = $Self->{ParamObject}->GetParam( Param => 'FormID' ) || '';
        my %UploadStuff = $Self->{ParamObject}->GetUploadAll(
            Param => 'FileUpload',
        );

        my $OverwriteExistingEntities = $Self->{ParamObject}->GetParam( Param => 'OverwriteExistingEntities' );

        # import the process YAML file
        my %ProcessImport = $Self->{ProcessObject}->ProcessImport(
            Content                   => $UploadStuff{Content},
            OverwriteExistingEntities => $OverwriteExistingEntities,
            UserID                    => $Self->{UserID},
        );

        if ( !$ProcessImport{Success} ) {

            # show the error screen
            return $Self->{LayoutObject}->ErrorScreen(
                Message => $ProcessImport{Message},
                Comment => $ProcessImport{Comment} || '',
            );
        }
        else {

            # show the overview with success informations
            $Param{NotifyData} = [
                {
                    Info => $ProcessImport{Message},
                },
                {
                    Info => $SynchronizeMessage,
                },
            ];

            return $Self->_ShowOverview(
                %Param,
            );
        }
    }

    # ------------------------------------------------------------ #
    # ProcessExport
    # ------------------------------------------------------------ #
    elsif ( $Self->{Subaction} eq 'ProcessExport' ) {

        # check for ProcessID
        my $ProcessID = $Self->{ParamObject}->GetParam( Param => 'ID' ) || '';
        if ( !$ProcessID ) {
            return $Self->{LayoutObject}->ErrorScreen(
                Message => "Need ProcessID!",
            );
        }

        my $ProcessData = $Self->_GetProcessData(
            ID => $ProcessID
        );

        # convert the processdata hash to string
        my $ProcessDataYAML = $Self->{YAMLObject}->Dump( Data => $ProcessData );

        # send the result to the browser
        return $Self->{LayoutObject}->Attachment(
            ContentType => 'text/html; charset=' . $Self->{LayoutObject}->{Charset},
            Content     => $ProcessDataYAML,
            Type        => 'attachment',
            Filename    => 'Export_ProcessEntityID_' . $ProcessData->{Process}->{EntityID} . '.yml',
            NoCache     => 1,
        );
    }

    # ------------------------------------------------------------ #
    # ProcessPrint
    # ------------------------------------------------------------ #
    elsif ( $Self->{Subaction} eq 'ProcessPrint' ) {

        # we need to use Data::Dumper with custom Indent
        my $Indent = $Data::Dumper::Indent;
        $Data::Dumper::Indent = 1;

        # check for ProcessID
        my $ProcessID = $Self->{ParamObject}->GetParam( Param => 'ID' ) || '';
        if ( !$ProcessID ) {
            return $Self->{LayoutObject}->ErrorScreen(
                Message => "Need ProcessID!",
            );
        }

        my $BooleanMapping = {
            0 => 'No',
            1 => 'Yes',
            2 => 'Yes (mandatory)',
        };

        my $ProcessData = $Self->_GetProcessData(
            ID => $ProcessID
        );

        my $Output = $Self->{LayoutObject}->Header(
            Value => $Param{Title},
            Type  => 'Small',
        );

        # print all activities
        if ( $ProcessData->{Activities} && %{ $ProcessData->{Activities} } ) {

            for my $ActivityEntityID ( sort keys %{ $ProcessData->{Activities} } ) {

                $Self->{LayoutObject}->Block(
                    Name => 'ActivityRow',
                    Data => {
                        %{ $ProcessData->{Activities}->{$ActivityEntityID} },
                        DialogCount =>
                            scalar
                            @{ $ProcessData->{Activities}->{$ActivityEntityID}->{ActivityDialogs} },
                    },
                );

                # list all assigned dialogs
                my $AssignedDialogs = $ProcessData->{Activities}->{$ActivityEntityID}->{Config}->{ActivityDialog};
                if ( $AssignedDialogs && %{$AssignedDialogs} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'AssignedDialogs',
                    );

                    for my $AssignedDialog ( sort keys %{$AssignedDialogs} ) {

                        my $AssignedDialogEntityID = $ProcessData->{Activities}->{$ActivityEntityID}->{Config}
                            ->{ActivityDialog}->{$AssignedDialog};

                        $Self->{LayoutObject}->Block(
                            Name => 'AssignedDialogsRow',
                            Data => {
                                Name => $ProcessData->{ActivityDialogs}->{$AssignedDialogEntityID}
                                    ->{Name},
                                EntityID => $AssignedDialogEntityID,
                            },
                        );
                    }
                }
            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'ActivityRowEmpty',
            );
        }

        # print all activity dialogs
        if ( $ProcessData->{ActivityDialogs} && %{ $ProcessData->{ActivityDialogs} } ) {

            for my $ActivityDialogEntityID ( sort keys %{ $ProcessData->{ActivityDialogs} } ) {

                $Self->{LayoutObject}->Block(
                    Name => 'ActivityDialogRow',
                    Data => {
                        ShownIn => join(
                            ', ',
                            @{
                                $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}
                                    ->{Config}->{Interface}
                                }
                        ),
                        %{ $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID} },
                    },
                );

                for my $ElementAttribute (
                    qw(DescriptionShort DescriptionLong SubmitButtonText SubmitAdviceText Permission RequiredLock)
                    )
                {

                    my $Value = $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}->{Config}
                        ->{$ElementAttribute};

                    if ( defined $Value ) {

                        if ( $ElementAttribute eq 'RequiredLock' ) {
                            $Value = $BooleanMapping->{$Value};
                        }

                        $Self->{LayoutObject}->Block(
                            Name => 'ElementAttribute',
                            Data => {
                                Key   => $ElementAttribute,
                                Value => $Value,
                            },
                        );
                    }
                }

                # list all assigned fields
                my $AssignedFields = $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}->{Config}
                    ->{FieldOrder};
                if ( $AssignedFields && @{$AssignedFields} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'AssignedFields',
                    );

                    for my $AssignedField ( @{$AssignedFields} ) {

                        $Self->{LayoutObject}->Block(
                            Name => 'AssignedFieldsRow',
                            Data => {
                                Name => $AssignedField,
                            },
                        );

                        my %Values = %{
                            $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}
                                ->{Config}->{Fields}->{$AssignedField}
                        };
                        if ( $Values{Config} ) {
                            $Values{Config} = Dumper( $Values{Config} );    ## no critic
                            $Values{Config} =~ s{ \s* \$VAR1 \s* =}{}xms;
                            $Values{Config} =~ s{\s+\{}{\{}xms;
                        }

                        for my $Key ( sort keys %Values ) {

                            if ( $Key eq 'Display' ) {
                                $Values{$Key} = $BooleanMapping->{ $Values{$Key} };
                            }

                            if ( $Values{$Key} ) {
                                $Self->{LayoutObject}->Block(
                                    Name => 'AssignedFieldsRowValue',
                                    Data => {
                                        Key   => $Key,
                                        Value => $Values{$Key},
                                    },
                                );
                            }
                        }
                    }
                }
            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'ActivityDialogRowEmpty',
            );
        }

        # print all transitions
        if ( $ProcessData->{Transitions} && %{ $ProcessData->{Transitions} } ) {

            for my $TransitionEntityID ( sort keys %{ $ProcessData->{Transitions} } ) {

                # list config
                my $Config = $ProcessData->{Transitions}->{$TransitionEntityID}->{Config};

                $Self->{LayoutObject}->Block(
                    Name => 'TransitionRow',
                    Data => {
                        %{ $ProcessData->{Transitions}->{$TransitionEntityID} },
                        ConditionLinking => $Config->{ConditionLinking},
                    },
                );

                if ( $Config && %{$Config} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'Condition',
                    );

                    for my $Condition ( sort keys %{ $Config->{Condition} } ) {

                        $Self->{LayoutObject}->Block(
                            Name => 'ConditionRow',
                            Data => {
                                Name => $Condition,
                            },
                        );

                        my %Values = %{ $Config->{Condition}->{$Condition} };

                        for my $Key ( sort keys %Values ) {

                            if ( $Values{$Key} ) {

                                if ( ref $Values{$Key} eq 'HASH' ) {

                                    $Self->{LayoutObject}->Block(
                                        Name => 'ConditionRowSub',
                                        Data => {
                                            NameSub => $Key,
                                        },
                                    );

                                    for my $SubKey ( sort keys %{ $Values{$Key} } ) {

                                        if ( ref $Values{$Key}->{$SubKey} eq 'HASH' ) {

                                            $Self->{LayoutObject}->Block(
                                                Name => 'ConditionRowSubSub',
                                                Data => {
                                                    NameSubSub => $SubKey,
                                                },
                                            );

                                            for my $SubSubKey (
                                                sort keys %{ $Values{$Key}->{$SubKey} }
                                                )
                                            {

                                                $Self->{LayoutObject}->Block(
                                                    Name => 'ConditionRowSubSubValue',
                                                    Data => {
                                                        Key => $SubSubKey,
                                                        Value =>
                                                            $Values{$Key}->{$SubKey}->{$SubSubKey},
                                                    },
                                                );
                                            }
                                        }
                                        else {

                                            $Self->{LayoutObject}->Block(
                                                Name => 'ConditionRowSubValue',
                                                Data => {
                                                    Key   => $SubKey,
                                                    Value => $Values{$Key}->{$SubKey},
                                                },
                                            );
                                        }
                                    }
                                }
                                else {

                                    $Self->{LayoutObject}->Block(
                                        Name => 'ConditionRowValue',
                                        Data => {
                                            Key   => $Key,
                                            Value => $Values{$Key},
                                        },
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'TransitionRowEmpty',
            );
        }

        # print all transition actions
        if ( $ProcessData->{TransitionActions} && %{ $ProcessData->{TransitionActions} } ) {

            for my $TransitionActionEntityID ( sort keys %{ $ProcessData->{TransitionActions} } ) {

                $Self->{LayoutObject}->Block(
                    Name => 'TransitionActionRow',
                    Data => {
                        Module => $ProcessData->{TransitionActions}->{$TransitionActionEntityID}
                            ->{Config}->{Module},
                        %{ $ProcessData->{TransitionActions}->{$TransitionActionEntityID} },
                    },
                );

                # list config
                my $Config = $ProcessData->{TransitionActions}->{$TransitionActionEntityID}->{Config}
                    ->{Config};
                if ( $Config && %{$Config} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'Config',
                    );

                    CONFIGITEM:
                    for my $ConfigItem ( sort keys %{$Config} ) {

                        next CONFIGITEM if !$ConfigItem;

                        $Self->{LayoutObject}->Block(
                            Name => 'ConfigRow',
                            Data => {
                                Name  => $ConfigItem,
                                Value => $Config->{$ConfigItem},
                            },
                        );
                    }
                }

            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'TransitionActionRowEmpty',
            );
        }

        # get logo
        my $Logo = $Self->{ConfigObject}->Get('AgentLogo');
        if ( $Logo && %{$Logo} ) {
            $Self->{LayoutObject}->Block(
                Name => 'Logo',
                Data => {
                    LogoURL => $Param{LogoURL} = $Self->{ConfigObject}->Get('Frontend::WebPath') . $Logo->{URL},
                },
            );
        }

        # collect path information
        my @Path;
        push @Path, $ProcessData->{Process}->{Config}->{StartActivity};

        ACTIVITY:
        for my $Activity ( @{ $ProcessData->{Process}->{Activities} } ) {
            next ACTIVITY if $Activity eq $ProcessData->{Process}->{Config}->{StartActivity};
            push @Path, $Activity;
        }

        for my $Activity (@Path) {

            for my $Transition (
                sort keys %{ $ProcessData->{Process}->{Config}->{Path}->{$Activity} }
                )
            {
                my $TransitionActionString;
                if (
                    $ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
                    ->{TransitionAction}
                    && @{
                        $ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}<commit_msg>Fixed wrong logo in process print.<commit_after># --
# Kernel/Modules/AdminProcessManagement.pm - process management
# Copyright (C) 2001-2015 OTRS AG, http://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Modules::AdminProcessManagement;
## nofilter(TidyAll::Plugin::OTRS::Perl::Dumper)

use strict;
use warnings;
use Data::Dumper;

use Kernel::System::YAML;

use Kernel::System::JSON;
use Kernel::System::DynamicField;
use Kernel::System::ProcessManagement::DB::Entity;
use Kernel::System::ProcessManagement::DB::Activity;
use Kernel::System::ProcessManagement::DB::ActivityDialog;
use Kernel::System::ProcessManagement::DB::Process;
use Kernel::System::ProcessManagement::DB::Process::State;
use Kernel::System::ProcessManagement::DB::Transition;
use Kernel::System::ProcessManagement::DB::TransitionAction;

use Kernel::System::VariableCheck qw(:all);

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {%Param};
    bless( $Self, $Type );

    # check all needed objects
    for my $Needed (
        qw(ParamObject DBObject LayoutObject ConfigObject LogObject MainObject EncodeObject)
        )
    {
        if ( !$Self->{$Needed} ) {
            $Self->{LayoutObject}->FatalError( Message => "Got no $Needed!" );
        }
    }

    # create additional objects
    $Self->{JSONObject}         = Kernel::System::JSON->new( %{$Self} );
    $Self->{DynamicFieldObject} = Kernel::System::DynamicField->new( %{$Self} );
    $Self->{YAMLObject}         = Kernel::System::YAML->new( %{$Self} );
    $Self->{ProcessObject}      = Kernel::System::ProcessManagement::DB::Process->new( %{$Self} );
    $Self->{EntityObject}       = Kernel::System::ProcessManagement::DB::Entity->new( %{$Self} );
    $Self->{ActivityObject}     = Kernel::System::ProcessManagement::DB::Activity->new( %{$Self} );

    $Self->{ActivityDialogObject} = Kernel::System::ProcessManagement::DB::ActivityDialog->new( %{$Self} );

    $Self->{StateObject} = Kernel::System::ProcessManagement::DB::Process::State->new( %{$Self} );

    $Self->{TransitionObject} = Kernel::System::ProcessManagement::DB::Transition->new( %{$Self} );

    $Self->{TransitionActionObject} = Kernel::System::ProcessManagement::DB::TransitionAction->new( %{$Self} );

    return $Self;
}

sub Run {
    my ( $Self, %Param ) = @_;

    $Self->{Subaction} = $Self->{ParamObject}->GetParam( Param => 'Subaction' ) || '';

    my $ProcessID = $Self->{ParamObject}->GetParam( Param => 'ID' )       || '';
    my $EntityID  = $Self->{ParamObject}->GetParam( Param => 'EntityID' ) || '';

    # get the list of updated or deleted entities
    my $EntitySyncStateList = $Self->{EntityObject}->EntitySyncStateList(
        UserID => $Self->{UserID}
    );

    my $SynchronizeMessage
        = 'Process Management information from database is not in sync with the system configuration, please synchronize all processes.';

    if ( IsArrayRefWithData($EntitySyncStateList) ) {

        # create a notification if system is not up to date
        $Param{NotifyData} = [
            {
                Info => $SynchronizeMessage,
            },
        ];
    }

    # ------------------------------------------------------------ #
    # ProcessImport
    # ------------------------------------------------------------ #
    if ( $Self->{Subaction} eq 'ProcessImport' ) {

        # challenge token check for write action
        $Self->{LayoutObject}->ChallengeTokenCheck();

        my $FormID = $Self->{ParamObject}->GetParam( Param => 'FormID' ) || '';
        my %UploadStuff = $Self->{ParamObject}->GetUploadAll(
            Param => 'FileUpload',
        );

        my $OverwriteExistingEntities = $Self->{ParamObject}->GetParam( Param => 'OverwriteExistingEntities' );

        # import the process YAML file
        my %ProcessImport = $Self->{ProcessObject}->ProcessImport(
            Content                   => $UploadStuff{Content},
            OverwriteExistingEntities => $OverwriteExistingEntities,
            UserID                    => $Self->{UserID},
        );

        if ( !$ProcessImport{Success} ) {

            # show the error screen
            return $Self->{LayoutObject}->ErrorScreen(
                Message => $ProcessImport{Message},
                Comment => $ProcessImport{Comment} || '',
            );
        }
        else {

            # show the overview with success informations
            $Param{NotifyData} = [
                {
                    Info => $ProcessImport{Message},
                },
                {
                    Info => $SynchronizeMessage,
                },
            ];

            return $Self->_ShowOverview(
                %Param,
            );
        }
    }

    # ------------------------------------------------------------ #
    # ProcessExport
    # ------------------------------------------------------------ #
    elsif ( $Self->{Subaction} eq 'ProcessExport' ) {

        # check for ProcessID
        my $ProcessID = $Self->{ParamObject}->GetParam( Param => 'ID' ) || '';
        if ( !$ProcessID ) {
            return $Self->{LayoutObject}->ErrorScreen(
                Message => "Need ProcessID!",
            );
        }

        my $ProcessData = $Self->_GetProcessData(
            ID => $ProcessID
        );

        # convert the processdata hash to string
        my $ProcessDataYAML = $Self->{YAMLObject}->Dump( Data => $ProcessData );

        # send the result to the browser
        return $Self->{LayoutObject}->Attachment(
            ContentType => 'text/html; charset=' . $Self->{LayoutObject}->{Charset},
            Content     => $ProcessDataYAML,
            Type        => 'attachment',
            Filename    => 'Export_ProcessEntityID_' . $ProcessData->{Process}->{EntityID} . '.yml',
            NoCache     => 1,
        );
    }

    # ------------------------------------------------------------ #
    # ProcessPrint
    # ------------------------------------------------------------ #
    elsif ( $Self->{Subaction} eq 'ProcessPrint' ) {

        # we need to use Data::Dumper with custom Indent
        my $Indent = $Data::Dumper::Indent;
        $Data::Dumper::Indent = 1;

        # check for ProcessID
        my $ProcessID = $Self->{ParamObject}->GetParam( Param => 'ID' ) || '';
        if ( !$ProcessID ) {
            return $Self->{LayoutObject}->ErrorScreen(
                Message => "Need ProcessID!",
            );
        }

        my $BooleanMapping = {
            0 => 'No',
            1 => 'Yes',
            2 => 'Yes (mandatory)',
        };

        my $ProcessData = $Self->_GetProcessData(
            ID => $ProcessID
        );

        my $Output = $Self->{LayoutObject}->Header(
            Value => $Param{Title},
            Type  => 'Small',
        );

        # print all activities
        if ( $ProcessData->{Activities} && %{ $ProcessData->{Activities} } ) {

            for my $ActivityEntityID ( sort keys %{ $ProcessData->{Activities} } ) {

                $Self->{LayoutObject}->Block(
                    Name => 'ActivityRow',
                    Data => {
                        %{ $ProcessData->{Activities}->{$ActivityEntityID} },
                        DialogCount =>
                            scalar
                            @{ $ProcessData->{Activities}->{$ActivityEntityID}->{ActivityDialogs} },
                    },
                );

                # list all assigned dialogs
                my $AssignedDialogs = $ProcessData->{Activities}->{$ActivityEntityID}->{Config}->{ActivityDialog};
                if ( $AssignedDialogs && %{$AssignedDialogs} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'AssignedDialogs',
                    );

                    for my $AssignedDialog ( sort keys %{$AssignedDialogs} ) {

                        my $AssignedDialogEntityID = $ProcessData->{Activities}->{$ActivityEntityID}->{Config}
                            ->{ActivityDialog}->{$AssignedDialog};

                        $Self->{LayoutObject}->Block(
                            Name => 'AssignedDialogsRow',
                            Data => {
                                Name => $ProcessData->{ActivityDialogs}->{$AssignedDialogEntityID}
                                    ->{Name},
                                EntityID => $AssignedDialogEntityID,
                            },
                        );
                    }
                }
            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'ActivityRowEmpty',
            );
        }

        # print all activity dialogs
        if ( $ProcessData->{ActivityDialogs} && %{ $ProcessData->{ActivityDialogs} } ) {

            for my $ActivityDialogEntityID ( sort keys %{ $ProcessData->{ActivityDialogs} } ) {

                $Self->{LayoutObject}->Block(
                    Name => 'ActivityDialogRow',
                    Data => {
                        ShownIn => join(
                            ', ',
                            @{
                                $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}
                                    ->{Config}->{Interface}
                                }
                        ),
                        %{ $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID} },
                    },
                );

                for my $ElementAttribute (
                    qw(DescriptionShort DescriptionLong SubmitButtonText SubmitAdviceText Permission RequiredLock)
                    )
                {

                    my $Value = $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}->{Config}
                        ->{$ElementAttribute};

                    if ( defined $Value ) {

                        if ( $ElementAttribute eq 'RequiredLock' ) {
                            $Value = $BooleanMapping->{$Value};
                        }

                        $Self->{LayoutObject}->Block(
                            Name => 'ElementAttribute',
                            Data => {
                                Key   => $ElementAttribute,
                                Value => $Value,
                            },
                        );
                    }
                }

                # list all assigned fields
                my $AssignedFields = $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}->{Config}
                    ->{FieldOrder};
                if ( $AssignedFields && @{$AssignedFields} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'AssignedFields',
                    );

                    for my $AssignedField ( @{$AssignedFields} ) {

                        $Self->{LayoutObject}->Block(
                            Name => 'AssignedFieldsRow',
                            Data => {
                                Name => $AssignedField,
                            },
                        );

                        my %Values = %{
                            $ProcessData->{ActivityDialogs}->{$ActivityDialogEntityID}
                                ->{Config}->{Fields}->{$AssignedField}
                        };
                        if ( $Values{Config} ) {
                            $Values{Config} = Dumper( $Values{Config} );    ## no critic
                            $Values{Config} =~ s{ \s* \$VAR1 \s* =}{}xms;
                            $Values{Config} =~ s{\s+\{}{\{}xms;
                        }

                        for my $Key ( sort keys %Values ) {

                            if ( $Key eq 'Display' ) {
                                $Values{$Key} = $BooleanMapping->{ $Values{$Key} };
                            }

                            if ( $Values{$Key} ) {
                                $Self->{LayoutObject}->Block(
                                    Name => 'AssignedFieldsRowValue',
                                    Data => {
                                        Key   => $Key,
                                        Value => $Values{$Key},
                                    },
                                );
                            }
                        }
                    }
                }
            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'ActivityDialogRowEmpty',
            );
        }

        # print all transitions
        if ( $ProcessData->{Transitions} && %{ $ProcessData->{Transitions} } ) {

            for my $TransitionEntityID ( sort keys %{ $ProcessData->{Transitions} } ) {

                # list config
                my $Config = $ProcessData->{Transitions}->{$TransitionEntityID}->{Config};

                $Self->{LayoutObject}->Block(
                    Name => 'TransitionRow',
                    Data => {
                        %{ $ProcessData->{Transitions}->{$TransitionEntityID} },
                        ConditionLinking => $Config->{ConditionLinking},
                    },
                );

                if ( $Config && %{$Config} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'Condition',
                    );

                    for my $Condition ( sort keys %{ $Config->{Condition} } ) {

                        $Self->{LayoutObject}->Block(
                            Name => 'ConditionRow',
                            Data => {
                                Name => $Condition,
                            },
                        );

                        my %Values = %{ $Config->{Condition}->{$Condition} };

                        for my $Key ( sort keys %Values ) {

                            if ( $Values{$Key} ) {

                                if ( ref $Values{$Key} eq 'HASH' ) {

                                    $Self->{LayoutObject}->Block(
                                        Name => 'ConditionRowSub',
                                        Data => {
                                            NameSub => $Key,
                                        },
                                    );

                                    for my $SubKey ( sort keys %{ $Values{$Key} } ) {

                                        if ( ref $Values{$Key}->{$SubKey} eq 'HASH' ) {

                                            $Self->{LayoutObject}->Block(
                                                Name => 'ConditionRowSubSub',
                                                Data => {
                                                    NameSubSub => $SubKey,
                                                },
                                            );

                                            for my $SubSubKey (
                                                sort keys %{ $Values{$Key}->{$SubKey} }
                                                )
                                            {

                                                $Self->{LayoutObject}->Block(
                                                    Name => 'ConditionRowSubSubValue',
                                                    Data => {
                                                        Key => $SubSubKey,
                                                        Value =>
                                                            $Values{$Key}->{$SubKey}->{$SubSubKey},
                                                    },
                                                );
                                            }
                                        }
                                        else {

                                            $Self->{LayoutObject}->Block(
                                                Name => 'ConditionRowSubValue',
                                                Data => {
                                                    Key   => $SubKey,
                                                    Value => $Values{$Key}->{$SubKey},
                                                },
                                            );
                                        }
                                    }
                                }
                                else {

                                    $Self->{LayoutObject}->Block(
                                        Name => 'ConditionRowValue',
                                        Data => {
                                            Key   => $Key,
                                            Value => $Values{$Key},
                                        },
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'TransitionRowEmpty',
            );
        }

        # print all transition actions
        if ( $ProcessData->{TransitionActions} && %{ $ProcessData->{TransitionActions} } ) {

            for my $TransitionActionEntityID ( sort keys %{ $ProcessData->{TransitionActions} } ) {

                $Self->{LayoutObject}->Block(
                    Name => 'TransitionActionRow',
                    Data => {
                        Module => $ProcessData->{TransitionActions}->{$TransitionActionEntityID}
                            ->{Config}->{Module},
                        %{ $ProcessData->{TransitionActions}->{$TransitionActionEntityID} },
                    },
                );

                # list config
                my $Config = $ProcessData->{TransitionActions}->{$TransitionActionEntityID}->{Config}
                    ->{Config};
                if ( $Config && %{$Config} ) {

                    $Self->{LayoutObject}->Block(
                        Name => 'Config',
                    );

                    CONFIGITEM:
                    for my $ConfigItem ( sort keys %{$Config} ) {

                        next CONFIGITEM if !$ConfigItem;

                        $Self->{LayoutObject}->Block(
                            Name => 'ConfigRow',
                            Data => {
                                Name  => $ConfigItem,
                                Value => $Config->{$ConfigItem},
                            },
                        );
                    }
                }

            }
        }
        else {
            $Self->{LayoutObject}->Block(
                Name => 'TransitionActionRowEmpty',
            );
        }

        # determine skin for selection of the correct logo
        # 1. use UserSkin setting from Agent preferences, if available
        # 2. use HostBased skin setting, if available
        # 3. use default skin from configuration

        my $SkinSelectedHostBased;
        my $DefaultSkinHostBased = $Self->{ConfigObject}->Get('Loader::Agent::DefaultSelectedSkin::HostBased');
        if ( $DefaultSkinHostBased && $ENV{HTTP_HOST} ) {
            REGEXP:
            for my $RegExp ( sort keys %{$DefaultSkinHostBased} ) {

                # do not use empty regexp or skin directories
                next REGEXP if !$RegExp;
                next REGEXP if !$DefaultSkinHostBased->{$RegExp};

                # check if regexp is matching
                if ( $ENV{HTTP_HOST} =~ /$RegExp/i ) {
                    $SkinSelectedHostBased = $DefaultSkinHostBased->{$RegExp};
                }
            }
        }

        my $SkinSelected = $Self->{'UserSkin'}
            || $SkinSelectedHostBased
            || $Self->{ConfigObject}->Get('Loader::Agent::DefaultSelectedSkin')
            || 'default';

        my %AgentLogo;

        # check if we need to display a custom logo for the selected skin
        my $AgentLogoCustom = $Self->{ConfigObject}->Get('AgentLogoCustom');
        if (
            $SkinSelected
            && $AgentLogoCustom
            && IsHashRefWithData($AgentLogoCustom)
            && $AgentLogoCustom->{ $SkinSelected }
            )
        {
            %AgentLogo = %{ $AgentLogoCustom->{ $SkinSelected } };
        }

        # Otherwise show default header logo, if configured
        elsif ( defined $Self->{ConfigObject}->Get('AgentLogo') ) {
            %AgentLogo = %{ $Self->{ConfigObject}->Get('AgentLogo') };
        }

        # get logo
        if ( $AgentLogo{URL} ) {
            $Self->{LayoutObject}->Block(
                Name => 'Logo',
                Data => {
                    LogoURL => $Self->{ConfigObject}->Get('Frontend::WebPath') . $AgentLogo{URL},
                },
            );
        }

        # collect path information
        my @Path;
        push @Path, $ProcessData->{Process}->{Config}->{StartActivity};

        ACTIVITY:
        for my $Activity ( @{ $ProcessData->{Process}->{Activities} } ) {
            next ACTIVITY if $Activity eq $ProcessData->{Process}->{Config}->{StartActivity};
            push @Path, $Activity;
        }

        for my $Activity (@Path) {

            for my $Transition (
                sort keys %{ $ProcessData->{Process}->{Config}->{Path}->{$Activity} }
                )
            {
                my $TransitionActionString;
                if (
                    $ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
                    ->{TransitionAction}
                    && @{
                        $ProcessData->{Process}->{Config}->{Path}->{$Activity}->{$Transition}
{'fraction_non_alphanumeric': 0.14061716904131166, 'fraction_numerical': 0.0007398391446504857, 'mean_word_length': 1.0586616881202713, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 649, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 184, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5817771', 'n_tokens_mistral': 9870, 'n_tokens_neox': 9283, 'n_words': 1699}