package ru.dbotthepony.mc.otm.core.math

import java.math.BigDecimal
import java.math.BigInteger
import kotlin.math.absoluteValue

inline val BigInteger.isZero get() 		= this.signum() == 0
inline val BigInteger.isPositive get() 	= this.signum() > 0
inline val BigInteger.isNegative get() 	= this.signum() < 0

inline val BigDecimal.isZero get() 		= this.signum() == 0
inline val BigDecimal.isPositive get() 	= this.signum() > 0
inline val BigDecimal.isNegative get() 	= this.signum() < 0

val BI_INT_MAX: BigInteger = BigInteger.valueOf(Int.MAX_VALUE.toLong())
val BI_INT_MIN: BigInteger = BigInteger.valueOf(Int.MIN_VALUE.toLong())
val BI_LONG_MAX: BigInteger = BigInteger.valueOf(Long.MAX_VALUE)
val BI_LONG_MIN: BigInteger = BigInteger.valueOf(Long.MIN_VALUE)

val BI_FLOAT_MAX: BigInteger = BigDecimal(Float.MAX_VALUE.toString()).toBigInteger()
val BI_FLOAT_MIN: BigInteger = BigDecimal(Float.MIN_VALUE.toString()).toBigInteger()
val BI_DOUBLE_MAX: BigInteger = BigDecimal(Double.MAX_VALUE.toString()).toBigInteger()
val BI_DOUBLE_MIN: BigInteger = BigDecimal(Double.MIN_VALUE.toString()).toBigInteger()

/**
 * Constant value which represent edge of meaningful bits.
 *
 * Equals to 0.000000000001
 */
const val EPSILON = 0.000000000001

fun weakEqualDoubles(a: Double, b: Double): Boolean {
	if (a == b)
		return true

	return (a - b).absoluteValue <= EPSILON
}

fun weakCompareDoubles(a: Double, b: Double): Int {
	if (weakEqualDoubles(a, b))
		return 0

	if (a > b)
		return 1

	return -1
}

fun weakLessThan(a: Double, b: Double) = weakCompareDoubles(a, b) < 0
fun weakGreaterThan(a: Double, b: Double) = weakCompareDoubles(a, b) > 0
fun weakLessOrEqual(a: Double, b: Double) = weakCompareDoubles(a, b) <= 0
fun weakGreaterOrEqual(a: Double, b: Double) = weakCompareDoubles(a, b) >= 0

fun BigInteger.toIntSafe(): Int {
	if (this > BI_INT_MAX) {
		return Int.MAX_VALUE
	} else if (this < BI_INT_MIN) {
		return Int.MIN_VALUE
	}

	return toInt()
}

/**
 * 0, 9 -> 0
 * 1, 9 -> 0
 * 8, 9 -> 0
 * 9, 9 -> 0
 * 10, 9 -> 1
 * 17, 9 -> 1
 * 18, 9 -> 1
 * 19, 9 -> 2
 */
@Suppress("SameParameterValue")
fun integerDivisionDown(elements: Int, elementsPerRow: Int): Int {
	require(elements >= 0) { "Invalid amount of elements $elements" }
	return (elements - 1) / elementsPerRow
}

/**
 * 0, 9 -> 0
 * 1, 9 -> 1
 * 8, 9 -> 1
 * 9, 9 -> 1
 * 10, 9 -> 2
 * 17, 9 -> 2
 * 18, 9 -> 2
 * 19, 9 -> 3
 */
@Suppress("SameParameterValue")
fun integerDivisionUp(elements: Int, elementsPerRow: Int): Int {
	require(elements >= 0) { "Invalid amount of elements $elements" }
	return (elements + elementsPerRow - 1) / elementsPerRow
}
