package ru.dbotthepony.kstarbound.client.gl.shader

import org.apache.logging.log4j.LogManager
import org.lwjgl.opengl.GL20.GL_COMPILE_STATUS
import org.lwjgl.opengl.GL20.glCompileShader
import org.lwjgl.opengl.GL20.glCreateShader
import org.lwjgl.opengl.GL20.glDeleteShader
import org.lwjgl.opengl.GL20.glGetShaderInfoLog
import org.lwjgl.opengl.GL20.glGetShaderiv
import org.lwjgl.opengl.GL20.glShaderSource
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import java.io.File

class GLShader(body: String, type: Int) {
	constructor(body: File, type: Int) : this(body.also { require(it.exists()) { "Shader file does not exists: $body" } }.readText(), type)
	val client = StarboundClient.current()
	val pointer = glCreateShader(type)

	init {
		checkForGLError()
		client.registerCleanable(this, ::glDeleteShader, pointer)
	}

	init {
		if (body == "") {
			throw IllegalArgumentException("Shader source is empty")
		}

		glShaderSource(pointer, body)
		glCompileShader(pointer)

		val result = intArrayOf(0)
		glGetShaderiv(pointer, GL_COMPILE_STATUS, result)

		if (result[0] == 0) {
			val split = body.split("\n")
			val reps = if (split.size < 10) 1 else if (split.size < 100) 2 else if (split.size < 1000) 3 else 4

			LOGGER.fatal("Next shader source has failed to compile, with line numbers:\n${split.withIndex().map {
				"${it.index}${" ".repeat((reps - it.index.toString().length).coerceAtLeast(0))}: ${it.value}"
			}.joinToString("\n")}")

			throw ShaderCompilationException(glGetShaderInfoLog(pointer))
		}

		checkForGLError()
	}

	companion object {
		private val LOGGER = LogManager.getLogger()
	}
}
