#!/usr/bin/env python2
'''
Created on Mar 1, 2016

@author: Matthew Yoshio Morikawa
'''

import cStringIO
import sys
import tempfile
import time
import datetime
sys.path.append('/usr/local/python-kyofilter_pre_E')
from PyPDF2 import PdfFileWriter, PdfFileReader
import StringIO
import re
import os
import ntpath
import reportlab
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase import pdfmetrics, ttfonts 
from reportlab.lib.colors import Color
from sys import stderr, argv
from math import sqrt
from math import ceil
from math import floor

from distutils.version import LooseVersion

#Constants
###############################################################################

KYOVERSION      = 1.0

ARG_DESTINATION = 0
ARG_JOB         = 1
ARG_USER        = 2
ARG_TITLE       = 3
ARG_NUM_COPIES  = 4
ARG_OPTIONS     = 5
ARG_PRINTABLE   = 6

WM_RENDERING    = "Wren"
WM_TEXT         = "Wtxt"
WM_FONT         = "Wfnt"
WM_COLOR        = "Wclr"
WM_TYPE         = "Wtyp"
WM_ANGLE        = "Wang"
WM_SIZE         = "Wsze"
WM_TRANSPARENCY = "Wtrans"
WM_REPEAT       = "Wflg"

CONFIG_DIR = "/usr/share/kyocera/"
TMP        = "/tmp/"
USER       = ""

#Debug functions
###############################################################################

DEBUG = True

def debug_write(input_string):
    if DEBUG:
        try:
            ts = time.time()
            st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
            debug_file= open("/tmp/print_debug", 'a+')
            debug_file.write(st + ": " +input_string + "\n")
            debug_file.flush()
            debug_file.close()
        except:
            pass

#Get watermark options
###############################################################################

def get_watermark_options(all_options):
    options = dict()
    debug_write(all_options)
    
    get_checkbox_option(options, WM_RENDERING, all_options, "False")
    get_text_option(options, all_options)
    get_option(options, WM_FONT, all_options, "Helvetica-Bold")
    get_option(options, WM_COLOR, all_options, "Black")
    get_option(options, WM_TYPE, all_options, "Solid")
    get_option(options, WM_ANGLE, all_options, "50")
    get_option(options, WM_SIZE, all_options, "72")
    get_option(options, WM_TRANSPARENCY, all_options, "watermark")
    get_checkbox_option(options, WM_REPEAT, all_options, "False")
    
    return options

def get_checkbox_option(options, option, all_options, default):
    debug_write("cOption " + option)
    if " " + option + " " in all_options or all_options.startswith(option + " "):
        options[option] = "True"
    else:
        get_option(options, option, all_options, default)
    
def get_option(options, option, all_options, default):
    debug_write("Option " + option)
    try:
        result = re.search( r"%s=(.*?)( |$)" % option, all_options).group(1)
        options[option] = result
        debug_write("    Result " + result)
    except AttributeError:
        options[option] = default
        debug_write("    Default " + default)

def get_text_option(options, all_options):
    debug_write("Option " + WM_TEXT)
    try:
        result = re.search( r"%s='(.*?)'" % WM_TEXT, all_options).group(1)
        options[WM_TEXT] = result.replace("\\", "")
        debug_write("    Result1 " + result)
    except AttributeError:
        result = get_text_from_config_file()
        debug_write("    Config Text: " + result)
        if result != "":
            options[WM_TEXT] = result.replace("\\", "")
            debug_write("    Result3 " + result)
        else:
            try:
                result = re.search( r"%s=(.*?)((?<!\\) |$)" % WM_TEXT, all_options).group(1)
                debug_write("    Result1 " + result)
                options[WM_TEXT] = get_text_equivalence(result)
                debug_write("    Result2 " + options[WM_TEXT])
            except AttributeError:
                options[WM_TEXT] = "CONFIDENTIAL"
                debug_write("    Default " + "CONFIDENTIAL")

def get_text_from_config_file():
    debug_write("    Checking config file")
    ppd  = ntpath.basename(os.environ.get('PPD')).replace(".ppd",".cfg")
    debug_write("        Got USER: " + USER)
    debug_write("        Got PPD: " + ppd)
    configFile = CONFIG_DIR + USER + "/" + ppd
    debug_write("        Config file: " + configFile)
    if os.path.isfile(configFile): 
        with open(configFile, 'r') as file_in:
            for line in file_in:
                if "Wtxt" in line:
                    text = line.partition("=")[2].strip()
                    debug_write("        Wtxt: " + text)
                    if text and is_custom(text):
                        return text[1:-1]
                    else:
                        return ""
    return ""

def is_custom(option):
    if option == "Confidential":
        return False
    elif option == "Original":
        return False
    elif option == "Copy":
        return False
    elif option == "DoNotPhotoCopy":
        return False
    elif option == "Draft":
        return False
    elif option == "Final":
        return False
    elif option == "Proof":
        return False
    else:
        return True


def get_text_equivalence(option):
    debug_write("    Get text equivalence " + option)
    if option == "Confidential":
        return "CONFIDENTIAL"
    elif option == "Original":
        return "ORIGINAL"
    elif option == "Copy":
        return "COPY"
    elif option == "DoNotPhotoCopy":
        return "DO NOT PHOTOCOPY"
    elif option == "Draft":
        return "DRAFT"
    elif option == "Final":
        return "FINAL"
    elif option == "Proof":
        return "PROOF"
    elif "Custom." in option:
        debug_write("    Found custom option")
        return option.replace("Custom.", "").replace("\\", "")
    else:
        return option

    
#Get base PDF
###############################################################################

def get_base_pdf():
    
    fileout = tempfile.NamedTemporaryFile(dir="/tmp")
    kyo_in = sys.stdin
    if len(argv) == 7:
        kyo_in = open(argv[ARG_PRINTABLE])
        
    for line in kyo_in.readlines():
        fileout.write(line)

    print fileout.name
    fileout.seek(0)
    
    in_pdf = PdfFileReader(fileout)

    return in_pdf
    
#Get watermark PDF
###############################################################################

def get_watermark_pdf(watermark_arguments):
    packet = StringIO.StringIO()
    draw_watermark(packet, watermark_arguments)
    packet.seek(0)
    watermark_pdf = PdfFileReader(packet)
    return watermark_pdf

def get_base_watermark_position(page_size):
    width, height = page_size
    return (width/2, height/2)

def get_canvas(watermark_arguments, page_size, packet):
    #wm_font     = "Helvetica-Bold"
    #wm_size     = int(watermark_arguments[WM_SIZE])
    wm_angle    = int(watermark_arguments[WM_ANGLE])
    
    can = canvas.Canvas(packet, page_size)
    #can.setFont(wm_font, wm_size)
    set_font(can, watermark_arguments)
    set_can_color(can, watermark_arguments)
    set_can_style(can, watermark_arguments)
    
    x, y = get_base_watermark_position(page_size)
    can.translate(x, y)
    
    can.rotate(wm_angle)
    
    return can

def set_font(can, watermark_arguments):
    supported_fonts = ('Courier', 'Courier-Bold', 'Courier-Oblique', 
                       'Courier-BoldOblique', 'Helvetica', 'Helvetica-Bold', 
                       'Helvetica-Oblique', 'Helvetica-BoldOblique',
                       'Times-Roman', 'Times-Bold', 'Times-Italic', 
                       'Times-BoldItalic', 'Symbol','ZapfDingbats')
    
    font = watermark_arguments[WM_FONT]
    size = int(watermark_arguments[WM_SIZE])
    
    for support in supported_fonts:
        if font == support:
            can.setFont(font, size)
            return
        
    ttf = "LiberationMono-Bold.ttf"
    #debug_write(ttf + "\n")
    for root, dirs, files in os.walk("/usr/share/fonts/truetype"):
        if ttf in files:
            pdfmetrics.registerFont(ttfonts.TTFont(font, os.path.join(root, ttf)))
            can.setFont(font, size)
            return
            
    debug_write("Font not Found")
    can.setFont("Helvetica-Bold", size) 
            

def set_can_style(can, watermark_arguments):
    fill = watermark_arguments[WM_TYPE]
    
    if fill == "Hollow":
        can.setFillColor(Color(0,0,0, alpha=0.0))
        can.setLineWidth(1)
        t=can.beginText()
        t.setTextRenderMode(2)
        can._code.append(t.getCode())

def set_can_color(can, watermark_arguments):
    color = watermark_arguments[WM_COLOR]
    fill  = watermark_arguments[WM_TYPE]
    trans = 1.0
    if watermark_arguments[WM_TRANSPARENCY] == "watermark":
        trans = 0.5
    
    if color == "Red" and fill != "Hollow":
        can.setFillColor(Color(1,0,0, alpha=trans))
    elif color == "Green" and fill != "Hollow":
        can.setFillColor(Color(0,1,0, alpha=trans))
    elif color == "Blue" and fill != "Hollow":
        can.setFillColor(Color(0,0,1, alpha=trans))
    elif color == "Black" and fill != "Hollow":
        can.setFillColor(Color(0,0,0, alpha=trans))
    elif color == "Red" and fill == "Hollow":
        can.setStrokeColor(Color(1,0,0, alpha=1.0))
    elif color == "Green" and fill == "Hollow":
        can.setStrokeColor(Color(0,1,0, alpha=1.0))
    elif color == "Blue" and fill == "Hollow":
        can.setStrokeColor(Color(0,0,1, alpha=1.0))
    elif color == "Black" and fill == "Hollow":
        can.setStrokeColor(Color(0,0,0, alpha=1.0))

def get_page_size(watermark_arguments):
    return letter

def draw_watermark(packet, watermark_arguments):
    wm_repeat = (watermark_arguments[WM_REPEAT] == "True")
    
    page_size=get_page_size(watermark_arguments)
    can = get_canvas(watermark_arguments, page_size,packet)
    
    if wm_repeat:
        draw_repeat_watermark(can, watermark_arguments, page_size)
    else:
        draw_single_watermark(can, watermark_arguments)
    can.save()

def draw_single_watermark(can, watermark_arguments):
    text = watermark_arguments[WM_TEXT]
    can.drawCentredString(0, 0, text)
    
def draw_repeat_watermark(can, watermark_arguments, page_size):
    wm_text     = watermark_arguments[WM_TEXT]
    wm_font     = "Helvetica-Bold"
    wm_size     = int(watermark_arguments[WM_SIZE])
    wm_length   = can.stringWidth(wm_text, wm_font, wm_size)
    whitespace  = wm_size * 2
    
    x, y = page_size
    
    #We fill the diagonal by diagonal space, as that will
    #guarantee coverage over the page
    diagonal = sqrt(x*x + y*y) #Pythagorean diagonal
    
    vertical_space = whitespace * 1.5
    horizontal_space = (wm_length + whitespace/2)
    
    collumns = diagonal / horizontal_space
    rows = diagonal / vertical_space
    
    min_x = int(floor(-collumns/2))
    max_x = int(ceil(collumns/2))
    
    min_y = int(floor(-rows/2))
    max_y = int(ceil(rows/2))
    
    for i in range(min_x, max_x + 1, 1):
        for j in range(min_y, max_y + 1, 1):
            draw_x = i * horizontal_space
            draw_y = j * vertical_space
            can.drawCentredString(draw_x, draw_y, wm_text)

#Apply watermark to pdf
###############################################################################

def apply_watermark_to_pdf(base_pdf, watermark_pdf):
    
    new_pdf = PdfFileWriter()
    
    num_of_pages = base_pdf.getNumPages()
    watermark = watermark_pdf.getPage(0)
    for p in range(num_of_pages):
        page = base_pdf.getPage(p)
        page.mergePage(watermark)
        new_pdf.addPage(page)

    return new_pdf
    
#Output pdf
###############################################################################

def output_pdf(new_pdf):
    output = cStringIO.StringIO()
    new_pdf.write(output)
    #print("Content-type: application/pdf\n")
    sys.stdout.write(output.getvalue())
    output.close()

#Check Version
###############################################################################

def check_version():
    current_version = reportlab.Version
    minimum_version = "2.4.0"
    debug_write("Version: " + current_version)
    try:
        result = LooseVersion(minimum_version) <= LooseVersion(current_version)
        return result
    except: 
        return False

#Main and Execution
###############################################################################

def main():

    debug_write("Starting Driver")


    index = 0
    for arg in sys.argv:
        debug_write(str(index) + " " + str(arg))
        index = index + 1
    debug_write("\n")
    
    global USER
    USER = sys.argv[ARG_USER]
    debug_write("User: " + USER)
    watermark_arguments = get_watermark_options(sys.argv[ARG_OPTIONS])
    

    #DEBUG TAG
    for arg in watermark_arguments:
        debug_write(str(arg) + ": " + str(watermark_arguments[arg]))
    debug_write("\n")
    
    render = watermark_arguments[WM_RENDERING]

    kyo_in = sys.stdin
    
    has_minimum_version = check_version()
    
    if render == "True" and has_minimum_version:
        debug_write("Getting base pdf")
        base_pdf = get_base_pdf()
        debug_write("Generating watermark")
        watermark_pdf = get_watermark_pdf(watermark_arguments)
        debug_write("Applying watermark")
        new_pdf = apply_watermark_to_pdf(base_pdf, watermark_pdf)
        debug_write("Outputting pdf")
        output_pdf(new_pdf)
    
        tmpdir = "/tmp/"
        debug_write("Temp Directory: " + tmpdir);
        
        prefilter_flag = tmpdir + str(argv[ARG_JOB]) + "_" + str(argv[ARG_TITLE])
        file = open(prefilter_flag, 'w+')
        file.close()
    else:
        debug_write("Watermark Filter run but not acting")
        if len(argv) == 7:
            kyo_in = open(argv[ARG_PRINTABLE])
        for line in kyo_in.readlines():
            print(line),
    
    
    debug_write("Stopping Driver")
    return 0
    
if __name__ == "__main__":
    main()
