package org.westmalle.wayland.nativ;


import com.sun.jna.LastErrorException;
import com.sun.jna.Pointer;
import org.westmalle.wayland.nativ.libc.Libc;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Singleton;

import static org.westmalle.wayland.nativ.libc.Libc.FD_CLOEXEC;
import static org.westmalle.wayland.nativ.libc.Libc.F_GETFD;
import static org.westmalle.wayland.nativ.libc.Libc.F_SETFD;

@Singleton
public class NativeFileFactory {

    private static final String TEMPLATE = "/westmalle-shared-XXXXXX";


    private final Libc libc;

    @Inject
    NativeFileFactory(@Nonnull final Libc libc) {
        this.libc = libc;
    }

    /**
     * Create a new, unique, anonymous file of the given size, and return the file descriptor for it. The file
     * descriptor is set CLOEXEC. The file is immediately suitable for mmap()'ing the given size at offset zero.
     * <p/>
     * The file should not have a permanent backing store like a disk, but may have if XDG_RUNTIME_DIR is not properly
     * implemented in OS.
     * <p/>
     * The file name is deleted from the file system.
     * <p/>
     * The file is suitable for buffer sharing between processes by transmitting the file descriptor over Unix sockets
     * using the SCM_RIGHTS methods.
     */
    public int createAnonymousFile(@Nonnegative final int size) throws LastErrorException {
        final String path = System.getenv("XDG_RUNTIME_DIR");
        if (path == null) {
            throw new LastErrorException(Libc.ENOENT);
        }

        final String name = path + TEMPLATE;

        final int fd = createTmpfileCloexec(new NativeString(name).getPointer());

        if (fd < 0) {
            return -1;
        }

        if (this.libc.ftruncate(fd,
                                size) < 0) {
            this.libc.close(fd);
            return -1;
        }

        return fd;
    }

    private int createTmpfileCloexec(final Pointer tmpname) {
        int fd = this.libc.mkstemp(tmpname);
        if (fd >= 0) {
            fd = setCloexecOrClose(fd);
            this.libc.unlink(tmpname);
        }

        return fd;
    }

    private int setCloexecOrClose(final int fd) {
        final int flags;

        if (fd == -1) {
            return -1;
        }

        flags = this.libc.fcntl(fd,
                                F_GETFD,
                                0);
        if (flags == -1) {
            this.libc.close(fd);
            return -1;
        }

        if (this.libc.fcntl(fd,
                            F_SETFD,
                            flags | FD_CLOEXEC) == -1) {
            this.libc.close(fd);
            return -1;
        }

        return fd;
    }
}

@@ -71,16 +71,43 @@
 eption;%0A
+import com.sun.jna.Memory;%0A
 import c
@@ -307,195 +307,8 @@
 n;%0A%0A
-import static org.westmalle.wayland.nativ.libc.Libc.FD_CLOEXEC;%0Aimport static org.westmalle.wayland.nativ.libc.Libc.F_GETFD;%0Aimport static org.westmalle.wayland.nativ.libc.Libc.F_SETFD;%0A%0A
 @Sin
@@ -1269,16 +1269,17 @@
 ption %7B%0A
+%0A
         
@@ -1386,38 +1386,85 @@
 new 
-LastErrorException(Libc.ENOENT
+IllegalStateException(%22Cannot create temporary file: XDG_RUNTIME_DIR not set%22
 );%0A 
@@ -1518,16 +1518,57 @@
 MPLATE;%0A
+        //FIXME assumes ascii-only string
 %0A       
@@ -1578,515 +1578,258 @@
 nal 
+Po
 int
- fd = createTmpfileCloexec(new NativeString(name).getPointer());%0A%0A        if (fd %3C 0) %7B%0A            return -1;%0A        %7D%0A%0A        if (this.libc.ftruncate(fd,%0A                                size) %3C 0) %7B%0A            this.libc.close(fd);%0A            return -1;%0A        %7D%0A%0A        return fd;%0A    %7D%0A%0A    private int createTmpfileCloexec(final Pointer tmpname) %7B%0A        int fd = this.libc.mkstemp(tmpname);%0A        if (fd %3E= 0) %7B%0A            fd = setCloexecOrClose(fd);%0A            this.libc.unlink(tmpname);
+er m = new Memory(name.length() + 1);%0A        m.setString(0,%0A                    name);%0A        final int fd = this.libc.mkstemp(m);%0A%0A        try %7B%0A            int flags = this.libc.fcntl(fd,%0A                                        Libc.F_GETFD,
 %0A   
@@ -1829,35 +1829,32 @@
 FD,%0A        
-%7D%0A%0A
         
 return fd;%0A 
@@ -1845,147 +1845,72 @@
     
-return fd;%0A
+ 
     
-%7D%0A%0A
     
-private int setCloexecOrClose(final int fd) %7B%0A        final int flags;%0A%0A        if (fd == -1) %7B%0A            return -1
+               0);%0A            flags %7C= Libc.FD_CLOEXEC
 ;%0A  
@@ -1918,27 +1918,12 @@
     
- %7D%0A%0A
     
-    flags =
  thi
@@ -1971,15 +1971,16 @@
     
-    F_G
+Libc.F_S
 ETFD
@@ -2013,137 +2013,47 @@
     
-    0);%0A        if (flags == -1) %7B%0A            this.libc.close(fd);%0A            return -1;%0A        %7D%0A%0A        if (this.libc.fcntl
+flags);%0A            this.libc.ftruncate
 (fd,
@@ -2081,24 +2081,26 @@
         
-F_SETFD,
+    size);
 %0A       
@@ -2100,32 +2100,53 @@
             
+this.libc.unlink(m);%0A
         
         flag
@@ -2129,32 +2129,34 @@
 m);%0A        
+%7D%0A
         
 flags %7C FD_C
@@ -2147,33 +2147,35 @@
     
-flags %7C FD_CLOEXEC) == -1
+catch (LastErrorException e
 ) %7B%0A
@@ -2223,17 +2223,15 @@
     
-return -1
+throw e
 ;%0A  
@@ -2230,33 +2230,32 @@
 ow e;%0A        %7D%0A
-%0A
         return f

simplify file creation implementation