#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
XXX

Author: Radek HuĊĦek
"""

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import subprocess as sp
import ast

def exec_pipeline(pipeline, inp, out = None, err_callback = None):
  def make_proc(cmd):
    p = QProcess()
    p.setProgram(cmd[0])
    p.setArguments(cmd[1:])
    return p

  def readChunk(cb, proc, channel):
    def x():
      proc.setReadChannel(channel)
      cb(str(proc.readAll(), encoding='utf-8'))
    return x

  procs = [ make_proc(cmd) for cmd in pipeline ]
  for a, b in zip(procs, procs[1:]):
    a.setStandardOutputProcess(b)
  
  procs[0].setStandardInputFile(inp)
  if out is None:
    if err_callback is not None:
      procs[-1].readyReadStandardOutput.connect(
        readChunk(err_callback, procs[-1], QProcess.StandardOutput))
  else:
    procs[-1].setStandardOutputFile(out)

  if err_callback is not None:
    for p in procs:
      p.readyReadStandardError.connect(
        readChunk(err_callback, p, QProcess.StandardError))
    err_callback("< '%s' \\\n" % inp)
    err_callback(" |\n".join(("'%s'" % "' '".join(cmd)) for cmd in pipeline))
    err_callback("\n")

  for p in procs:
    p.start(QProcess.Unbuffered | QProcess.ReadWrite)

  for p in procs:
    while not p.waitForFinished(30):
      QApplication.instance().processEvents()


SAVE_AS_FILE = object()

PRINTERS = ast.literal_eval("[\n%s\n]" % "".join(sys.stdin))
PRINTERS.append(("Save as ...", SAVE_AS_FILE))

for l in sp.check_output(["lpstat", "-a"]).decode("UTF-8").split("\n"):
  p = l.split(" ")[0]
  if p == "":
    continue
  PRINTERS.append((p, ["lp", "-d", p]))

class CPP(QWidget):
  def __init__(self, pdf, user):
    super().__init__()
    self._pdf = pdf

    vbox = QVBoxLayout()
    vbox.addStretch(1)

    o = QLabel("Printing %s" % (pdf,), self)
    o.setMinimumWidth(400)
    o.setMaximumWidth(800)
    o.setWordWrap(True)
    vbox.addWidget(o)

    hbox = QHBoxLayout()
    hbox.addWidget(QLabel("Duplex:"))
    self._duplex = QComboBox(self)
    self._duplex.addItem("None", 'duplex=one-sided')
    self._duplex.addItem("Long Edge", "duplex=two-sided-long-edge")
    self._duplex.addItem("Short Side", "duplex=two-sided-long-edge")
    self._duplex.setCurrentIndex(1)
    self._pdfbook = QCheckBox('Use pdfbook', self)
    self._staple = QCheckBox('Staple', self)
    self._staple.setEnabled(False)

    def _pdfbook_changed(enabled):
      self._staple.setEnabled(enabled)
      self._duplex.setEnabled(not enabled)
      if enabled:
        self._duplex.setCurrentIndex(1)
      else:
        self._staple.setChecked(False)

    self._pdfbook.clicked[bool].connect(_pdfbook_changed)
    hbox.addWidget(self._duplex)
    vbox.addLayout(hbox)
    vbox.addWidget(self._pdfbook)
    vbox.addWidget(self._staple)

    o = QComboBox(self)
    for (p, cmd) in PRINTERS:
      o.addItem(p, cmd)
    vbox.addWidget(o)
    self._printer = o

    hbox = QHBoxLayout()
    b_p = QPushButton("Print", self)
    b_p.clicked.connect(self.print)
    hbox.addWidget(b_p)
    self._button_print = b_p
    b_c = QPushButton("Cancel", self)
    b_c.clicked.connect(self.close)
    hbox.addWidget(b_c)
    self._button_cancel = b_c
    vbox.addLayout(hbox)

    self._logger = QTextEdit()
    self._logger.setReadOnly(True)
    vbox.addWidget(self._logger)

    self.setLayout(vbox)
    self.setWindowTitle('CUPS pdf printer postprocessor')
    self.show()


  def print(self):
    lp = QProcess()
    self._button_print.setEnabled(False)
    log = []
    pipeline = []

    def logMsg(msg):
      log.append(msg)
      self._logger.setPlainText("".join(log))

    if self._pdfbook.isChecked():
      pipeline.append([ "pdfbook", "/dev/stdin", "-o", "/dev/stdout" ])

    if self._printer.currentData() is SAVE_AS_FILE:
      f = QFileDialog.getSaveFileName(self, 'Save as ...')
      if not f[0]:
        self.close()
      pipeline.append([ "dd", "of=%s" % (f[0],) ])
    else:
      cmd = self._printer.currentData().copy()
      cmd += [ "-o", self._duplex.currentData() ]
      if self._staple.isChecked():
        cmd += [ "-o", "XRFold=BiFoldStaple" ]
      cmd.append("-")
      pipeline.append(cmd)

    exec_pipeline(pipeline, self._pdf, err_callback=logMsg)
    self._button_cancel.setText("Close")


if __name__ == '__main__':
  app = QApplication(sys.argv[2:])
  ex = CPP(sys.argv[1], sys.argv[2])
  sys.exit(app.exec_())