#!/usr/bin/perl6
# your code goes here

use NativeCall;

class DIR is repr('CPointer') {

    sub opendir(Str) of Pointer is native(Str) { * }

    method new(Str $dir)  {
        return nativecast(DIR, opendir($dir));
    }

    class Dirent is repr('CStruct') {
        has int64 $.ino;
        has int64 $.off;
        has uint16 $.reclen;
        has uint8 $.type;
        has Str $.name;

        #`(
        submethod TWEAK() {
            $!ino  = long.new(0);
            $!off  = long.new(0);
            $!reclen = uint16.new(0);
            $!type   = uint8.new(0);
            $!name := CArray[int8].new;
            $!name.[$_] = 0 for ^256;
        })

        #`(method name() {
            say $!name.[0];
            my Buf $buf .= new;
            $buf[$_] = $!name[$_] for ^256;
            $buf.decode('utf8');
        })
    }

    sub readdir(DIR) of Pointer is native(Str) { * }

    sub readdir_r(DIR, Pointer[Dirent], Pointer[Pointer[Dirent]]) of int32 is native(Str) { * }

    method read() of Dirent {
        my $ptr = nativecast(Pointer[Dirent], readdir(self));
        return $ptr.deref;
    }

    method read_r() of Dirent {
        my $passd = CArray[Dirent].new;
        my $passr = CArray[Pointer[Dirent]].new;

        $passd[0] = Dirent.new;
        $passr[0] = Pointer[Dirent].new;
        say "ret = ", readdir_r(self, nativecast(Pointer[Dirent], $passd), nativecast(Pointer[Pointer[Dirent]], $passr));
        say $passd[0];
        $passd[0];
    }

    sub closedir(DIR) of int32 is native(Str) { * }

    method close() of int {
        closedir(self);
    }

    method error() {
        my $error := cglobal('libc.so.6', 'errno', int32);
        $error;
    }

    submethod DESTORY() {

    }
}

my $current = DIR.new(".");

dd $current;

for ^3 {
    my $dirent = $current.read;
    say $current.error unless $dirent;
    say $dirent.name;
}

$current.close;
