package ru.dbotthepony.mc.otm.matter

import net.minecraft.network.FriendlyByteBuf
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.readDecimal
import ru.dbotthepony.mc.otm.core.math.writeDecimal
import ru.dbotthepony.mc.otm.core.util.readDouble
import ru.dbotthepony.mc.otm.core.util.writeDouble
import java.io.InputStream
import java.io.OutputStream

interface IMatterValue : Comparable<IMatterValue> {
	val matter: Decimal
	val complexity: Double

	val hasMatterValue: Boolean get() = matter.isPositive && complexity > 0.0

	/**
	 * Java friendly version of hasMatterValue
	 */
	fun hasMatterValue() = hasMatterValue

	operator fun plus(other: IMatterValue): IMatterValue {
		return MatterValue(matter + other.matter, complexity + other.complexity)
	}

	operator fun minus(other: IMatterValue): IMatterValue {
		return MatterValue(matter - other.matter, complexity - other.complexity)
	}

	operator fun times(other: IMatterValue): IMatterValue {
		return MatterValue(matter * other.matter, complexity * other.complexity)
	}

	operator fun times(other: Int): IMatterValue {
		return MatterValue(matter * other, complexity * other)
	}

	override fun compareTo(other: IMatterValue): Int {
		val matterComparison = matter.compareTo(other.matter)

		if (matterComparison == 0) {
			return complexity.compareTo(other.complexity)
		}

		return matterComparison
	}

	/**
	 * ZERO
	 */
	companion object : IMatterValue {
		val ZERO: IMatterValue get() = this

		override val matter: Decimal
			get() = Decimal.ZERO
		override val complexity: Double
			get() = 0.0
	}
}


fun FriendlyByteBuf.writeMatterValue(value: IMatterValue) {
	writeDecimal(value.matter)
	writeDouble(value.complexity)
}

fun OutputStream.writeMatterValue(value: IMatterValue) {
	writeDecimal(value.matter)
	writeDouble(value.complexity)
}

fun FriendlyByteBuf.readMatterValue(): IMatterValue {
	val matter = readDecimal()
	val complexity = readDouble()

	if (matter.isZero && complexity == 0.0) {
		return IMatterValue.Companion
	} else {
		return MatterValue(matter, complexity)
	}
}

fun InputStream.readMatterValue(): IMatterValue {
	val matter = readDecimal()
	val complexity = readDouble()

	if (matter.isZero && complexity == 0.0) {
		return IMatterValue.Companion
	} else {
		return MatterValue(matter, complexity)
	}
}

data class MatterValue(
	override val matter: Decimal,
	override val complexity: Double
) : IMatterValue
