#!/usr/bin/env python3

# This script is used to generate the binary files for song appending
#
# The goal is to convert the "memory locations" generated by mmutil in soundbank.h
# into a binary file that the game can read during runtime.

import os, sys, struct, time, json, platform
from pathlib import Path

directory = 'audio'

build_type = "default"

try:
    build_type = sys.argv[1]
except:
    pass

files = ""
if(build_type == "default"):
    mmutil_header = "soundbank.h"                       # header generated by mmutil containing asset "memory locations"
    soundbank_binary = "soundbank.bin"                  # soundbank binary generated by mmutil containing sound effects (which gets appended onto the ROM afterwards)
    defaults_header = ""                                # default songs and sound effect definitions used in the game's code
    location_binary = "effect_locations.bin"            # binary containing the "memory locations" extracted from the mmutil header

    mmutil = sys.argv[2]
    gbfs = sys.argv[3]
    defaults_header = sys.argv[4]

    file_list = sys.argv[5::]

    for f in file_list:
        files += f + " "
else:
    mmutil_header = "tools/soundbank.h"
    soundbank_binary = "tools/soundbank.bin"
    defaults_header = "tools/sound_effects.txt"
    location_binary = "tools/effect_locations.bin"

    # build mmutil input argument

    for filename in os.listdir(directory):
        if(filename.find('.wav') != -1):
            files += f"'{directory}/{filename}' "

        if(filename.find('.mod') != -1) or\
        (filename.find('.it') != -1) or\
        (filename.find('.xm') != -1) or\
        (filename.find('.S3M') != -1) or\
        (filename.find('.s3m') != -1):
            files += f"'{directory}/{filename}' "

    mmutil = Path("./tools/mmutil.exe")

print(files)
# run mmutil
if platform.system() == 'Linux' and build_type != "default":
    if platform.machine() == 'arm64' or platform.machine() == 'aarch64':
        command = f"/bin/sh -c \"./tools/ape.aarch64 {mmutil} {files} -o{soundbank_binary} -h{mmutil_header}\""
    else:
        command = f"/bin/sh -c \"./tools/ape.x86_64 {mmutil} {files} -o{soundbank_binary} -h{mmutil_header}\""
    os.system(command)
else:
    command = f"{mmutil} {files} -o{soundbank_binary} -h{mmutil_header}"
    os.system(command)

# wait for mmutil to finish
print("Waiting for header...")
tries = 0
while tries < 100:
    if os.path.exists(mmutil_header):
        break

    time.sleep(0.1)

    tries += 1
else:
    print("Timed out waiting for header.")
    sys.exit()

# place the generated "memory locations" from soundbank.h into dictionaries

effect_list = {}
song_list = {}

songs = {
    "menu" : [],
    "game" : [],
}

def sortFunc(a):
    return a["name"];

with open(mmutil_header) as f:
    for line in f:
        line = line.split()[1:]#split into words and ditch #define

        if(line[0].find('MSL') != -1):
            continue

        if(line[0].find('SFX') != -1):
            effect_list[line[0]] = int(line[1])

        elif(line[0].find('MOD') != -1):
            key = "game"

            if(line[0].find('MENU_') != -1):
                key = "menu"

            name = line[0].replace("GAME_","").replace("MENU_","")

            songs[key].append(
                {
                    "name" : name,
                    "location" : int(line[1])
                }
            )

    songs["menu"].sort(key=sortFunc)
    songs["game"].sort(key=sortFunc)

print("\nsfx locations: ")
print(json.dumps(effect_list,indent=2))

# create lists containing the "memory locations" for the default assets in audio_files.h

sfx = []

with open(defaults_header) as f:
    for line in f:
        if (line.find("SFX") != -1):
            line = line.replace("\n","")

            try:
                sfx.append(effect_list[line])
            except:
                sfx.append(-1)

print("songs: ")
print(json.dumps(songs,indent=2))

# finally, create the output location_binary file
with open(location_binary,"wb") as result:
    def write(num):
        result.write(struct.pack('<i',int(num)))

    write(81) # save tag, exists validate binary

    # sfx count and locations
    write(len(sfx))
    for s in sfx:
        write(s)

    # write menu songs
    write(len(songs["menu"]))
    for song in songs["menu"]:
        write(song["location"])

    # write game songs
    write(len(songs["game"]))
    for song in songs["game"]:
        write(song["location"])

if(build_type == "default"):
    os.system(f"{gbfs} 'audio.gbfs' {soundbank_binary} {location_binary}")
