// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains JNI conversions to/from Java types for the types declared
// in lib.h. The other file that contains functions related to the types in
// lib.h is types.go. We need to place the JNI code in a separate file in order
// to use build tags to restrict the compilation to Java and Android.
//
// All "x.extractToJava" methods leave "x" in the same state as "x.free".

// +build java android
// +build cgo

package main

import "unsafe"

// #include <stdlib.h>
// #include "jni_wrapper.h"
// #include "lib.h"
import "C"

// newVBytesFromJava creates a v23_syncbase_Bytes from a jbyteArray.
func newVBytesFromJava(env *C.JNIEnv, array C.jbyteArray) C.v23_syncbase_Bytes {
	r := C.v23_syncbase_Bytes{}
	n := C.GetArrayLength(env, array)
	r.n = C.int(n)
	r.p = (*C.uint8_t)(C.malloc(C.size_t(r.n)))
	C.GetByteArrayRegion(env, array, 0, n, (*C.jbyte)(unsafe.Pointer(r.p)))
	// We don't have to check for exceptions because GetByteArrayRegion can
	// only throw ArrayIndexOutOfBoundsException and we know the requested
	// amount of elements is valid.
	return r
}

// extractToJava constructs a jbyteArray from a v23_syncbase_Bytes. The pointer
// inside v23_syncbase_Bytes will be freed.
func (x *C.v23_syncbase_Bytes) extractToJava(env *C.JNIEnv) C.jbyteArray {
	obj := C.NewByteArray(env, C.jsize(x.n))
	if C.ExceptionOccurred(env) != nil {
		panic("NewByteArray OutOfMemoryError exception")
	}
	C.SetByteArrayRegion(env, obj, 0, C.jsize(x.n), (*C.jbyte)(unsafe.Pointer(x.p)))
	// We don't have to check for exceptions because SetByteArrayRegion can
	// only throw ArrayIndexOutOfBoundsException and we know the requested
	// amount of elements is valid.
	x.free()
	return obj
}

// newVIdFromJava creates a v23_syncbase_Id from a jobject.
func newVIdFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_Id {
	blessing := C.jstring(C.GetObjectField(env, obj, idClass.blessing))
	if C.ExceptionOccurred(env) != nil {
		panic("newVIdFromJava exception while retrieving Id.blessing")
	}

	name := C.jstring(C.GetObjectField(env, obj, idClass.name))
	if C.ExceptionOccurred(env) != nil {
		panic("newVIdFromJava exception while retrieving Id.name")
	}

	return C.v23_syncbase_Id{
		blessing: newVStringFromJava(env, blessing),
		name:     newVStringFromJava(env, name),
	}
}

// extractToJava constructs a jstring from a v23_syncbase_String. The pointer
// inside v23_syncbase_String will be freed. The code is somewhat complicated
// and inefficient because the NewStringUTF from JNI only works with modified
// UTF-8 strings (inner nulls are encoded as 0xC0, 0x80 and the string is
// terminated with a null).
func (x *C.v23_syncbase_String) extractToJava(env *C.JNIEnv) C.jstring {
	n := int(x.n)
	srcPtr := uintptr(unsafe.Pointer(x.p))
	numNulls := 0
	for i := 0; i < n; i++ {
		if *(*byte)(unsafe.Pointer(srcPtr + uintptr(i))) == 0 {
			numNulls++
		}
	}
	tmp := C.malloc(C.size_t(n + numNulls + 1))
	defer C.free(tmp)
	tmpPtr := uintptr(tmp)
	j := 0
	for i := 0; i < n; i, j = i+1, j+1 {
		if *(*byte)(unsafe.Pointer(srcPtr + uintptr(i))) != 0 {
			*(*byte)(unsafe.Pointer(tmpPtr + uintptr(j))) = *(*byte)(unsafe.Pointer(srcPtr + uintptr(i)))
			continue
		}
		*(*byte)(unsafe.Pointer(tmpPtr + uintptr(j))) = 0xC0
		j++
		*(*byte)(unsafe.Pointer(tmpPtr + uintptr(j))) = 0x80
	}
	*(*byte)(unsafe.Pointer(tmpPtr + uintptr(j))) = 0
	r := C.NewStringUTF(env, (*C.char)(tmp))
	if C.ExceptionOccurred(env) != nil {
		panic("NewStringUTF OutOfMemoryError exception")
	}
	x.free()
	return r
}

// newVStringFromJava creates a v23_syncbase_String from a jstring.
func newVStringFromJava(env *C.JNIEnv, s C.jstring) C.v23_syncbase_String {
	r := C.v23_syncbase_String{}
	if s == nil {
		return r
	}
	// Note that GetStringUTFLength does not include a trailing zero.
	n := int(C.GetStringUTFLength(env, s))
	r.n = C.int(n)
	// TODO(razvanm): The JNI documentation doesn't clearly specify whether
	// the string returned by GetStringUTFRegion is null-terminated. What
	// I empirically found was that the heap gets corrupted if we allocate
	// the exact amount of bytes and the string size is of certain sizes (to
	// be more specific, size of the form 24 + 16 * x). Adding a single
	// extra byte seems to avoid the issue. I only checked sizes up to 32K.
	//
	// Some interesting perspective on the JNI's brokenness:
	//   http://www.club.cc.cmu.edu/~cmccabe/blog_jni_flaws.html
	r.p = (*C.char)(C.malloc(C.size_t(r.n + 1)))
	p := uintptr(unsafe.Pointer(r.p))
	// Note that we need to use GetStringLength and not GetStringUTFLength
	// because we need to indicate how many Unicode characters we want to be
	// copied.
	C.GetStringUTFRegion(env, s, 0, C.GetStringLength(env, s), r.p)
	// We don't have to check for exceptions because GetStringUTFRegion can
	// only throw StringIndexOutOfBoundsException and we know the requested
	// amount of characters is valid.
	j := 0
	for i := 0; i < n; i, j = i+1, j+1 {
		if i+1 < n && *(*byte)(unsafe.Pointer(p + uintptr(i))) == 0xC0 && *(*byte)(unsafe.Pointer(p + uintptr(i+1))) == 0x80 {
			*(*byte)(unsafe.Pointer(p + uintptr(j))) = 0
			i++
			continue
		}

		if j == i {
			continue
		}

		*(*byte)(unsafe.Pointer(p + uintptr(j))) = *(*byte)(unsafe.Pointer(p + uintptr(i)))
	}
	r.p = (*C.char)(C.realloc(unsafe.Pointer(r.p), (C.size_t)(j)))
	return r
}

// newVSyncgroupMemberInfoFromJava creates a v23_syncbase_SyncgroupMemberInfo
// from a jobject.
func newVSyncgroupMemberInfoFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_SyncgroupMemberInfo {
	syncPriority := C.GetIntField(env, obj, syncgroupMemberInfoClass.syncPriority)
	if C.ExceptionOccurred(env) != nil {
		panic("newVSyncgroupMemberInfoFromJava exception while retrieving SyncgroupMemberInfo.syncPriority")
	}
	blobDevType := C.GetIntField(env, obj, syncgroupMemberInfoClass.blobDevType)
	if C.ExceptionOccurred(env) != nil {
		panic("newVSyncgroupMemberInfoFromJava exception while retrieving SyncgroupMemberInfo.blobDevType")
	}
	return C.v23_syncbase_SyncgroupMemberInfo{
		syncPriority: C.uint8_t(syncPriority),
		blobDevType:  C.uint8_t(blobDevType),
	}
}

// newVSyngroupSpecFromJava creates a v23_syncbase_SyncgroupSpec from a jobject.
func newVSyngroupSpecFromJava(env *C.JNIEnv, obj C.jobject) C.v23_syncbase_SyncgroupSpec {
	description := C.jstring(C.GetObjectField(env, obj, syncgroupSpecClass.description))
	if C.ExceptionOccurred(env) != nil {
		panic("newVSyngroupSpecFromJava exception while retrieving SyncgroupSpec.description")
	}

	publishSyncbaseName := C.jstring(C.GetObjectField(env, obj, syncgroupSpecClass.publishSyncbaseName))
	if C.ExceptionOccurred(env) != nil {
		panic("newVSyngroupSpecFromJava exception while retrieving SyncgroupSpec.publishSyncbaseName")
	}

	// TODO(razvanm): construct a proper Permissions object based on the
	// C.v23_syncbase_Permissions.

	collections := C.GetObjectField(env, obj, syncgroupSpecClass.collections)
	if C.ExceptionOccurred(env) != nil {
		panic("newVSyngroupSpecFromJava exception while retrieving SyncgroupSpec.collections")
	}
	collectionsIds := newVIdsFromJava(env, collections)

	mountTables := C.GetObjectField(env, obj, syncgroupSpecClass.mountTables)
	if C.ExceptionOccurred(env) != nil {
		panic("newVSyngroupSpecFromJava exception while retrieving SyncgroupSpec.mountTables")
	}
	mountTablesStrings := newVStringsFromJava(env, mountTables)

	return C.v23_syncbase_SyncgroupSpec{
		description:         newVStringFromJava(env, description),
		publishSyncbaseName: newVStringFromJava(env, publishSyncbaseName),
		collections:         collectionsIds,
		mountTables:         mountTablesStrings,
	}
}
