package mg.dot.feufaro.midi

import mg.dot.feufaro.solfa.ParseULine
import mg.dot.feufaro.solfa.Transpose


data class MidiPitch (
    var voiceNumber: Int = 0,
    var octave: Int = 0,
    var pitch: String = "",
    var alter: String = "",
    var duration: Int = 0,
    var markers: List<String> = listOf(),
    var tick : Int = 0,
    var metaBytes: String = "",
    var metaByteSize: Int = 0,
    var metaType : Int = -1
) {
    var velocity: Int = 96
    companion object {
        var key: String = "C"
        var curVoiceNumber: Int = 0
        var nextTick : MutableList<Int> = mutableListOf()
    }
    fun setMeta(type: Int, tickMeta: Int, nb: Int, data0: Int, data1: Int = 0, data2: Int = 0, data3: Int = 0, data4: Int = 0) {
        metaBytes = ""+ data0.toChar() + data1.toChar() + data2.toChar() + data3.toChar() + data4.toChar()
        tick = tickMeta
        metaByteSize = nb
        metaType = type
    }
    fun setNote(note: String, theDuration: Int) {
        val midiPitch = Transpose.transposeToMidi(note, key, "C")
        velocity = if (midiPitch < 0) {
            0
        } else {
            99
        }
        pitch = midiPitch.toString()
        duration = theDuration
        tick = nextTick.getOrNull(voiceNumber) ?: 0
        nextTick[voiceNumber] = theDuration + tick
        voiceNumber = curVoiceNumber
        metaType = -1
    }
    fun setMarker(theMarkers : MutableList<String>) {
        if (theMarkers.isNotEmpty()) {
            markers = theMarkers.toList()
        } else {
            markers = listOf()
        }
    }
    fun currentVoiceNumber(value: Int) {
        curVoiceNumber = value
        while (nextTick.size <= value) {
            nextTick.add(0)
        }
    }
    fun initKey(theKey: String) {
        key = theKey
        val armature = Transpose.toArmature(key)
        val tickMeta = nextTick.getOrNull(0) ?: 0
        setMeta(0x59, tickMeta, 2, armature)
    }
    fun initMeasure(theMeasure: String): Boolean {
        val numerator = theMeasure.replace(Regex("/.*"), "").toIntOrNull()
        val denominator = theMeasure.replace(Regex("^[^/]*/(\\d+).*$"), "$1").toIntOrNull() ?: 4
        val data1 = when (denominator) {
            1 -> 0
            2 -> 1
            4 -> 2
            8 -> 3
            16 -> 4
            else -> 5
        }
        val blankDuration = (4 * (numerator ?: 4) - ParseULine.blankDuration) * 15
        if (numerator != null) {
            setMeta(0x58, blankDuration, 4, numerator, data1, 60, 20)
            return true
        }
        return false
    }
    fun reset() {
        tick = 0
        nextTick.clear()
    }
}