package net.torvald.terrarum.modulebasegame

import net.torvald.reflection.extortField
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.ClusteredFormatDOM
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.archivers.Clustfile
import net.torvald.terrarum.savegame.*
import net.torvald.terrarum.serialise.Common
import net.torvald.terrarum.serialise.toBig64
import java.io.File

/**
 * Created by minjaesong on 2024-10-08.
 */
object SavegameConverter {

    fun type254toType11(infile: File, outFile: File) {
        val type254DOM = VDUtil.readDiskArchive(infile)
        type254DOMtoType11Disk(type254DOM, outFile)
    }

    private val getGenver = Regex("""(?<="genver" ?: ?)[0-9]+""")

    private fun type254DOMtoType11Disk(type254DOM: VirtualDisk, outFile: File) {
        val version: Long = when (type254DOM.saveKind) {
            VDSaveKind.PLAYER_DATA, VDSaveKind.WORLD_DATA -> {
                val savegameInfo = ByteArray64Reader(type254DOM.getFile(VDFileID.SAVEGAMEINFO)!!.bytes, Common.CHARSET)
                CharArray(128).let {
                    savegameInfo.read(it, 0, 128)
                    getGenver.find(String(it))?.value?.toLong()!!
                }
            }
            else -> 0L
        }

        val newDisk = ClusteredFormatDOM.createNewArchive(
            outFile,
            Common.CHARSET,
            type254DOM.getDiskName(Common.CHARSET),
            ClusteredFormatDOM.MAX_CAPA_IN_SECTORS,
            byteArrayOf(
                -1, // pad
                byteArrayOf(15, -1)[type254DOM.saveOrigin.ushr(4).and(1)], // imported/native
                byteArrayOf(0x00, 0x50, 0x57)[type254DOM.saveKind], // player/world
                byteArrayOf(0x6d, 0x6d, 0x61, 0x61)[type254DOM.saveMode], // manual/auto
                type254DOM.extraInfoBytes[4], type254DOM.extraInfoBytes[5], // snapshot info
                0, 0,// reserved
            ) + version.toBig64() // VERSION_RAW in big-endian
        )
        val DOM = ClusteredFormatDOM(newDisk)
        val root = DOM.getRootFile()

        var cnt = 0

        // do filecopy
        type254DOM.entries.filter { it.key != 0L }.forEach { entryID, diskEntry ->
            val filename = Common.type254EntryIDtoType17Filename(entryID)

            println("Converting file $filename; old cluster size: ${DOM.usedClusterCount}; old ROOT cluster num: ${DOM.getRootDir().entryID}; fileCount: $cnt")

            if (diskEntry.contents !is EntryFile) throw IllegalStateException("Entry in the savegame is not a file (${diskEntry.contents.javaClass.simpleName})")

            cnt += 1
            val entry = diskEntry.contents as EntryFile

            val oldBytes = entry.bytes.toByteArray()

            Clustfile(DOM, root, filename).let { file ->
                // write bytes
                file.createNewFile()
                file.writeBytes(oldBytes)
                // modify attributes
                val FAT = file.extortField<ClusteredFormatDOM.FATEntry>("FAT")!!
                FAT.creationDate = diskEntry.creationDate
                FAT.modificationDate = diskEntry.modificationDate
            }
        }

        DOM.dispose()
    }

}

fun main() {
    val infile = File("/home/torvald/.Terrarum/Worlds/2d3e3aa5-bf5b-45c8-acf6-66ef9f1c2217")
    val outfile = File("/home/torvald/.Terrarum/Worlds/2d3e3aa5-bf5b-45c8-acf6-66ef9f1c2217.terrarumworld")

    SavegameConverter.type254toType11(infile, outfile)
}