package Sidef::Types::Glob::Socket {

    use utf8;
    use 5.016;
    our $AUTOLOAD;

    use parent qw(
      Sidef::Object::Object
    );

    use Sidef::Types::Bool::Bool;

    sub new {
        bless {}, __PACKAGE__;
    }

    {
        no strict 'refs';
        require Socket;

        foreach my $name (@Socket::EXPORT, @Socket::EXPORT_OK) {
            $name =~ /^[a-z]/i or next;
            *{__PACKAGE__ . '::' . $name} = sub {
                my ($self, @args) = @_;

                my $func = \&{'Socket' . '::' . $name};
                @args = map { $_->get_value } @args;

                my @results = eval { $func->(@args) };

                if ($@) {
                    @results = scalar $func->(@args);
                }

                return (
                        @results > 1
                        ? (map { Sidef::Types::Perl::Perl->to_sidef($_) } @results)
                        : Sidef::Types::Perl::Perl->to_sidef($results[0])
                       );
            };
        }
    }

    sub open {
        my ($self, $domain, $type, $protocol) = @_;
        CORE::socket(my $sh, $domain, $type, $protocol) || return undef;
        Sidef::Types::Glob::SocketHandle->new($sh);
    }

    sub socketpair {
        my ($self, $socket1, $socket2, $domain, $type, $protocol) = @_;
        CORE::socketpair(my $sh1, my $sh2, $domain, $type, $protocol)
          || return (Sidef::Types::Bool::Bool::FALSE);
        ${$socket1} = Sidef::Types::Glob::SocketHandle->new($sh1);
        ${$socket2} = Sidef::Types::Glob::SocketHandle->new($sh2);
        (Sidef::Types::Bool::Bool::TRUE);
    }

    #
    ## gethost*
    #
    sub gethostbyname {
        my ($self, $name) = @_;
        Sidef::Types::String::String->new(CORE::gethostbyname("$name") // return undef);
    }

    sub gethostbyaddr {
        my ($self, $addr, $addrtype) = @_;
        Sidef::Types::String::String->new(CORE::gethostbyaddr("$addr", "$addrtype") // return undef);
    }

    sub gethostent {
        my ($self) = @_;
        Sidef::Types::String::String->new(CORE::gethostent() // return undef);
    }

    #
    ## getnet*
    #
    sub getnetbyname {
        my ($self, $name) = @_;
        Sidef::Types::String::String->new(CORE::getnetbyname("$name") // return undef);
    }

    sub getnetbyaddr {
        my ($self, $addr, $addrtype) = @_;
        Sidef::Types::String::String->new(CORE::getnetbyaddr("$addr", "$addrtype") // return undef);
    }

    sub getnetent {
        my ($self) = @_;
        Sidef::Types::String::String->new(CORE::getnetent() // return undef);
    }

    #
    ## getserv*
    #
    sub getservbyname {
        my ($self, $name, $proto) = @_;
        Sidef::Types::String::String->new(CORE::getservbyname("$name", $proto) // return undef);
    }

    sub getservbyport {
        my ($self, $port, $proto) = @_;
        Sidef::Types::String::String->new(CORE::getservbyport($port, $proto) // return undef);
    }

    sub getservent {
        my ($self) = @_;
        Sidef::Types::String::String->new(CORE::getservent() // return undef);
    }

    #
    ## getproto*
    #
    sub getprotobynumber {
        my ($self, $num) = @_;
        Sidef::Types::String::String->new(CORE::getprotobynumber(CORE::int($num)) // return undef);
    }

    sub getprotobyname {
        my ($self, $name) = @_;
        Sidef::Types::Number::Number->new(CORE::getprotobyname("$name") // (return undef));
    }

    sub getprotoent {
        my ($self) = @_;
        Sidef::Types::Number::Number->new(CORE::getprotoent() // (return undef));
    }

    #
    ## set*
    #
    sub sethostent {
        my ($self, $stayopen) = @_;
        (CORE::sethostent($stayopen ? 1 : 0)) ? (Sidef::Types::Bool::Bool::TRUE) : (Sidef::Types::Bool::Bool::FALSE);
    }

    sub setnetent {
        my ($self, $stayopen) = @_;
        (CORE::setnetent($stayopen ? 1 : 0)) ? (Sidef::Types::Bool::Bool::TRUE) : (Sidef::Types::Bool::Bool::FALSE);
    }

    sub setprotoent {
        my ($self, $stayopen) = @_;
        (CORE::setprotoent($stayopen ? 1 : 0)) ? (Sidef::Types::Bool::Bool::TRUE) : (Sidef::Types::Bool::Bool::FALSE);
    }

    sub setservent {
        my ($self, $stayopen) = @_;
        (CORE::setservent($stayopen ? 1 : 0)) ? (Sidef::Types::Bool::Bool::TRUE) : (Sidef::Types::Bool::Bool::FALSE);
    }
};

1
