package ru.dbotthepony.kstarbound.math.vector

import kotlin.math.sqrt

/**
 * Vectors are exclusively immutable
 */
sealed class Vector {
	val length: Double get() = sqrt(lengthSquared)
	val isValid: Boolean get() = isFinite && !isNaN

	abstract val isFinite: Boolean
	abstract val isNaN: Boolean
	abstract val lengthSquared: Double

	/**
	 * @throws IllegalArgumentException if matrix is not finite
	 */
	inline fun requireIsFinite(lambda: () -> Any) {
		if (!isFinite) {
			throw IllegalArgumentException(lambda.invoke().toString())
		}
	}

	/**
	 * @throws IllegalArgumentException if matrix is not finite
	 */
	fun requireIsFinite() {
		if (!isFinite) {
			throw IllegalArgumentException("Matrix is not finite")
		}
	}

	/**
	 * @throws IllegalStateException if matrix is not finite
	 */
	inline fun checkIsFinite(lambda: () -> Any) {
		if (!isFinite) {
			throw IllegalStateException(lambda.invoke().toString())
		}
	}

	/**
	 * @throws IllegalStateException if matrix is not finite
	 */
	fun checkIsFinite() {
		if (!isFinite) {
			throw IllegalStateException("Matrix is not finite")
		}
	}

	/**
	 * @throws IllegalArgumentException if vector has NaN component
	 */
	inline fun requireNotNaN(lambda: () -> Any) {
		if (isNaN) {
			throw IllegalArgumentException(lambda.invoke().toString())
		}
	}

	/**
	 * @throws IllegalArgumentException if matrix has NaN component
	 */
	fun requireNotNaN() {
		if (isNaN) {
			throw IllegalArgumentException("Matrix has NaN component")
		}
	}

	/**
	 * @throws IllegalStateException if matrix has NaN component
	 */
	inline fun checkNotNaN(lambda: () -> Any) {
		if (!isFinite) {
			throw IllegalStateException(lambda.invoke().toString())
		}
	}

	/**
	 * @throws IllegalStateException if matrix has NaN component
	 */
	fun checkNotNaN() {
		if (!isFinite) {
			throw IllegalStateException("Matrix has NaN component")
		}
	}

	/**
	 * @throws IllegalArgumentException if matrix has NaN or infinite component
	 */
	fun requireIsValid() {
		requireIsFinite()
		requireNotNaN()
	}

	/**
	 * @throws IllegalStateException if matrix has NaN or infinite component
	 */
	fun checkIsValid() {
		requireIsFinite()
		requireNotNaN()
	}

	/**
	 * @throws IllegalArgumentException if matrix has NaN or infinite component
	 */
	inline fun requireIsValid(lambda: () -> Any) {
		requireIsFinite(lambda)
		requireNotNaN(lambda)
	}

	/**
	 * @throws IllegalStateException if matrix has NaN or infinite component
	 */
	inline fun checkIsValid(lambda: () -> Any) {
		requireIsFinite(lambda)
		requireNotNaN(lambda)
	}
}
