from ..assembler import ASM
from .. import utils


def addBank3F(rom):
    # Bank3F is used to initialize the tile data in VRAM:1 at the start of the rom.
    # The normal rom does not use this tile data to maintain GB compatibility.
    rom.patch(0, 0x0150, ASM("""
        cp   $11 ; is running on Game Boy Color?
        jr   nz, notGBC
        ldh  a, [$4d]
        and  $80 ; do we need to switch the CPU speed?
        jr   nz, speedSwitchDone
        ; switch to GBC speed
        ld   a, $30
        ldh  [$00], a
        ld   a, $01
        ldh  [$4d], a
        xor  a
        ldh  [$ff], a
        stop
        db $00

    speedSwitchDone:
        xor  a
        ldh  [$70], a
        ld   a, $01 ; isGBC = true
        jr   Init

    notGBC:
        xor  a ; isGBC = false
    Init:
        """), ASM("""
        ; Check if we are a color gameboy, we require a color version now.
        cp $11
        jr nz, notGBC

        ; Switch to bank $3F to run our custom initializer
        ld   a, $3F
        ld   [$2100], a
        call $4000
        ; Switch back to bank 0 after loading our own initializer
        ld   a, $01
        ld   [$2100], a
        
        ; set a to 1 to indicate GBC
        ld   a, $01
        jr Init
    notGBC:
        xor a
    Init:
        """), fill_nop=True)

    rom.patch(0x3F, 0x0000, None, ASM("""
        ; switch speed
        ld   a, $30
        ldh  [$00], a
        ld   a, $01
        ldh  [$4d], a
        xor  a
        ldh  [$ff], a
        stop
        db $00

        ; Switch VRAM bank
        ld   a, $01
        ldh  [$4F], a

        call $28CF ; display off

        ; Use the GBC DMA to transfer our tile data
        ld   a, $68
        ldh  [$51], a
        ld   a, $00
        ldh  [$52], a

        ld   a, $80
        ldh  [$53], a
        ld   a, $00
        ldh  [$54], a

        ld   a, $7F
        ldh  [$55], a

    waitTillTransferDone:
        ldh  a, [$55]
        and  $80
        jr z, waitTillTransferDone

        ld   a, $70
        ldh  [$51], a
        ld   a, $00
        ldh  [$52], a

        ld   a, $88
        ldh  [$53], a
        ld   a, $00
        ldh  [$54], a

        ld   a, $7F
        ldh  [$55], a

    waitTillTransferDone2:
        ldh  a, [$55]
        and  $80
        jr z, waitTillTransferDone2

        ld   a, $68
        ldh  [$51], a
        ld   a, $00
        ldh  [$52], a

        ld   a, $90
        ldh  [$53], a
        ld   a, $00
        ldh  [$54], a

        ld   a, $7F
        ldh  [$55], a

    waitTillTransferDone3:
        ldh  a, [$55]
        and  $80
        jr z, waitTillTransferDone3

        ; Switch VRAM bank back
        ld   a, $00
        ldh  [$4F], a

        ; Switch the display back on, else the later code hangs
        ld   a, $80
        ldh  [$40], a

    speedSwitchDone:
        xor  a
        ldh  [$70], a

        ; Check if we are running on a bad emulator
        ldh  [$02], a
        ldh  a, [$02]
        and  $7c
        cp   $7c
        jr   nz, badEmu

        ; Enable the timer to run 32 times per second
        xor  a
        ldh  [$06], a
        ld   a, $04
        ldh  [$07], a

        ; Set SB to $FF to indicate we have no data from hardware
        ld   a, $FF
        ldh  [$01], a
        ret
badEmu:
        xor  a
        ldh  [$40], a ; switch display off
        ; Load some palette
        ld   a, $80
        ldh  [$68], a
        xor  a
        ldh  [$69], a
        ldh  [$69], a
        ldh  [$69], a
        ldh  [$69], a

        ; Load a different gfx tile for the first gfx
        cpl
        ld   hl, $8000
        ld   c, $10
.loop:
        ldi  [hl], a
        dec  c
        jr   nz, .loop

        ld   a, $01
        ld   [$9800], a
        ld   [$9820], a
        ld   [$9840], a
        ld   [$9860], a
        ld   [$9880], a

        ld   [$9801], a
        ld   [$9841], a
        ld   [$9881], a

        ld   [$9822], a
        ld   [$9862], a

        ld   [$9824], a
        ld   [$9844], a
        ld   [$9864], a
        ld   [$9884], a

        ld   [$9805], a
        ld   [$9845], a

        ld   [$9826], a
        ld   [$9846], a
        ld   [$9866], a
        ld   [$9886], a

        ld   [$9808], a
        ld   [$9828], a
        ld   [$9848], a
        ld   [$9868], a
        ld   [$9888], a

        ld   [$9809], a
        ld   [$9889], a

        ld   [$982A], a
        ld   [$984A], a
        ld   [$986A], a

        ld   [$9900], a
        ld   [$9920], a
        ld   [$9940], a
        ld   [$9960], a
        ld   [$9980], a

        ld   [$9901], a
        ld   [$9941], a
        ld   [$9981], a

        ld   [$9903], a
        ld   [$9923], a
        ld   [$9943], a
        ld   [$9963], a
        ld   [$9983], a

        ld   [$9904], a
        ld   [$9925], a
        ld   [$9906], a

        ld   [$9907], a
        ld   [$9927], a
        ld   [$9947], a
        ld   [$9967], a
        ld   [$9987], a

        ld   [$9909], a
        ld   [$9929], a
        ld   [$9949], a
        ld   [$9969], a
        ld   [$9989], a

        ld   [$998A], a

        ld   [$990B], a
        ld   [$992B], a
        ld   [$994B], a
        ld   [$996B], a
        ld   [$998B], a

        ; lcd on
        ld   a, $91
        ldh  [$40], a
blockBadEmu:
        di
        jr   blockBadEmu
        
        """))

    # Copy all normal item graphics
    rom.banks[0x3F][0x2800:0x2B00] = rom.banks[0x2C][0x0800:0x0B00]  # main items
    rom.banks[0x3F][0x2B00:0x2C00] = rom.banks[0x2C][0x0C00:0x0D00]  # overworld key items
    rom.banks[0x3F][0x2C00:0x2D00] = rom.banks[0x32][0x3D00:0x3E00]  # dungeon key items
    # Create ruppee for palettes 0-3
    rom.banks[0x3F][0x2B80:0x2BA0] = rom.banks[0x3F][0x2A60:0x2A80]
    for n in range(0x2B80, 0x2BA0, 2):
        rom.banks[0x3F][n+1] ^= rom.banks[0x3F][n]

    # Create capacity upgrade arrows
    rom.banks[0x3F][0x2A30:0x2A40] = utils.createTileData("""
   33
  3113
 311113
33311333
  3113
  3333
""")
    rom.banks[0x3F][0x2A20:0x2A30] = rom.banks[0x3F][0x2A30:0x2A40]
    for n in range(0x2A20, 0x2A40, 2):
        rom.banks[0x3F][n] |= rom.banks[0x3F][n + 1]

    # Add the slime key and mushroom which are not in the above sets
    rom.banks[0x3F][0x2CC0:0x2D00] = rom.banks[0x2C][0x28C0:0x2900]
    # Add tunic sprites as well.
    rom.banks[0x3F][0x2C80:0x2CA0] = rom.banks[0x35][0x0F00:0x0F20]

    # Add the bowwow sprites
    rom.banks[0x3F][0x2D00:0x2E00] = rom.banks[0x2E][0x2400:0x2500]

    # Zol sprites, so we can have zol anywhere from a chest
    rom.banks[0x3F][0x2E00:0x2E60] = rom.banks[0x2E][0x1120:0x1180]
    # Patch gel(zol) entity to load sprites from the 2nd bank
    rom.patch(0x06, 0x3C09, "5202522254025422" "5200522054005420", "600A602A620A622A" "6008602862086228")
    rom.patch(0x07, 0x329B, "FFFFFFFF" "FFFFFFFF" "54005420" "52005220" "56005600",
                            "FFFFFFFF" "FFFFFFFF" "62086228" "60086028" "64086408")
    rom.patch(0x06, 0x3BFA, "56025622", "640A642A");


    # Cucco
    rom.banks[0x3F][0x2E80:0x2F00] = rom.banks[0x32][0x2500:0x2580]
    # Patch the cucco graphics to load from 2nd vram bank
    rom.patch(0x05, 0x0514,
              "5001" "5201" "5401" "5601" "5221" "5021" "5621" "5421",
              "6809" "6A09" "6C09" "6E09" "6A29" "6829" "6E29" "6C29")
    # Song symbols
    rom.banks[0x3F][0x2F00:0x2F60] = utils.createTileData("""


     ...
  . .222
 .2.2222
.22.222.
.22222.3
.2..22.3
 .33...3
 .33.3.3
 ..233.3
.22.2333
.222.233
 .222...
  ...
""" + """


      ..
     .22
    .223
   ..222
  .33.22
  .3..22
  .33.33
   ..23.
  ..233.
 .22.333
.22..233
 ..  .23
      ..
""" + """


    ...
   .222.
  .2.332
  .23.32
  .233.2
 .222222
.2222222
.2..22.2
.2.3.222
.22...22
 .2333..
  .23333
   .....""", " .23")

    # Ghost
    rom.banks[0x3F][0x2F60:0x2FE0] = rom.banks[0x32][0x1800:0x1880]

    # Instruments
    rom.banks[0x3F][0x3000:0x3200] = rom.banks[0x31][0x1000:0x1200]
    # Patch the egg song event to use the 2nd vram sprites
    rom.patch(0x19, 0x0BAC,
        "5006520654065606"
        "58065A065C065E06"
        "6006620664066606"
        "68066A066C066E06",
        "800E820E840E860E"
        "880E8A0E8C0E8E0E"
        "900E920E940E960E"
        "980E9A0E9C0E9E0E"
    )

    # Rooster
    rom.banks[0x3F][0x3200:0x3300] = rom.banks[0x32][0x1D00:0x1E00]
    rom.patch(0x19, 0x19BC,
              "42234023" "46234423" "40034203" "44034603" "4C034C23" "4E034E23" "48034823" "4A034A23",
              "A22BA02B" "A62BA42B" "A00BA20B" "A40BA60B" "AC0BAC2B" "AE0BAE2B" "A80BA82B" "AA0BAA2B")
    # Replace some main item graphics with the rooster
    rom.banks[0x2C][0x0900:0x0940] = utils.createTileData(utils.tileDataToString(rom.banks[0x32][0x1D00:0x1D40]), " 321")

    # Trade sequence items
    rom.banks[0x3F][0x3300:0x3640] = rom.banks[0x2C][0x0400:0x0740]
