// 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.

package java

import (
	"fmt"
	"log"
	"path"
	"strings"

	"v.io/v23/vdl"
	"v.io/x/ref/lib/vdl/compile"
	"v.io/x/ref/lib/vdl/vdlutil"
)

func javaFullyQualifiedNamedType(def *compile.TypeDef, forceClass bool, env *compile.Env) string {
	if def.File == compile.BuiltInFile {
		name, _ := javaBuiltInType(def.Type, forceClass)
		return name
	}
	return javaPath(path.Join(javaGenPkgPath(def.File.Package.GenPath), vdlutil.FirstRuneToUpper(def.Name)))
}

// javaReflectType returns java.reflect.Type string for provided VDL type.
func javaReflectType(t *vdl.Type, env *compile.Env) string {
	return fmt.Sprintf("new com.google.common.reflect.TypeToken<%s>(){}.getType()", javaType(t, true, env))
}

// javaBuiltInType returns the type name for the provided built in type
// definition, forcing the use of a java class (e.g., java.lang.Integer) if so
// desired.  This method also returns a boolean value indicating whether the
// returned type is a class.
func javaBuiltInType(typ *vdl.Type, forceClass bool) (string, bool) {
	if typ == nil {
		if forceClass {
			return "java.lang.Void", true
		} else {
			return "void", false
		}
	}
	switch typ.Kind() {
	case vdl.Bool:
		if forceClass {
			return "java.lang.Boolean", true
		} else {
			return "boolean", false
		}
	case vdl.Byte:
		if forceClass {
			return "java.lang.Byte", true
		} else {
			return "byte", false
		}
	case vdl.Uint16:
		return "io.v.v23.vdl.VdlUint16", true
	case vdl.Int16:
		if forceClass {
			return "java.lang.Short", true
		} else {
			return "short", false
		}
	case vdl.Uint32:
		return "io.v.v23.vdl.VdlUint32", true
	case vdl.Int32:
		if forceClass {
			return "java.lang.Integer", true
		} else {
			return "int", false
		}
	case vdl.Uint64:
		return "io.v.v23.vdl.VdlUint64", true
	case vdl.Int64:
		if forceClass {
			return "java.lang.Long", true
		} else {
			return "long", false
		}
	case vdl.Float32:
		if forceClass {
			return "java.lang.Float", true
		} else {
			return "float", false
		}
	case vdl.Float64:
		if forceClass {
			return "java.lang.Double", true
		} else {
			return "double", false
		}
	case vdl.Complex64:
		return "io.v.v23.vdl.VdlComplex64", true
	case vdl.Complex128:
		return "io.v.v23.vdl.VdlComplex128", true
	case vdl.String:
		return "java.lang.String", true
	case vdl.TypeObject:
		return "io.v.v23.vdl.VdlTypeObject", true
	case vdl.Any:
		return "io.v.v23.vdl.VdlAny", true
	default:
		return "", false
	}
}

func javaNativeType(t *vdl.Type, env *compile.Env) (string, bool) {
	if t == vdl.ErrorType {
		return "io.v.v23.verror.VException", true
	}
	if def := env.FindTypeDef(t); def != nil {
		pkg := def.File.Package
		if native, ok := pkg.Config.Java.WireToNativeTypes[def.Name]; ok {
			// There is a Java native type configured for this defined type.
			return native, true
		}
	}
	return "", false
}

func javaType(t *vdl.Type, forceClass bool, env *compile.Env) string {
	if t == nil {
		name, _ := javaBuiltInType(nil, forceClass)
		return name
	}
	if native, ok := javaNativeType(t, env); ok {
		return native
	}
	if def := env.FindTypeDef(t); def != nil {
		return javaFullyQualifiedNamedType(def, forceClass, env)
	}
	switch t.Kind() {
	case vdl.Array:
		return fmt.Sprintf("%s[]", javaType(t.Elem(), false, env))
	case vdl.List:
		// NOTE(spetrovic): We represent byte lists as Java byte arrays, as it's doubtful anybody
		// would want to use them as Java lists.
		if javaType(t.Elem(), false, env) == "byte" {
			return fmt.Sprintf("byte[]")
		}
		return fmt.Sprintf("%s<%s>", "java.util.List", javaType(t.Elem(), true, env))
	case vdl.Set:
		return fmt.Sprintf("%s<%s>", "java.util.Set", javaType(t.Key(), true, env))
	case vdl.Map:
		return fmt.Sprintf("%s<%s, %s>", "java.util.Map", javaType(t.Key(), true, env), javaType(t.Elem(), true, env))
	case vdl.Optional:
		return fmt.Sprintf("io.v.v23.vdl.VdlOptional<%s>", javaType(t.Elem(), true, env))
	default:
		log.Fatalf("vdl: javaType unhandled type %v %v", t.Kind(), t)
		return ""
	}
}

func javaVdlPrimitiveType(kind vdl.Kind) string {
	switch kind {
	case vdl.Bool, vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Float32, vdl.Float64, vdl.Complex128, vdl.Complex64, vdl.String:
		return "io.v.v23.vdl.Vdl" + vdlutil.FirstRuneToUpper(kind.String())
	}
	log.Fatalf("val: unhandled kind: %v", kind)
	return ""
}

// javaHashCode returns the java code for the hashCode() computation for a given type.
func javaHashCode(name string, ty *vdl.Type, env *compile.Env) string {
	if isJavaNativeArray(ty, env) {
		return fmt.Sprintf("java.util.Arrays.hashCode(%s)", name)
	}
	if def := env.FindTypeDef(ty); def != nil && def.File == compile.BuiltInFile {
		switch ty.Kind() {
		case vdl.Bool:
			return fmt.Sprintf("java.lang.Boolean.valueOf(%s).hashCode()", name)
		case vdl.Byte, vdl.Int16:
			return "(int)" + name
		case vdl.Int32:
			return name
		case vdl.Int64:
			return fmt.Sprintf("java.lang.Long.valueOf(%s).hashCode()", name)
		case vdl.Float32:
			return fmt.Sprintf("java.lang.Float.valueOf(%s).hashCode()", name)
		case vdl.Float64:
			return fmt.Sprintf("java.lang.Double.valueOf(%s).hashCode()", name)
		}
	}
	return fmt.Sprintf("(%s == null ? 0 : %s.hashCode())", name, name)
}

// isClass returns true iff the provided type is represented by a Java class.
func isClass(t *vdl.Type, env *compile.Env) bool {
	if t == nil { // void type
		return false
	}
	if def := env.FindTypeDef(t); def != nil && def.File == compile.BuiltInFile {
		// Built-in type.  See if it's represented by a class.
		if tname, isClass := javaBuiltInType(t, false); tname != "" && !isClass {
			return false
		}
	}
	return true
}

// isJavaNativeArray returns true iff the provided type is represented by a Java array.
func isJavaNativeArray(t *vdl.Type, env *compile.Env) bool {
	typeStr := javaType(t, false, env)
	return strings.HasSuffix(typeStr, "[]")
}

func bitlen(kind vdl.Kind) int {
	switch kind {
	case vdl.Float32, vdl.Complex64:
		return 32
	case vdl.Float64, vdl.Complex128:
		return 64
	}
	panic(fmt.Errorf("vdl: bitLen unhandled kind %v", kind))
}
