import os
import sys
import hashlib

from asar import init as asar_init, close as asar_close, patch as asar_patch, geterrors as asar_errors, getprints as asar_prints, getwarnings as asar_warnings

JAP10HASH = '03a63945398191337e896e5771f77173'

try:
    from yaml import CLoader as Loader
except ImportError:
    from yaml import Loader


def int16_as_bytes(value):
    value = value & 0xFFFF
    return [value & 0xFF, (value >> 8) & 0xFF]


def int32_as_bytes(value):
    value = value & 0xFFFFFFFF
    return [value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF]


def is_bundled():
    return getattr(sys, 'frozen', False)


def local_path(path):
    if local_path.cached_path:
        return os.path.join(local_path.cached_path, path)

    elif is_bundled():
        if hasattr(sys, "_MEIPASS"):
            # we are running in a PyInstaller bundle
            local_path.cached_path = sys._MEIPASS  # pylint: disable=protected-access,no-member
        else:
            # cx_Freeze
            local_path.cached_path = os.path.dirname(os.path.abspath(sys.argv[0]))
    else:
        # we are running in a normal Python environment
        import __main__
        local_path.cached_path = os.path.dirname(os.path.abspath(__main__.__file__))

    return os.path.join(local_path.cached_path, path)


local_path.cached_path = None


def make_new_base2current(old_rom_data, new_rom_data):
    from collections import OrderedDict
    import json
    # extend to 2 mb
    old_rom_data.extend(bytearray([0x00]) * (2097152 - len(old_rom_data)))

    out_data = OrderedDict()
    for idx, old in enumerate(old_rom_data):
        new = new_rom_data[idx]
        if old != new:
            out_data[idx] = [int(new)]
    for offset in reversed(list(out_data.keys())):
        if offset - 1 in out_data:
            out_data[offset-1].extend(out_data.pop(offset))
    with open('../base2current.json', 'wt') as outfile:
        json.dump([{key: value} for key, value in out_data.items()], outfile, separators=(",", ":"))

    basemd5 = hashlib.md5()
    basemd5.update(new_rom_data)
    return "New Rom Hash: " + basemd5.hexdigest()


if __name__ == '__main__':
    try:
        asar_init()
        print("Asar DLL initialized")
        
        print("Opening Base rom")
        with open('../alttp.sfc', 'rb') as stream:
            old_rom_data = bytearray(stream.read())
            
        if len(old_rom_data) % 0x400 == 0x200:
            old_rom_data = old_rom_data[0x200:]
            
        basemd5 = hashlib.md5()
        basemd5.update(old_rom_data)
        if JAP10HASH != basemd5.hexdigest():
            raise Exception("Base rom is not 'Zelda no Densetsu - Kamigami no Triforce (J) (V1.0)'")
            
        print("Patching Base Rom")
        result, new_rom_data = asar_patch(os.path.abspath('LTTP_RND_GeneralBugfixes.asm'), old_rom_data)
        
        if result:
            with open('../working.sfc', 'wb') as stream:
                stream.write(new_rom_data)
            print("Success\n")
            print(make_new_base2current(old_rom_data, new_rom_data))
            prints = asar_prints()
            for p in prints:
                print(p)
        else:
            errors = asar_errors()
            print("\nErrors: " + str(len(errors)))
            for error in errors:
                print (error)
        warnings = asar_warnings()
        print("\nWarnings: " + str(len(warnings)))
        for w in warnings:
            print(w)
        
        asar_close()
    except:
        import traceback
        traceback.print_exc()

