import w3g
import sys

# tttttttt;Eee;aaa...
#
# tttttttt  32bit, 8char hexadecimal number, time in ms
# aaa...    variable length argument string A
# Eee       3 char event type, starting with player number E (0 or 1), the
#           rest can be:
#
#   ma    set map to A
#   ra    set player's race to A (o,h,n,u)
#   ni    set player's nickname to A
#   cl    player clicks at coords in A (2 16bit hexadecimals)
#   wi    player wins
#   bu    player starts building, A starts with coords, then building follows
#   tu    player starts training normal unit A
#   th    player starts training hero A
#   ca    player casts A
#   up    player upgrades A
#   ti    player starts researching tier 2 or 3 (specified in A)
#   hl    player's hero learns ability A
#   ch    player says A in chat
#   lv    player levels up (or trains if 1st) a hero A
#   ap    player's current APM is A (1 16bit hexadecimal)
#   ac    other action, described in A

def strStartsWith(string,start):
  return string[:len(start)] == start

def printEvent(timeMs,eventType,arg):
  print("{0:08x};".format(timeMs) + eventType + ";" + arg)

def coordsToStr(coords):
  result = ""

  for i in range(2):
    result += "{0:04x}".format(int((65535 * (event.loc[i] + w3g.MAXPOS)) / (2 * w3g.MAXPOS)))

  return result

def abilityIsHero(ability):
  return w3g.ITEMS[ability] in [
    "Paladin", "Archmage", "Mountain King", "Blood Mage"
    "Priestess of the Moon", "Keeper of the Grove", "Demon Hunter", "Warden",
    "Far Seer",  "Blademaster", "Tauren Chieftain", "Shadow Hunter",   
    "Death Knight", "Dread Lord", "Lich", "Crypt Lord",
    "Pandaren Brewmaster", "Dark Ranger", "Naga Sea Witch", "Pit Lord", "Beastmaster", "Goblin Tinker", "Firelord", "Goblin Alchemist"
    ]

def abilityIsBuilding(ability): 
  return w3g.ITEMS[ability] in [
    "Ancient of Lore",
    "Ancient of War",
    "Ancient of Wind",
    "Altar of Elders",
    "Ancient of Wonders",
    "Hunter\"s Hall",
    "Chimaera Roost",
    "Entangled Gold Mine",
    "Moon Well",
    "Tree of Life",
    "Ancient Protector",
    "Altar of Kings",
    "Workshop",
    "Arcane Sanctum",
    "Barracks",
    "Blacksmith",
    "Aviary",
    "Lumber Mill",
    "Bear Den",
    "Town Hall",
    "Arcane Vault",
    "Watch Tower",
    "Pig Farm",
    "House",
    "Altar of Storms",
    "Orc Barracks",
    "Beastiary",
    "Forge",
    "Great Hall",
    "Spirit Lodge",
    "Burrow",
    "Tauren Totem",
    "Voodoo Lounge",
    "Orc Watch Tower",
    "Altar of Darkness",
    "Boneyard",
    "Haunted Gold Mine",
    "Graveyard",
    "Necropolis",
    "Sacrificial Pit",
    "Crypt",
    "Slaughterhouse",
    "Tomb of Relics",
    "Ziggurat"
    ]

def abilityIsHeroLearn(ability):
  return w3g.ITEMS[ability][:3] != "Use" and w3g.ITEMS[ability].find(":") >= 0

def abilityIsUnit(ability):
  return w3g.ITEMS[ability] in [
    "Archer",
    "Ballista",
    "Cenarius",
    "Chimeara",
    "Druid of the Claw",
    "Druid of the Talon",
    "Dryad",
    "Faerie Dragon",
    "Hippogryph",
    "Mountain Giant",
    "Huntress",
    "Wisp",
    "Blood Elf Priest",
    "Blood Elf Sorceress",
    "High Elf Footman",
    "Dragonhawk Rider",
    "Footman",
    "Gryphon Rider",
    "Flying Machine",
    "High Elf Swordman",
    "Priest",
    "Mortar",
    "Siege Engine",
    "Peasant",
    "Rifleman",
    "Siege Engine (Rocket)",
    "Sorceress",
    "Spell Breaker",
    "Felhound",
    "Furbolg Tracker",
    "Furbolg Elder",
    "Furbolg Champion",
    "Furbolg",
    "Furbolg Shaman",
    "Sapper",
    "High Elf Archer",
    "High Elf Barracks",
    "Blood Elf Peasant",
    "Dragon Turtle",
    "Mur\"gul Slave",
    "Naga Sorceress",
    "Mur\"gul Reaver",
    "Naga Royal Guard",
    "Naga Siren",
    "Tidal Guardian",
    "Ogre Magi",
    "Orc Dragonrider",
    "Forest Troll Shadow Priest",
    "Burning Archer",
    "Snap Dragon",
    "Hellcaller",
    "Soulstealer",
    "Shadowdancer",
    "Satyr",
    "Dragon Hawk",
    "Zepplin",
    "Catapult",
    "Troll Witch Doctor",
    "Grunt",
    "Troll Headhunter",
    "Kodo Beast",
    "Peon",
    "Raider",
    "Shaman",
    "Tauren",
    "Troll Berserker",
    "Troll Batrider",
    "Wyvern",
    "Abomination",
    "Acolyte",
    "Banshee",
    "Pit Fiend",
    "Frost Wyrm",
    "Gargoyle",
    "Ghoul",
    "Meat Wagon",
    "Necromancer",
    "Obsidian Statue",
    "Shade",
    "Burning Archer",
    "Dragon Hawk",
    "Bandit",
    "Rogue",
    "Enforcer",
    "Assassin",
    "Black Drake",
    "Red Dragon Whelp",
    "Black Dragon Whelp",
    "Red Drake",
    "Black Dragon",
    "Red Dragon",
    "Blue Dragon",
    "Blue Dragon Whelp",
    "Blue Drake",
    "Bronze Dragon",
    "Bronze Drake",
    "Bronze Dragon Whelp",
    "Green Dragon",
    "Green Drake",
    "Green Dragon Whelp",
    "Centaur Archer",
    "Centaur Outrunner",
    "Centaur Drudge",
    "Dark Troll High Priest",
    "Dark Troll Shadow Priest",
    "Dark Troll Berserker",
    "Dark Troll WarLord",
    "Dark Troll",
    "Dark Troll Trapper",
    "Forest Troll High Priest",
    "Forest Troll Shadow Priest",
    "Forest Troll",
    "Forest Troll Berserker",
    "Forest Troll Trapper",
    "Forest Troll WarLord",
    "Mud Golem",
    "Goblin Shredder",
    "Furbolg Shaman",
    "Gnoll Poacher",
    "Gnoll Assassin",
    "Gnoll",
    "Gnoll Brute",
    "Gnoll Warden",
    "Gnoll Overseer",
    "Goblin Sapper",
    "Harpy Rogue",
    "Harpy Windwitch",
    "Ice Troll Berserker",
    "Ice Troll Trapper",
    "Kobold",
    "Kobold Geomancer",
    "Thunder Lizard",
    "Murloc Flesheater",
    "Murloc Huntsman",
    "Wildkin",
    "Razormane Medicine Man",
    "Nerubian Warrior",
    "Nerubian Webspinner",
    "Ogre Warrior",
    "Ogre Mauler",
    "Ogre Lord",
    "Ogre Magi",
    "Frost Revenant",
    "Sludge Flinger",
    "Satyr Shadowdancer",
    "Satyr Soulstealer",
    "Goblin Zeppelin",
    "Giant Sea Turtle",
    "Makrura Deepseer",
    "Makrura Snapper",
    "Mur\"gul Snarecaster",
    "Spider Crab Shorecrawler",
    "Transport Ship",
    "Spider Crab Limbripper",
    "Spider Crab Behemoth",
    "Blue Dragonspawn Meddler",
    "Magnataur Warrior",
    "Barbed Arachnathid",
    "Barbed Arachnathid",
    "Polar Furbolg Shaman",
    "Magic Vault",
    "Icy Treasure Box",
    "Fel Beast",
    "Draenei Darkslayer",
    "Draenei Disciple",
    "Voidwalker",
    "Greater Voidwalker",
    "Nether Dragon Hatchling",
    "Nether Drake",
    "Nether Dragon"
    ]

f = w3g.File(sys.argv[1])

printEvent(0,"0ma",f.map_name)

players = []

for i in range(2):
  players.append({})
  players[i]["id"]= -1
  players[i]["race"] = "?"
  players[i]["name"] = "?"
  players[i]["won"] = False

winner = f.winner()

for i in range(len(f.slot_records)):
  if f.slot_records[i].team < 12:
    if players[0]["id"] < 0:
      players[0]["id"] = f.slot_records[i].player_id
    else:
      players[1]["id"] = f.slot_records[i].player_id
      break

for i in range(2):
  players[i]["race"] = f.player_race(players[i]["id"])
  players[i]["name"] = f.player_name(players[i]["id"])

  if f.winner() == players[i]["id"]:
    players[i]["won"] = True

for i in range(2):
  printEvent(0,str(i) + "ni",players[i]["name"])
  printEvent(0,str(i) + "ra",players[i]["race"])

for event in f.events:
  pid = event.player_id

  if pid == players[0]["id"] or pid == players[1]["id"]:
    pid = "0" if pid == players[0]["id"] else "1"

    if isinstance(event,w3g.Ability):
      abilityStr = w3g.ITEMS[event.ability]

      if abilityIsHero(event.ability):
        printEvent(event.time,pid + "th",abilityStr)
      elif abilityIsUnit(event.ability):
        printEvent(event.time,pid + "tu",abilityStr)
      elif abilityIsBuilding(event.ability):
        printEvent(event.time,pid + "bu",coordsToStr(event.loc) + " " + abilityStr)
      elif abilityIsHeroLearn(event.ability):
        printEvent(event.time,pid + "hl",abilityStr)
      elif strStartsWith(abilityStr,"Use ability: "):
        abilityStr = abilityStr[13:abilityStr.find(" (")]
        printEvent(event.time,pid + "ca",abilityStr)
      elif abilityStr in ["Keep", "Stronghold", "Tree of Ages", "Halls of the Dead"]:
        printEvent(event.time,pid + "ti","2")
      elif abilityStr in ["Castle", "Fortress", "Tree of Eternity", "Black Citadel"]:
        printEvent(event.time,pid + "ti","3")
      elif strStartsWith(abilityStr,"Upgrade "):
        abilityStr = abilityStr[8:]
        printEvent(event.time,pid + "up",abilityStr)
      elif (strStartsWith(abilityStr,"Swap item") or
        strStartsWith(abilityStr,"Use item") or
        strStartsWith(abilityStr,"Revive hero") or
        strStartsWith(abilityStr,"Call to arms") or
        strStartsWith(abilityStr,"Load unit") or
        strStartsWith(abilityStr,"Remove single") or
        strStartsWith(abilityStr,"Peons into")):
        printEvent(event.time,pid + "ac",w3g.ITEMS[event.ability])

    if isinstance(event,w3g.AbilityPosition):
      printEvent(event.time,pid + "cl",coordsToStr(event.loc))
    elif isinstance(event,w3g.Chat):
      printEvent(event.time,pid + "ch",event.msg)
    else:
      otherAction = ""

      if isinstance(event,w3g.LeftGame):
        otherAction = "left"
      elif isinstance(event,w3g.Pause):
        otherAction = "paused"
      elif isinstance(event,w3g.Resume):
        otherAction = "resumed"
      elif isinstance(event,w3g.GiveItem):
        otherAction = "gives item"
      elif isinstance(event,w3g.CancelHeroRevival):
        otherAction = "cancels hero revival"
      elif isinstance(event,w3g.MinimapSignal):
        otherAction = "map pings"
      elif isinstance(event,w3g.HeroSkillSubmenu):
        otherAction = "opens hero skill menu"
      elif isinstance(event,w3g.BuildingSubmenu):
        otherAction = "opens build menu"

      if len(otherAction) != 0:
        printEvent(event.time,pid + "ac",otherAction)
  elif isinstance(event,w3g.Chat): # observer chat
    printEvent(event.time,"3ch",str(event.player_id) + ": " + event.msg)
