package ffm; /// usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 11

/**
 * Java 11 approach to calling native functions - requires JNI
 * <p>
 * This demonstrates the complexity involved before FFM API.
 * You need separate C files, compilation steps, and platform-specific builds.
 * </p>
 * <p>
 * Execute with JBang to force Java 11: jbang Java11NativeCalls.java
 * </p>
 */
public class Java11NativeCalls {

    // Load the native library (would need to be compiled separately)
    static {
        try {
            System.loadLibrary("java11native"); // Looks for libjava11native.so/.dll/.dylib
            System.out.println("✓ Native library loaded successfully");
        } catch (UnsatisfiedLinkError e) {
            System.out.println("✗ Native library not found - this is expected!");
            System.out.println("  Would need to compile native code first...");
        }
    }

    // Native method declarations - these require corresponding C implementations
    public static native long nativeStrlen(String str);

    public static native int nativeGetpid();

    public static native long nativeMalloc(long size);

    public static native void nativeFree(long ptr);

    public static native void nativeWriteInt(long ptr, int value);

    public static native int nativeReadInt(long ptr);

    static void main(String[] args) {
        System.out.println("=== Java 11 Native Function Calls (JNI Approach) ===");
        System.out.println();

        // Show what the complete process would involve
        showRequiredSteps();

        // Demonstrate what the Java code would look like (if native lib existed)
        demonstrateJavaCode();
    }

    private static void showRequiredSteps() {
        System.out.println("To implement native calls in Java 11, you need:");
        System.out.println();

        System.out.println("1. JAVA SIDE - Declare native methods:");
        System.out.println("   public static native long nativeStrlen(String str);");
        System.out.println("   public static native int nativeGetpid();");
        System.out.println();

        System.out.println("2. GENERATE HEADERS - Use javac to create C headers:");
        System.out.println("   javac -h . ffm.Java11NativeCalls.java");
        System.out.println("   # Creates: ffm.Java11NativeCalls.h");
        System.out.println();

        System.out.println("3. C IMPLEMENTATION - Write C code (see below)");
        System.out.println();

        System.out.println("4. COMPILE NATIVE LIBRARY - Platform specific:");
        System.out.println("   Linux:   gcc -shared -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \\");
        System.out.println("            -o libjava11native.so java11native.c");
        System.out.println("   macOS:   gcc -shared -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin \\");
        System.out.println("            -o libjava11native.dylib java11native.c");
        System.out.println("   Windows: Different compiler, different paths, .dll extension...");
        System.out.println();

        System.out.println("5. DEPLOY - Manage platform-specific libraries");
        System.out.println("   • Different file extensions (.so/.dll/.dylib)");
        System.out.println("   • Architecture variants (x64, arm64, etc.)");
        System.out.println("   • Library path configuration");
        System.out.println();
    }

    private static void demonstrateJavaCode() {
        System.out.println("If the native library existed, Java usage would be:");
        System.out.println();

        try {
            // This would work if we had the native library compiled
            System.out.println("// Calling strlen on a string");
            System.out.println("long len = nativeStrlen(\"Hello JNI!\");");
            System.out.println("// Result: length of string");
            System.out.println();

            System.out.println("// Getting process ID");
            System.out.println("int pid = nativeGetpid();");
            System.out.println("// Result: current process ID");
            System.out.println();

            System.out.println("// Manual memory management");
            System.out.println("long ptr = nativeMalloc(1024);");
            System.out.println("nativeWriteInt(ptr, 0x12345678);");
            System.out.println("int value = nativeReadInt(ptr);");
            System.out.println("nativeFree(ptr);");
            System.out.println();

            // Try to actually call (will fail without native lib)
            long result = nativeStrlen("Hello JNI!");
            System.out.println("Actual strlen result: " + result);

        } catch (UnsatisfiedLinkError e) {
            System.out.println("⚠️  Cannot call native methods - library not compiled");
        }
    }
}

/*
REQUIRED C CODE (java11native.c):
=====================================

#include <jni.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "ffm.Java11NativeCalls.h"

// Implementation of nativeStrlen
JNIEXPORT jlong JNICALL Java_Java11NativeCalls_nativeStrlen
  (JNIEnv *env, jclass cls, jstring str) {
    
    // Convert Java string to C string
    const char *cstr = (*env)->GetStringUTFChars(env, str, NULL);
    if (cstr == NULL) return -1; // OutOfMemoryError already thrown
    
    // Call actual strlen
    jlong result = (jlong) strlen(cstr);
    
    // Release the C string
    (*env)->ReleaseStringUTFChars(env, str, cstr);
    
    return result;
}

// Implementation of nativeGetpid
JNIEXPORT jint JNICALL Java_Java11NativeCalls_nativeGetpid
  (JNIEnv *env, jclass cls) {
    return (jint) getpid();
}

// Implementation of nativeMalloc
JNIEXPORT jlong JNICALL Java_Java11NativeCalls_nativeMalloc
  (JNIEnv *env, jclass cls, jlong size) {
    void *ptr = malloc((size_t) size);
    return (jlong) ptr;
}

// Implementation of nativeFree
JNIEXPORT void JNICALL Java_Java11NativeCalls_nativeFree
  (JNIEnv *env, jclass cls, jlong ptr) {
    free((void *) ptr);
}

// Implementation of nativeWriteInt
JNIEXPORT void JNICALL Java_Java11NativeCalls_nativeWriteInt
  (JNIEnv *env, jclass cls, jlong ptr, jint value) {
    *((int *) ptr) = value;
}

// Implementation of nativeReadInt
JNIEXPORT jint JNICALL Java_Java11NativeCalls_nativeReadInt
  (JNIEnv *env, jclass cls, jlong ptr) {
    return *((int *) ptr);
}

COMPLEXITY COMPARISON:
=====================

FFM API (Java 22) - ONE FILE:
    FunctionDescriptor strlenDesc = FunctionDescriptor.of(
        ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
    MethodHandle strlen = linker.downcallHandle(strlenAddress, strlenDesc);
    long length = (long) strlen.invoke(cString);

JNI (Java 11) - MULTIPLE FILES + BUILD SYSTEM:
    1. Java file with native declarations
    2. C header file (generated)
    3. C implementation file (manual)
    4. Platform-specific compilation commands
    5. Library deployment and loading
    6. Error handling across language boundaries
    7. Manual memory management for strings/objects

ISSUES WITH JNI APPROACH:
========================
• 10x more code across multiple files
• Platform-specific build complexity
• Manual string/object lifecycle management
• Error handling across language boundaries
• Deployment complexity (multiple native libraries)
• Debugging across Java/C boundary is difficult
• Performance overhead from JNI call marshalling
• Security: native code can crash the JVM
• Maintenance: need C expertise on the team

FFM API eliminates ALL of these issues!
*/