// Copyright (c) 2026 The elk-go Authors.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package javacompat

import (
	
	
)

const (
	canonicalDoubleNaN uint64 = 0x7ff8000000000000
	canonicalFloatNaN  uint32 = 0x7fc00000
)

// DoubleToLongBits implements Double.doubleToLongBits, including NaN
// canonicalization. Use math.Float64bits when Java's doubleToRawLongBits is
// specifically required.
func ( float64) uint64 {
	if math.IsNaN() {
		return canonicalDoubleNaN
	}
	return math.Float64bits()
}

// FloatToIntBits implements Float.floatToIntBits, including NaN
// canonicalization.
func ( float32) uint32 {
	if math.IsNaN(float64()) {
		return canonicalFloatNaN
	}
	return math.Float32bits()
}

// DoubleCompare implements Double.compare. In particular, -0.0 sorts before
// +0.0 and every NaN sorts after positive infinity and compares equal to every
// other NaN.
func (,  float64) int {
	if  <  {
		return -1
	}
	if  >  {
		return 1
	}
	 := int64(DoubleToLongBits())
	 := int64(DoubleToLongBits())
	if  ==  {
		return 0
	}
	if  <  {
		return -1
	}
	return 1
}

// FloatCompare implements Float.compare.
func (,  float32) int {
	if  <  {
		return -1
	}
	if  >  {
		return 1
	}
	 := int32(FloatToIntBits())
	 := int32(FloatToIntBits())
	if  ==  {
		return 0
	}
	if  <  {
		return -1
	}
	return 1
}

// DoubleHashCode implements Double.hashCode(double).
func ( float64) int32 {
	 := DoubleToLongBits()
	return int32( ^ ( >> 32))
}

// FloatHashCode implements Float.hashCode(float).
func ( float32) int32 { return int32(FloatToIntBits()) }

// LongHashCode implements Long.hashCode(long).
func ( int64) int32 {
	 := uint64()
	return int32( ^ ( >> 32))
}

// BooleanHashCode implements Boolean.hashCode(boolean).
func ( bool) int32 {
	if  {
		return 1231
	}
	return 1237
}

// StringHashCode implements String.hashCode over Java UTF-16 code units, not
// Unicode code points. This distinction matters for supplementary characters.
func ( string) int32 {
	var  int32
	for ,  := range utf16.Encode([]rune()) {
		 = 31* + int32()
	}
	return 
}

// HashMapSpread reproduces the one-step high-bit spread observed by ELK's
// Java-compatible hash tables. Its behavior is pinned by independent vectors.
func ( int32) int32 { return  ^ int32(uint32()>>16) }

// IntCompare and LongCompare implement Integer.compare and Long.compare.
func (,  int32) int {
	if  <  {
		return -1
	}
	if  >  {
		return 1
	}
	return 0
}

func (,  int64) int {
	if  <  {
		return -1
	}
	if  >  {
		return 1
	}
	return 0
}

// DoubleToInt and DoubleToLong implement Java's narrowing primitive casts:
// NaN becomes zero, finite out-of-range values and infinities saturate, and
// finite in-range values truncate toward zero.
func ( float64) int32 {
	switch {
	case math.IsNaN():
		return 0
	case  >= float64(math.MaxInt32):
		return math.MaxInt32
	case  <= float64(math.MinInt32):
		return math.MinInt32
	default:
		return int32()
	}
}

func ( float64) int64 {
	switch {
	case math.IsNaN():
		return 0
	// float64(MaxInt64) rounds to 2^63, which is precisely the first value
	// Java must saturate rather than convert.
	case  >= 0x1p63:
		return math.MaxInt64
	case  <= -0x1p63:
		return math.MinInt64
	default:
		return int64()
	}
}

// MathRoundDouble and MathRoundFloat implement Math.round.
func ( float64) int64 { return DoubleToLong(math.Floor( + 0.5)) }

func ( float32) int32 {
	return DoubleToInt(math.Floor(float64() + 0.5))
}

// MathMinDouble and MathMaxDouble preserve Java's NaN and signed-zero rules.
func (,  float64) float64 {
	if math.IsNaN() || math.IsNaN() {
		return math.NaN()
	}
	if  == 0 &&  == 0 {
		if math.Signbit() || math.Signbit() {
			return math.Copysign(0, -1)
		}
		return 0
	}
	return math.Min(, )
}

func (,  float64) float64 {
	if math.IsNaN() || math.IsNaN() {
		return math.NaN()
	}
	if  == 0 &&  == 0 {
		if !math.Signbit() || !math.Signbit() {
			return 0
		}
		return math.Copysign(0, -1)
	}
	return math.Max(, )
}

// UnsignedRightShiftInt and UnsignedRightShiftLong implement Java's >>>. Java
// masks the shift distance to five or six bits respectively.
func ( int32,  uint) int32 {
	return int32(uint32() >> ( & 31))
}

func ( int64,  uint) int64 {
	return int64(uint64() >> ( & 63))
}

// Narrowing integral conversions implement Java casts.
func ( int32) int8   { return int8() }
func ( int32) int16 { return int16() }
func ( int32) uint16 { return uint16() }