#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# (c) Copyright 2003-2015 HP Development Company, L.P.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# Author: Gaurav Sood, Sanjay Kumar
#

__version__ = '1.1'
__title__ =  'PostScript Finishing Filter (hpps)'
__doc__ = "CUPS filter that implements job storage (secure printing), Job Accounting and Born On Date (BOD) features on specific capable printers."

# StdLib
import sys
import getopt
import os.path
import os
import syslog
import time
import tempfile
import subprocess
import time
PY3 = sys.version_info[0] == 3
if PY3:
    import configparser
else:
    import ConfigParser as configparser

CUPS_FILTER_OK = 0
CUPS_FILTER_FAILED = 1 

input_fd = 0
output_fd = 1

job_id = 0
pid = os.getpid()
config_file = '/etc/hp/hplip.conf'
home_dir = ''


def bug(m):
    log.stderr("ERROR: %s" % m)

def msg(m):
    log.stderr("INFO: %s" % m)

if os.path.exists(config_file):
    config = configparser.ConfigParser()
    config.read(config_file)

    try:
        home_dir = config.get('dirs', 'home')
    except:
        bug("Error setting home directory: home= under [dirs] not found.")
        sys.exit(CUPS_FILTER_FAILED)
else:
    bug("Error setting home directory: /etc/hp/hplip.conf not found")
    sys.exit(CUPS_FILTER_FAILED)

if not home_dir or not os.path.exists(home_dir):
    bug("Error setting home directory: Home directory %s not found." % home_dir)
    sys.exit(CUPS_FILTER_FAILED)

sys.path.insert(0, home_dir)
os.chdir(home_dir)


# HPLIP
try:
    from base.g import *
    from base.codes import *
    from base import device
    from base import utils
    from prnt import cups
    from base.sixext import to_bytes_utf8, to_string_utf8
except ImportError as e:
    bug("Error importing HPLIP modules:%s %s\n" % (pid, e))
    sys.exit(CUPS_FILTER_FAILED)


def usage(typ='text'):
    if typ == 'text':
        utils.log_title(__title__, __version__)

    utils.format_text(USAGE, typ, title=__title__, crumb='pscfilter')
    sys.exit(CUPS_FILTER_OK)

try:
    opts, args = getopt.getopt(sys.argv[1:], 'l:hg', ['level=', 'help', 'help-rest', 'help-man'])
 
except getopt.GetoptError:
    usage()

for o, a in opts:

    if o in ('-l', '--logging'):
        log_level = a.lower().strip()
        log.set_level(log_level)

    elif o == '-g':
        log.set_level('debug')

    elif o in ('-h', '--help'):
        usage()

    elif o == '--help-rest':
        usage('rest')

    elif o == '--help-man':
        usage('man')


# CUPS provided environment
try:
    ppd_file = os.environ['PPD']
except KeyError:
    bug("Improper environment: Must be run by CUPS.")
    sys.exit(CUPS_FILTER_FAILED)

try:
    job_id, username, title, copies, options = args[0:5]
    job_id = int(job_id)
except IndexError:
    bug("Invalid command line: invalid arguments.")
    sys.exit(CUPS_FILTER_FAILED)

START_JOB = b"\x1b%-12345X@PJL JOBNAME="
UEL = b"@PJL ENTER LANGUAGE=POSTSCRIPT\x0a"
END_JOB = b"\x1b%-12345X@PJL EOJ\x0a\x1b%-12345X"

try:
    ppd_str = to_string_utf8(open(ppd_file, 'rb').read())
except IOError:
    bug("Unabel to read PPD File")
    sys.exit(CUPS_FILTER_FAILED)

opts = {}

for opt in options.split():
    try:
        o, v = opt.split('=')
    except ValueError:
        continue
    else:
        opts[o] = v

key_list = [x for x in ['HPAccountingInfo', 'HPBOD', 'HPPJLEconoMode', 'HPPJLEconoMode2',  'HPPJLOutputMode', 'HPPJLDryTime', 
                        'HPPJLSaturation', 'HPPJLInkBleed', 'HPPJLColorAsGray', 'HPPJLTrueBlack','HPPJLPrintQuality'] if x in ppd_str]

#output_fd = os.open("/tmp/PSC.out", os.O_WRONLY | os.O_CREAT)

def header():
    os.write(output_fd, START_JOB)
    os.write(output_fd, to_bytes_utf8("hplip_%s_%s\x0a" % (username, job_id)))
    os.write(output_fd, to_bytes_utf8('@PJL SET USERNAME="%s"\x0a' % username))
    os.write(output_fd, to_bytes_utf8('@PJL SET JOBNAME="%s"\x0a' % title))

# --------------------Secure Printing---------------------
# Embeds private job PJL's into the print stream
# ----------------------------------------------------------    

def secure_print():
    os.write(output_fd, b"@PJL SET HOLD=ON\x0a")
    os.write(output_fd, b"@PJL SET HOLDTYPE=PRIVATE\x0a")
    secpin = ""
    if "HPDigit" in ppd_str:
        try:
            tmp = opts['HPDigit']
            if "Custom." in tmp:
                tmp = tmp[7:]
            if tmp.isdigit() and len(tmp) == 4:
                secpin += tmp
            else: 
                secpin = "0000"
        except KeyError as e:
            msg("Setting Pin to default")
    else:
        szKeyInitials = ['HPFIDigit', 'HPSEDigit', 'HPTHDigit', 'HPFTDigit']                                 
        for x in szKeyInitials:
            try:
                secpin += opts[x]
            except KeyError:
                secpin += '0'
    os.write(output_fd, to_bytes_utf8('@PJL SET HOLDKEY="%s"\x0a' % secpin))

        
#os.write(output_fd, to_bytes_utf8('@PJL SET COPIES="%s"\x0a' % copies))
    
#----------------Job Accouting----------------------------
# Embeds the job accouting (1-8) PJL's into print stream
# -----------------------------------------------------

class HPPS_Filter(object):
    def HPAccountingInfo(self):
        p = subprocess.Popen(['hostname', '-s'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        system_name , err = p.communicate()
        if system_name == '':
            system_name = 'unknown_system_name'
        p = subprocess.Popen(['hostname', '-d'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        domain_name, err = p.communicate() 
        if domain_name == '':
            domain_name = 'unknown_domain_name'

            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct1=%s\"\x0a' % username))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct2=%s\"\x0a' % system_name.rstrip(b'\n')))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct3=%s\"\x0a' % domain_name.rstrip(b'\n')))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct4=%s\"\x0a' % time.strftime("%Y%m%d%I%M%S", time.localtime())))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct5=%s\"\x0a' % opts['job-uuid']))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct6=%s\"\x0a' % "HP Linux Printing"))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct7=%s\"\x0a' % "HP Linux Printing"))
            os.write(output_fd, to_bytes_utf8('@PJL SET JOBATTR=\"JobAcct8=%s\"\x0a' % username))

# -------------------------Born On Date ----------------------------
# Embeds the born on date PJL's in to print stream. Uses GMT Time Stamp
# Based upon the "BornOnDate_PJL_DMINFO_PJL_TIMESTAMP.doc
# -----------------------------------------------------------------
    def HPBOD(self):
        BOD_fixed = "0400040101020D10100115"  # HEX value of the time stamp OID
        BOD_time = time.strftime("%Y%m%d%I%M%S", time.gmtime()) # Timestamp GMT
        BOD_Var = ''  
        for x in BOD_time:
            BOD_Var = BOD_Var + hex(ord(x))[2:]
        os.write(output_fd, to_bytes_utf8('@PJL DMINFO ASCIIHEX=\"%s%s\"\x0A' % (BOD_fixed, BOD_Var)))

# -------------------------Other Features ----------------------------
    def HPPJLEconoMode(self):
        if 'HPPJLEconoMode' in options and 'noHPPJLEconoMode' not in options:
            os.write(output_fd, b"@PJL SET ECONOMODE=ON\x0a")
        else:
            os.write(output_fd, b"@PJL SET ECONOMODE=OFF\x0a")

        os.write(output_fd, b"@PJL SET RESOLUTION=600\x0a")
        os.write(output_fd, b"@PJL SET BITSPERPIXEL=2\x0a")


    def HPPJLEconoMode2(self):
        pq = opts.get('HPPJLEconoMode2', "")   
        if pq == 'yes' or pq == 'on':
            os.write(output_fd, b"@PJL SET ECONOMODE=ON\x0a")   
        elif pq == 'no' or pq == 'off':
            os.write(output_fd, b"@PJL SET ECONOMODE=OFF\x0a")
        else:
            pass
        os.write(output_fd, b"@PJL SET RESOLUTION=600\x0a")
        os.write(output_fd, b"@PJL SET BITSPERPIXEL=1\x0a")

    def HPPJLPrintQuality(self):
        pq = opts.get('HPPJLPrintQuality',"")         
        if pq == 'FastRes1200':
            os.write(output_fd, b"@PJL SET RESOLUTION=600\x0a@PJL SET BITSPERPIXEL=2\x0a")
        elif pq == '600dpi':
            os.write(output_fd, b"@PJL SET RESOLUTION=600\x0a@PJL SET BITSPERPIXEL=1\x0a")
        elif pq == 'ProRes1200':
            os.write(output_fd, b"@PJL SET RESOLUTION=1200\x0a@PJL SET BITSPERPIXEL=1\x0a")  
        else:
            os.write(output_fd, b"@PJL SET RESOLUTION=600\x0a@PJL SET BITSPERPIXEL=2\x0a")
	
		
    def HPPJLOutputMode(self):     
        pq = opts.get('HPPJLOutputMode', "")  
        if pq == 'GeneralOffice':
            os.write(output_fd, b'@PJL SET PRINTQUALITY=DRAFT\x0a') 
        elif pq == 'Professional':
            os.write(output_fd, b'@PJL SET PRINTQUALITY=NORMAL\x0a') 
        elif pq == 'Presentation':
            os.write(output_fd, b'@PJL SET PRINTQUALITY=BEST\x0a') 
        elif pq == 'MaximumDPI':
            os.write(output_fd, b'@PJL SET PRINTQUALITY=MAX\x0a') 
        else:
            os.write(output_fd, b'@PJL SET PRINTQUALITY=NORMAL\x0a')
        
    def HPPJLDryTime(self):
        pq = opts.get('HPPJLDryTime', "")
        if pq == '0' or pq == 'Default':
            os.write(output_fd, b'@PJL SET DRYTIME=0\x0a') 
        elif pq == 'Medium':
            os.write(output_fd, b'@PJL SET DRYTIME=4\x0a') 
        elif pq == 'Long':
            os.write(output_fd, b'@PJL SET DRYTIME=7\x0a') 
        else:
            os.write(output_fd, b'@PJL SET DRYTIME=0\x0a')
        
    def HPPJLSaturation(self):
        pq = opts.get('HPPJLSaturation', "")
        if pq == '-2':
            os.write(output_fd, b'@PJL SET SATURATION=0\x0a') 
        elif pq == '-1':
            os.write(output_fd, b'@PJL SET SATURATION=2\x0a') 
        elif pq == '0' or pq == 'default':
            os.write(output_fd, b'@PJL SET SATURATION=4\x0a') 
        elif pq == '+1':
            os.write(output_fd, b'@PJL SET SATURATION=6\x0a') 
        elif pq == '+2':
            os.write(output_fd, b'@PJL SET SATURATION=8\x0a')
        else:
            os.write(output_fd, b'@PJL SET SATURATION=4\x0a')
        
    def HPPJLInkBleed(self):
        pq = opts.get('HPPJLInkBleed', "")
        if pq == '-2' or pq == 'Default':
            os.write(output_fd, b'@PJL SET INKBLEED=0\x0a') 
        elif pq == '-1':
            os.write(output_fd, b'@PJL SET INKBLEED=2\x0a') 
        elif pq == '0' or pq == 'Less':
            os.write(output_fd, b'@PJL SET INKBLEED=4\x0a') 
        elif pq == '+1':
            os.write(output_fd, b'@PJL SET INKBLEED=6\x0a') 
        elif pq == 'Least':
            os.write(output_fd, b'@PJL SET INKBLEED=7\x0a') 
        elif pq == '+2':
            os.write(output_fd, b'@PJL SET INKBLEED=8\x0a') 
        else:
            os.write(output_fd, b'@PJL SET INKBLEED=4\x0a')
        
    def HPPJLColorAsGray(self):
        pq = opts.get('HPPJLColorAsGray', "")
        if pq == 'off' or pq == 'False':
            os.write(output_fd, b'@PJL SET GRAYSCALE=OFF\x0a') 
        elif pq == 'HighQuality':
            os.write(output_fd, b'@PJL SET GRAYSCALE=COMPOSITE\x0a') 
            os.write(output_fd, b'@PJL SET PLANESINUSE=1\x0a')
        elif pq == 'BlackInkOnly':
            os.write(output_fd, b'@PJL SET GRAYSCALE=BLACKONLY\x0a')
            os.write(output_fd, b'@PJL SET PLANESINUSE=1\x0a')
        elif pq == 'yes' or pq == 'on' :
            os.write(output_fd, b'@PJL SET RESOLUTION=600\x0a')
            os.write(output_fd, b'@PJL SET BITSPERPIXEL=8\x0a')
            os.write(output_fd, b'@PJL SET GRAYSCALE=COMPOSITE\x0a')
        elif pq == 'no':
            os.write(output_fd, b'@PJL SET RESOLUTION=600\x0a')
            os.write(output_fd, b'@PJL SET BITSPERPIXEL=8\x0a')
        elif pq == 'Plain' or pq == 'True': # for device 586 and device 586 flow
            os.write(output_fd, b'@PJL SET PLANESINUSE=1\x0a')
#       elif pq == 'check': # for device 556 no value is passed
#          os.write(output_fd, b'')
        else:
            os.write(output_fd, b'@PJL SET GRAYSCALE=OFF\x0a')
        
    def HPPJLTrueBlack(self):
        pq = opts.get('HPPJLTrueBlack', "")
        if pq == 'HighQuality':
            os.write(output_fd, b'@PJL SET GRAYSCALE=COMPOSITE\x0a') 
        elif pq == 'BlackInkOnly':
            os.write(output_fd, b'@PJL SET GRAYSCALE=BLACKONLY\x0a') 
        else:
            os.write(output_fd, b'@PJL SET GRAYSCALE=BLACKONLY\x0a')
        
try:
    header()
    if 'HPPinPrnt' in options and 'noHPPinPrnt' not in options:
        secure_print()
    hpps_filter = HPPS_Filter()
    for x in key_list:
        (getattr(hpps_filter, x))()		
    
    os.write(output_fd, UEL)
    while True:
        data = os.read(0, 4096)
        if not data:
            break
        os.write(output_fd, data)
    os.write(output_fd, END_JOB)
    
except:
    bug('HPPS filter failure')
    sys.exit(CUPS_FILTER_FAILED)
sys.exit(CUPS_FILTER_OK)




