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

import (
	"fmt"
	"log"
	"unicode"
	"unicode/utf8"

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

// swiftBuiltInType returns the type name for the provided built in type
// definition, forcing the use of a swift class (e.g., swift.lang.Integer) if so
// desired.  This method also returns a boolean value indicating whether the
// returned type is a class.
//
// All swift integers (byte, short, int, long) are signed.  We
// translate signed vdl integers int{16,32,64} into their
// swift equivalents.  We translate unsigned vdl integers
// uint{16,32,64} into our class-based representation
// VdlUint{16,32,64}.
//
// According to this rule, we should translate signed
// vdl int8 into swift byte, and unsigned vdl byte into
// swift VdlUint8.  However we flip the rule, and
// actually translate vdl int8 into swift VdlInt8, and
// vdl byte into swift byte.  We do this because we want the
// common usage of vdl []byte to translate into swift byte[].
func (ctx *swiftContext) swiftBuiltInType(typ *vdl.Type) string {
	if typ == nil {
		return "Void"
	}
	switch typ.Kind() {
	case vdl.Bool:
		return "Bool"
	case vdl.Byte:
		return "UInt8"
	case vdl.Int8:
		return "Int8"
	case vdl.Uint16:
		return "UInt16"
	case vdl.Int16:
		return "Int16"
	case vdl.Uint32:
		return "UInt32"
	case vdl.Int32:
		return "Int32"
	case vdl.Uint64:
		return "UInt64"
	case vdl.Int64:
		return "Int64"
	case vdl.Float32:
		return "Float"
	case vdl.Float64:
		return "Double"
	case vdl.String:
		return "String"
	case vdl.TypeObject:
		return "VdlTypeObject"
	case vdl.Any:
		return "Any"
	case vdl.List, vdl.Array:
		return fmt.Sprintf("[%v]", ctx.swiftType(typ.Elem()))
	case vdl.Map:
		return fmt.Sprintf("[%v : %v]", ctx.swiftType(typ.Key()), ctx.swiftType(typ.Elem()))
	case vdl.Set:
		return fmt.Sprintf("Set<%v>", ctx.swiftType(typ.Key()))
	default:
		panic("Unsupported built in type")
	}
}

func (ctx *swiftContext) swiftTypeName(tdef *compile.TypeDef) string {
	if name, ok := ctx.memoizedTypeNames[tdef]; ok {
		return name
	}
	var name string
	if tdef.File == compile.BuiltInFile {
		name = ctx.swiftBuiltInType(tdef.Type)
	} else {
		// A typeName is created by walking concatenating a package path with the type name
		// into a camel cased symbol. For example Value in v.io/v23/syncbase/nosql would be
		// SyncbaseNosqlValue (because v23 defines a swift module we stop just before that).
		// Convienently the Swift package name already does the package path part, so we
		// can just append to that. In cases where we're at the root of our Swift module,
		// the package name will be a zero value and so we correctly end up with just our
		// tdef.Name.
		name = ctx.swiftPackageName(tdef.File.Package) + vdlutil.FirstRuneToUpper(tdef.Name)
		if !ctx.pkgIsSameModule(tdef.File.Package) {
			name = ctx.swiftModule(tdef.File.Package) + "." + name
		}
	}
	ctx.memoizedTypeNames[tdef] = name
	return name
}

// swiftAccessModifier returns the Swift access modifier given the type.
func swiftAccessModifier(tdef *compile.TypeDef) string {
	if tdef.Exported {
		return "public"
	}
	return "internal"
}

// accessModifierForName returns the Swift access modifier given the name.
// It follows VDL naming conventions, indicating that an uppercase name
// denotes a public type and a lowercase name a package-protected type.
func swiftAccessModifierForName(name string) string {
	r, _ := utf8.DecodeRuneInString(name)
	if unicode.IsUpper(r) {
		return "public"
	}
	return "internal"
}

func swiftNativeType(t *vdl.Type, env *compile.Env) (string, bool) {
	if t == vdl.ErrorType {
		// TODO(zinman) Verify this can never be a user-defined error,
		// and determine if we need to prepend the v23 namespace here
		// or if that adjustment will be higher up the stack.
		switch t.Kind() {
		case vdl.Optional:
			return "VError?", true
		case vdl.Struct:
			return "VError", true
		default:
			panic(fmt.Sprintf("Unexpected vdl.Type.Kind() for ErrorType: %v", t.Kind()))
		}
	}
	if tdef := env.FindTypeDef(t); tdef != nil {
		pkg := tdef.File.Package
		if native, ok := pkg.Config.Swift.WireToNativeTypes[tdef.Name]; ok {
			// There is a Swift native type configured for this defined type.
			return native, true
		}
	}
	return "", false
}

// swiftCaseName returns the Swift name of a field translated as a Enum case.
func swiftVariableName(tdef *compile.TypeDef, fld vdl.Field) string {
	// Check if reserved
	return vdlutil.FirstRuneToLower(fld.Name)
}

// swiftCaseName returns the Swift name of a field.
func swiftCaseName(tdef *compile.TypeDef, fld vdl.Field) string {
	// Check if reserved
	return vdlutil.FirstRuneToUpper(fld.Name)
}

func (ctx *swiftContext) swiftType(t *vdl.Type) string {
	if t == nil {
		return ctx.swiftBuiltInType(nil) //, forceClass)
	}

	if native, ok := swiftNativeType(t, ctx.env); ok {
		return native
	}
	if tdef := ctx.env.FindTypeDef(t); tdef != nil {
		return ctx.swiftTypeName(tdef)
	}
	switch t.Kind() {
	case vdl.Array, vdl.List:
		val := fmt.Sprintf("[%s]", ctx.swiftType(t.Elem()))
		return val
	case vdl.Set:
		return fmt.Sprintf("%s<%s>", "Set", ctx.swiftType(t.Key()))
	case vdl.Map:
		return fmt.Sprintf("[%s : %s]", ctx.swiftType(t.Key()), ctx.swiftType(t.Elem()))
	case vdl.Optional:
		return fmt.Sprintf("%s?", ctx.swiftType(t.Elem()))
	default:
		log.Fatalf("vdl: swiftType unhandled type %v %v", t.Kind(), t)
		return ""
	}
}

// swiftHashCode returns the swift code for the hashCode() computation for a given type.
func (ctx *swiftContext) swiftHashCode(name string, ty *vdl.Type) (string, error) {
	if def := ctx.env.FindTypeDef(ty); def != nil && def.File == compile.BuiltInFile {
		switch ty.Kind() {
		case vdl.Bool:
			return fmt.Sprintf("%s.hashValue", name), nil
		case vdl.Byte, vdl.Uint16, vdl.Int16:
			return "Int(" + name + ")", nil
		case vdl.Uint32, vdl.Int32:
			return name, nil
		case vdl.Uint64, vdl.Int64:
			return fmt.Sprintf("%s.hashValue", name), nil
		case vdl.Float32:
			return fmt.Sprintf("Float(%s).hashValue", name), nil
		case vdl.Float64:
			return fmt.Sprintf("Double(%s).hashValue", name), nil
		}
	}

	if !isTypeHashable(ty, make(map[*vdl.Type]bool)) {
		return "", fmt.Errorf("Any is not supported with hashCode")
	}

	switch ty.Kind() {
	case vdl.Optional:
		return fmt.Sprintf("(%s?.hashValue ?? 0)", name), nil
	// Primitives are going to access the rawValue inside this box
	case vdl.Bool, vdl.Byte, vdl.Uint16, vdl.Int16, vdl.Uint32, vdl.Int32, vdl.Uint64, vdl.Int64, vdl.Float32, vdl.Float64:
		return fmt.Sprintf("%s.rawValue.hashValue", name), nil
	}
	return fmt.Sprintf("%s.hashValue", name), nil
}

// isTypeHashable returns true if the type provided is hashable in Swift.
// Part of the difficulty in Swift is that as of 2.1 we can't create extensions
// with protocol conformance (Hashable, Equatable) AND type constraints (where Element : Hashable)
// Thus we can't extend Array AND require its elements to conform to Hashable as follows:
// ILLEGAL => extension Array : Hashable where Element : Hashable
//
// Returns false for Any, arrays, maps, and sets. Returns true for primitives,
// strings, enums. Optional, structs, and unions are only hashable if all of their
// contents are hashable.
func isTypeHashable(ty *vdl.Type, seen map[*vdl.Type]bool) bool {
	return !ty.ContainsKind(vdl.WalkAll, vdl.Any, vdl.Array, vdl.List, vdl.Set, vdl.Map, vdl.TypeObject)
}

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