package theorycrafter.tournaments

import theorycrafter.storage.*
import theorycrafter.utils.StoredCollection
import theorycrafter.utils.with
import java.io.DataInput
import java.io.DataOutput


/**
 * The data of a serialized representation of a tournament compositiom.
 */
class StoredComposition(


	/**
	 * The composition id; `null` if it hasn't been written to disk yet.
	 */
	id: Int? = null,


    /**
     * The name of the composition.
     */
    val name: String,


    /**
     * The list of ships in this composition; a `null` value indicates an empty slot.
     */
    val ships: List<StoredCompositionShip?>,


    /**
     * The composition note.
     */
    val note: String = ""


) {


    /**
	 * The id of the composition on disk; `null` if it hasn't been saved to disk yet.
	 */
	var id: Int? = id
	set(value) {
		if (field != null)
			throw IllegalArgumentException("Composition $this already has an id")
		field = value
	}


    /**
     * The composition ship data we store on disk.
     */
    class StoredCompositionShip(
        val shipTypeId: Int,
        val amount: Int? = null,
        val fitId: Int?,
        val active: Boolean
    ) {

        constructor(ship: Composition.Ship): this(
            shipTypeId = ship.shipType.itemId,
            amount = ship.amount,
            fitId = ship.fitId,
            active = ship.active
        )

    }


    /**
     * The serializer for compositions.
     */
    object Serializer : StoredCollection.Serializer<StoredComposition> {


        override val itemFormatVersion = 4


        /**
         * Reads the list of ships in the composition.
         */
        private fun DataInput.readShips(formatVersion: Int) = List(readUnsignedByte()) {
            val shipTypeId = readOptionalEveId()
            if (shipTypeId == null)
                null
            else {
                StoredCompositionShip(
                    shipTypeId = shipTypeId,
                    amount = if (formatVersion >= 4) readOptionalInt() else null,
                    fitId = if (formatVersion >= 2) readOptionalInt() else null,
                    active = readBoolean(),
                )
            }
        }


        /**
         * Writes the list of ships in the composition.
         */
        private fun DataOutput.writeShips(ships: List<StoredCompositionShip?>) {
            writeByte(ships.size)
            for (ship in ships) {
                writeOptionalEveId(ship?.shipTypeId)
                if (ship == null)
                    continue
                writeOptionalInt(ship.amount)
                writeOptionalInt(ship.fitId)
                writeBoolean(ship.active)
            }
        }


        override fun readItem(input: DataInput, formatVersion: Int): StoredComposition = with(input) {
            StoredComposition(
                id = readInt(),
                name = readUTF(),
                ships = readShips(formatVersion),
                note = if (formatVersion >= 3) readUTF() else ""
            )
        }


        override fun writeItem(output: DataOutput, item: StoredComposition) {
            val compId = item.id ?: throw IllegalArgumentException("Composition has not been assigned an id")

            with(output, item) {
                writeEveId(compId)
                writeUTF(name)
                writeShips(ships)
                writeUTF(item.note)
            }
        }


    }


}
