#!/usr/bin/env python

# makePromoCards.py by Alex M. Fink
#  created on 22 February 2016
#
# No copyright. No license. Don't care.
#
# NOTE: To use this, you will need Python and a LaTeX distribution.
#       Commands are for Mac OS X, but should work on Linux.
#       Expansion to Windows should be pretty simple.
#
#
# This script is for generating sheets of cards, where each card has a unique
# promotional code and a unique QR code image with a unique link. The original
# intention is to generate promotional cards from Google PlayStore promo codes
# for paid apps. Twelve 3.5in x 2in cards are generated per sheet, and only a 
# multiple of twelve cards will be generated. Changing these specifics shouldn't
# be too hard, but these things are mostly hardcoded in here. If you want to 
# change any layout stuff, even if you don't know anything about LaTeX, it
# should be relatively easy. Sizes and positions are defined in the giant 
# preambleEtc string; they are all in inches, since \unitlength is set to 1in.
# Cutting guide marks are also drawn, intruding slightly onto the cards at 
# points; this seemed to work best using my printer. To use this script, at 
# minimum you will need to change the variables after the import commands below.


import os
import sys
import qrcode
import csv

# Edit these to your specifics
csvFileName = "dummycodes.csv"
cardImgFileName = "PromoGraphic.png"
pdflatex = "/usr/texbin/pdflatex"

# If you change this, other things in the code need to be changed manually.
numCardsPerPage = 12


# All of the spacing, sizing, and positioning is here
preambleEtc = \
"""\\documentclass[a4paper,landscape,12pt]{article}

% Generated by makePromoCards.py

\\pagestyle{empty}

%\\usepackage[showframe]{geometry}
\\usepackage{graphicx}

% \\usepackage[scaled]{beramono}
% \\usepackage[T1]{fontenc}

% Use Beramono because it has a nice zero and is monospaced
\\usepackage[scaled]{beramono}
\\renewcommand*\\familydefault{\\ttdefault} % Set default document text to "typewriter"
\\usepackage[T1]{fontenc}

% \\usepackage{calc}
% \\usepackage[nomessages]{fp}


% Margins? We don't need no stinkin' margins.
\\setlength{\\oddsidemargin}{0.25in}
\\setlength{\\evensidemargin}{0.25in}
\\setlength{\\topmargin}{0.0in}
\\setlength{\\headheight}{0.0in}
\\setlength{\\headsep}{0.0in}
\\setlength{\\marginparsep}{0.0in}
\\setlength{\\marginparwidth}{0.0in}
\\setlength{\\hoffset}{-1.0in}
\\setlength{\\voffset}{-1.0in}
\\setlength{\\footskip}{0.0in}
\\setlength{\\textwidth}{11.0in} %-0.85
\\setlength{\\textheight}{8.0in} %-0.2
%\\setlength{\\bottommargin}{-0.5in}


% Bottom-left coordinates of each card
\\newcommand{\\CardRowOne}{0}
\\newcommand{\\CardRowTwo}{2} % No extra vertical space
\\newcommand{\\CardRowThree}{4}
\\newcommand{\\CardRowFour}{6}
\\newcommand{\\CardColOne}{0}
\\newcommand{\\CardColTwo}{3.625} % 0.125in of horizontal spacing
\\newcommand{\\CardColThree}{7.25}

% Bottom-left coordinates of each alphanumeric code
%  Add the offsets here to the card locations
%  y = 0.0616667
%  x = 0.5
\\newcommand{\\CodeRowOne}{0.0616667}
\\newcommand{\\CodeRowTwo}{2.0616667} 
\\newcommand{\\CodeRowThree}{4.0616667}
\\newcommand{\\CodeRowFour}{6.0616667}
\\newcommand{\\CodeColOne}{0.53}
\\newcommand{\\CodeColTwo}{4.155} 
\\newcommand{\\CodeColThree}{7.78}

% Bottom-left coordinates of each QR code
%  Add the offsets here to the card locations
% x = 2.315
% y = 0.166667
\\newcommand{\\QRRowOne}{0.166667}
\\newcommand{\\QRRowTwo}{2.166667} 
\\newcommand{\\QRRowThree}{4.166667}
\\newcommand{\\QRRowFour}{6.166667}
\\newcommand{\\QRColOne}{2.385}
\\newcommand{\\QRColTwo}{6.010} 
\\newcommand{\\QRColThree}{9.635}

\\newcommand{\\QRWidth}{1.0in}
\\newcommand{\\QRHeight}{1.0in}

% Cutting marks
\\newcommand{\\MarkColOne}{0}
\\newcommand{\\MarkColTwo}{3.5625}
\\newcommand{\\MarkColThree}{7.1875}
\\newcommand{\\MarkColFour}{10.8125}
\\newcommand{\\MarkRowOne}{0}
\\newcommand{\\MarkRowTwo}{2}
\\newcommand{\\MarkRowThree}{4}
\\newcommand{\\MarkRowFour}{6}

\\begin{document}
\\setlength{\\unitlength}{1in}
"""

def parseCSVFile():
    codeList = []
    with open(csvFileName) as csvFile:
        csvReader = csv.reader(csvFile, delimiter = ' ')
        for promoCode in csvReader:
            codeList.append(promoCode[0]) # a list is returned, so grab the single element
        csvFile.close()
    return codeList

def generateQRCodeImage(codeString, inFileName):
    dataString = "https://play.google.com/store?code=" + codeString
    qr_ = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M) # 15% of errors are correctable
    qr_.add_data(dataString)
    img_ = qr_.make_image()
    img_.save('imgs/'+inFileName)

def makeAllQRCodeImages(codeList,numCodes):
    os.system("mkdir imgs")
    for i1 in range(numCodes):
        generateQRCodeImage(codeList[i1], 'qr_'+str(i1)+'.png')

def makePage(texFile, pageNum, codeList):
    texFile.write("\\begin{picture}(10.75,8.0)(0,0)\n")
    writeQRLines(texFile,pageNum)
    writeGrfxLines(texFile, pageNum)
    writeCodeLines(texFile, pageNum, codeList)
    writeMarkLines(texFile, pageNum)
    texFile.write("\\end{picture}\n")
    texFile.write("\\newpage\n")

def writeQRLines(texFile, pageNum):
    qrc = ["\\QRColOne", "\\QRColTwo", "\\QRColThree"]
    qrr = ["\\QRRowOne", "\\QRRowTwo", "\\QRRowThree", "\\QRRowFour"]
    fileNum = pageNum*numCardsPerPage
    texFile.write("% Unique QR Codes\n")
    for c1 in range(3):
        for r1 in range(4):
            texFile.write("\\put("+qrc[c1]+","+qrr[r1] + \
                "){\\includegraphics[width=\\QRWidth,height=\\QRHeight]{imgs/qr_" + \
                str(fileNum) + ".png}}\n")
            fileNum = fileNum + 1

def writeGrfxLines(texFile, pageNum):
    gc = ["\\CardColOne", "\\CardColTwo", "\\CardColThree"]
    gr = ["\\CardRowOne", "\\CardRowTwo", "\\CardRowThree", "\\CardRowFour"]
    texFile.write("% Common graphics\n")
    for c1 in range(3):
        for r1 in range(4):
            texFile.write("\\put("+gc[c1]+","+gr[r1]+"){\\includegraphics{" + \
                cardImgFileName+"}}\n")


def writeCodeLines(texFile, pageNum, codeList):
    cdc = ["\\CodeColOne", "\\CodeColTwo", "\\CodeColThree"]
    cdr = ["\\CodeRowOne", "\\CodeRowTwo", "\\CodeRowThree", "\\CodeRowFour"]
    codeNum = pageNum*numCardsPerPage
    texFile.write("% Unique Text - the codes\n")
    for c1 in range(3):
        for r1 in range(4):
            texFile.write("\\put("+cdc[c1]+","+cdr[r1]+"){"+codeList[codeNum]+ \
                "}\n")
            codeNum = codeNum + 1

def writeMarkLines(texFile, pageNum):
    mc = ["\\MarkColOne", "\\MarkColTwo", "\\MarkColThree", "\\MarkColFour"]
    mr = ["\\MarkRowOne", "\\MarkRowTwo", "\\MarkRowThree", "\\MarkRowFour"]
    texFile.write("% Cutting Marks\n")
    for c1 in range(4):
        texFile.write("\\put("+mc[c1]+",-1){\\line(0,1){0.9}}\n")
        texFile.write("\\put("+mc[c1]+",9){\\line(0,-1){1.05}}\n")
    for r1 in range(4):
        texFile.write("\\put(-1,"+mr[r1]+"){\\line(1,0){1.05}}\n")
        texFile.write("\\put(11.75,"+mr[r1]+"){\\line(-1,0){1.05}}\n")

def main():
    
    # Get codes from CSV File
    codeList=parseCSVFile()

    # Calculate number of pages. Only uses a multiple of 12 codes.
    # Any extra codes will be ignored.
    numPages = len(codeList)/numCardsPerPage
    numCodes = numPages*numCardsPerPage

    makeAllQRCodeImages(codeList, numCodes)

    # Make .tex file
    texFile = open('promo_cards.tex', 'w')
    texFile.write(preambleEtc)
    for pageNum in range(numPages):
        makePage(texFile, pageNum, codeList)
    texFile.write("\\end{document}\n")
    texFile.close()

    os.system(pdflatex + " promo_cards.tex")


if __name__ == '__main__':
    main()
