package me.eater.threedom.gl.vertex

import org.joml.*
import org.lwjgl.opengl.GL30.*
import java.nio.ByteBuffer
import kotlin.reflect.KProperty

abstract class VertexDataPoint<T>(val type: Int, var value: T, val length: Int, val slots: Int = 1) {
    abstract fun write(position: Int, buffer: ByteBuffer)

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }

    class SingleInt(value: Int) : VertexDataPoint<Int>(GL_INT, value, 4) {
        override fun write(position: Int, buffer: ByteBuffer) {
            buffer.putInt(position, value)
        }

    }

    class SingleFloat(value: Float) : VertexDataPoint<Float>(GL_FLOAT, value, 4) {
        override fun write(position: Int, buffer: ByteBuffer) {
            buffer.putFloat(position, value)
        }
    }

    class SingleDouble(value: Double) : VertexDataPoint<Double>(GL_DOUBLE, value, 8) {
        override fun write(position: Int, buffer: ByteBuffer) {
            buffer.putDouble(position, value)
        }
    }

    class SingleBoolean(value: Boolean) : VertexDataPoint<Boolean>(GL_BOOL, value, 1) {
        override fun write(position: Int, buffer: ByteBuffer) {
            buffer.put(position, if (value) 1 else 2)
        }
    }

    class Vec2(value: Vector2fc) : VertexDataPoint<Vector2fc>(GL_FLOAT, value, 8, 2) {
        override fun write(position: Int, buffer: ByteBuffer) {
            value.get(position, buffer)
        }
    }

    class Vec3(value: Vector3fc) : VertexDataPoint<Vector3fc>(GL_FLOAT, value, 12, 3) {
        override fun write(position: Int, buffer: ByteBuffer) {
            value.get(position, buffer)
        }
    }

    class Vec4(value: Vector4fc) : VertexDataPoint<Vector4fc>(GL_FLOAT, value, 16, 4) {
        override fun write(position: Int, buffer: ByteBuffer) {
            value.get(position, buffer)
        }
    }

    class Mat3(value: Matrix3fc) : VertexDataPoint<Matrix3fc>(GL_FLOAT, value, 3 * 3 * 4, 9) {
        override fun write(position: Int, buffer: ByteBuffer) {
            value.get(position, buffer)
        }
    }

    class Mat4(value: Matrix4fc) : VertexDataPoint<Matrix4fc>(GL_FLOAT, value, 4 * 4 * 4, 16) {
        override fun write(position: Int, buffer: ByteBuffer) {
            value.get(position, buffer)
        }
    }
}
