package Lemonldap::NG::Portal::UserDB::LDAP;

use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants
  qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS);

extends 'Lemonldap::NG::Portal::Lib::LDAP';

our $VERSION = '2.0.0';

has ldapGroupAttributeNameSearch => (
    is      => 'rw',
    lazy    => 1,
    builder => sub {
        return $_[0]->{conf}->{ldapGroupAttributeNameSearch}
          ? [
            split( /\s+/, $_[0]->{conf}->{ldapGroupAttributeNameSearch} ),

            # Push group attribute value for recursive search
            (
                $_[0]->{conf}->{ldapGroupRecursive}
                  and $_[0]->{conf}->{ldapGroupAttributeNameGroup} ne "dn"
                ? $_[0]->{conf}->{ldapGroupAttributeNameGroup}
                : ()
            )
          ]
          : [];
    }
);

has attrs => (
    is      => 'rw',
    lazy    => 1,
    builder => sub {
        return [
            values %{ $_[0]->{conf}->{exportedVars} },
            values %{ $_[0]->{conf}->{ldapExportedVars} }
        ];
    }
);

# RUNNING METHODS

sub getUser {
    my ( $self, $req ) = @_;
    return PE_LDAPCONNECTFAILED unless $self->ldap and $self->bind();
    my $mesg = $self->ldap->search(
        base   => $self->conf->{ldapBase},
        scope  => 'sub',
        filter => $self->filter->($req),
        defer  => $self->conf->{ldapSearchDeref} || 'find',
        attrs  => $self->attrs,
    );
    if ( $mesg->code() != 0 ) {
        $self->logger->error( 'LDAP Search error: ' . $mesg->error );
        return PE_LDAPERROR;
    }
    if ( $mesg->count() > 1 ) {
        $self->logger->error('More than one entry returned by LDAP directory');
        eval { $self->p->_authentication->setSecurity($req) };
        return PE_BADCREDENTIALS;
    }
    unless ( $req->datas->{entry} = $mesg->entry(0) ) {
        my $user = $req->{mail} || $req->{user};
        $self->userLogger->warn("$user was not found in LDAP directory");
        eval { $self->p->_authentication->setSecurity($req) };
        return PE_BADCREDENTIALS;
    }
    $req->datas->{dn} = $req->datas->{entry}->dn();
    PE_OK;
}

# Load all parameters included in exportedVars parameter.
# Multi-value parameters are loaded in a single string with
# a separator (param multiValuesSeparator)
# @return Lemonldap::NG::Portal constant
sub setSessionInfo {
    my ( $self, $req ) = @_;
    $req->{sessionInfo}->{_dn} = $req->datas->{dn};

    my %vars = ( %{ $self->conf->{exportedVars} },
        %{ $self->conf->{ldapExportedVars} } );
    while ( my ( $k, $v ) = each %vars ) {
        $req->sessionInfo->{$k} =
          $self->{ldap}->getLdapValue( $req->datas->{entry}, $v ) || "";
    }

    PE_OK;
}

# Load all groups in $groups.
# @return Lemonldap::NG::Portal constant
sub setGroups {
    my ( $self, $req ) = @_;
    my $groups  = $req->{sessionInfo}->{groups};
    my $hGroups = $req->{sessionInfo}->{hGroups};

    if ( $self->conf->{ldapGroupBase} ) {

        # Get value for group search
        my $group_value = $self->ldap->getLdapValue( $req->datas->{entry},
            $self->conf->{ldapGroupAttributeNameUser} );

        $self->logger->debug( "Searching LDAP groups in "
              . $self->{ldapGroupBase}
              . " for $group_value" );

        # Call searchGroups
        my $ldapGroups = $self->ldap->searchGroups(
            $self->conf->{ldapGroupBase},
            $self->conf->{ldapGroupAttributeName},
            $group_value, $self->ldapGroupAttributeNameSearch
        );

        foreach ( keys %$ldapGroups ) {
            my $groupName = $_;
            $hGroups->{$groupName} = $ldapGroups->{$groupName};
            my $groupValues = [];
            foreach ( @{ $self->ldapGroupAttributeNameSearch } ) {
                next if $_ =~ /^name$/;
                my $firstValue = $ldapGroups->{$groupName}->{$_}->[0];
                push @$groupValues, $firstValue;
            }
            $groups .=
              $self->conf->{multiValuesSeparator} . join( '|', @$groupValues );
        }

    }

    $req->{sessionInfo}->{groups} = $groups;
    PE_OK;
}

1;
