#!/usr/bin/env python3

#note: image templates: https://boardgamegeek.com/thread/813176/card-templates

#TODO: dynamic text sizes
#TODO: remote upload?

import json
from PIL import Image, ImageDraw, ImageFont
import textwrap
import math
import os

IMG_HERO_CHAR_FRONT = Image.open("images/HeroCharFront.png")
IMG_HERO_CHAR_BACK = Image.open("images/HeroCharBack.png")
IMG_HERO_DECK = Image.open("images/HeroCard.png")
IMG_TARGET_HP = Image.open("images/targetHP.png")

FONT_KEYWORD = ImageFont.truetype("fonts/RedStateBlueStateBB_reg.otf", size=40)
FONT_TITLE = ImageFont.truetype("fonts/CrashLandingBB.otf", size=60)
FONT_DESCRIPTION = ImageFont.truetype("fonts/RedStateBlueStateBB_reg.otf", size=30)
FONT_TARGET_HP = ImageFont.truetype("fonts/CrashLandingBB.otf", size=120)
FONT_CHAR_HP = ImageFont.truetype("fonts/ap.ttf", size=120)

def drawTextIf(draw, position, font, card, key, wrap=False):
    if key in card:
        text = str(card[key])

        if wrap:
            # badly wrap text to fit on card
            text = '\n'.join(textwrap.fill(line.strip(), wrap,
                                           break_long_words=False,
                                           replace_whitespace=False)
                             for line in text.splitlines())
        draw.text(position, text, font=font, fill="#000000")

def addCardToBase(baseImg, baseX, cardNum, cardImg):
    baseImg.paste(cardImg, ((cardNum % baseX) * cardImg.width,
                            int(cardNum / baseX) * cardImg.height))

def makeFaces(deckJson, outfile):
    # TODO: probably a more optimal way to fit cards
    baseX = math.ceil(math.sqrt(len(deckJson['deck']) +
                                len(deckJson['character']) * 2))
    baseImage = Image.new('RGB', (IMG_HERO_DECK.width * baseX,
                                  IMG_HERO_DECK.height * baseX))

    cardNum = 0
    # Make a card for each hero character card
    for card in deckJson['character']:
        cardFrontImg = IMG_HERO_CHAR_FRONT.copy()
        draw = ImageDraw.Draw(cardFrontImg)
        drawTextIf(draw, (150, 70), FONT_CHAR_HP, card, 'name')
        drawTextIf(draw, (100, 900), FONT_DESCRIPTION, card, 'power', 40)
        drawTextIf(draw, (53, 260), FONT_CHAR_HP, card, 'hp')
        addCardToBase(baseImage, baseX, cardNum, cardFrontImg)
        cardNum += 1

        cardBackImg = IMG_HERO_CHAR_BACK.copy()
        draw = ImageDraw.Draw(cardBackImg)
        drawTextIf(draw, (150, 70), FONT_CHAR_HP, card, 'name')
        drawTextIf(draw, (80, 800), FONT_DESCRIPTION, card, 'incapacitated', 43)
        addCardToBase(baseImage, baseX, cardNum, cardBackImg)
        cardNum += 1

    # Make a card for each card in the deck
    for card in deckJson['deck']:
        cardImg = IMG_HERO_DECK.copy()

        if 'hp' in card: # Draw HP marker, if it exists
            # self mask for transparency
            cardImg.paste(IMG_TARGET_HP, (510, 36), IMG_TARGET_HP)

        draw = ImageDraw.Draw(cardImg)
        drawTextIf(draw, (52, 50), FONT_TITLE, card, 'name')
        drawTextIf(draw, (85, 610), FONT_KEYWORD, card, 'type')
        drawTextIf(draw, (52, 670), FONT_DESCRIPTION, card, 'description', 46)
        drawTextIf(draw, (120, 910), FONT_DESCRIPTION, card, 'flavor')
        drawTextIf(draw, (600, 40), FONT_TARGET_HP, card, 'hp')
        addCardToBase(baseImage, baseX, cardNum, cardImg)
        cardNum += 1

    baseImage.save(outfile + ".png", "PNG")
    return (baseX, baseX)

def makeJson(deckJson, imgWidth, imgHeight, outfile):
    with open("templates/deck.json") as f:
        outJson = json.load(f)
    with open("templates/card.json") as f:
        cardTemplate = json.load(f)

    # number of cards in x and y direction
    outJson['ObjectStates'][0]['CustomDeck']['1'].update(
        {"NumWidth": imgWidth,
         "NumHeight": imgHeight,
         #"FaceURL": "http://adam-desktop.dyn.wpi.edu:8000/" + outfile + ".png",
         "FaceURL": "file://" + os.getcwd() + "/" + outfile + ".png",
         "BackURL": "http://cloud-3.steamusercontent.com/ugc/156906385556221451/CE2C3AFE1759790CB0B532FFD636D05A99EC91F4/"})

    # decks start at (10 * deck id)
    cardNum = 100
    for card in deckJson['character']:
        outJson['ObjectStates'][0]['DeckIDs'].append(cardNum)

        # add front card with back as second state
        cardOutBack = cardTemplate.copy()
        cardOutBack.update({"Nickname": card['name'],
                        "Description": "Incapacitated",
                            "CardID": cardNum + 1})
        cardOut = cardTemplate.copy()
        cardOut.update({"Nickname": card['name'],
                        "Description": "Active",
                        "CardID": cardNum,
                        "States": {"2": cardOutBack}})
        outJson['ObjectStates'][0]['ContainedObjects'].append(cardOut)
        cardNum += 2

    for card in deckJson['deck']:
        for i in range(0, card['count']):
            outJson['ObjectStates'][0]['DeckIDs'].append(cardNum)

            # add a card object thing for each card, and give it a name
            cardOut = cardTemplate.copy()
            cardOut.update({"Nickname": card['name'],
                            "Description": card.get('type', ""),
                            "CardID": cardNum})
            outJson['ObjectStates'][0]['ContainedObjects'].append(cardOut)
        cardNum += 1

    with open(outfile + ".json", "w") as f:
        json.dump(outJson, f)

with open("hero_3.json") as f:
    deckJson = json.load(f)

outfile = "out"

imgWidth, imgHeight = makeFaces(deckJson, outfile)
makeJson(deckJson, imgWidth, imgHeight, outfile)
