package op.threads;
import entity.prescription.MedStock;
import entity.prescription.MedStockTools;
import entity.system.SYSPropsTools;
import op.OPDE;
import op.system.LogicalPrinter;
import op.system.PrinterForm;
import op.tools.PrintListElement;
import op.tools.SYSTools;
import javax.print.DocFlavor;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
/**
* Während des Einbuch-Vorgang können sehr schnell viele einzelne kleine Druckaufträge
* für die Etiketten nötig werden. Damit die Erstellung dieser Jobs das Programm nicht anhält
* bedienen wir uns hier einer nebenläufigen Programierung.
*/
public class PrintProcessor extends Thread {
// TODO: change to synchronized version
private boolean interrupted;
private List<PrintListElement> printQueue;
HashMap<String, ArrayList<PrintListElement>> preparedPrintJobs;
public void addPrintJobs(List<PrintListElement> jobs) {
printQueue.addAll(jobs);
}
public void addPrintJob(PrintListElement job) {
printQueue.add(job);
}
public boolean isInterrupted() {
return interrupted;
}
public boolean isWorking() {
boolean working = !OPDE.getLogicalPrinters().getLogicalPrintersList().isEmpty();
working &= OPDE.getProps().containsKey(SYSPropsTools.KEY_PHYSICAL_PRINTER);
working &= OPDE.getLogicalPrinters().getPrintService(OPDE.getProps().getProperty(SYSPropsTools.KEY_PHYSICAL_PRINTER)) != null;
working &= OPDE.getProps().containsKey(SYSPropsTools.KEY_LOGICAL_PRINTER) && OPDE.getLogicalPrinters().getMapName2LogicalPrinter().containsKey(OPDE.getProps().getProperty(SYSPropsTools.KEY_LOGICAL_PRINTER));
working &= OPDE.getProps().containsKey(SYSPropsTools.KEY_MEDSTOCK_LABEL) && OPDE.getLogicalPrinters().getMapName2LogicalPrinter().get(OPDE.getProps().getProperty(SYSPropsTools.KEY_LOGICAL_PRINTER)).getForms().containsKey(OPDE.getLocalProps().getProperty(SYSPropsTools.KEY_MEDSTOCK_LABEL));
return working;
}
public LogicalPrinter getSelectedLogicalPrinter() {
LogicalPrinter logicalPrinter = null;
if (isWorking()) {
logicalPrinter = OPDE.getLogicalPrinters().getMapName2LogicalPrinter().get(OPDE.getProps().getProperty(SYSPropsTools.KEY_LOGICAL_PRINTER));
}
return logicalPrinter;
}
public PrinterForm getSelectedForm() {
PrinterForm printerForm = null;
LogicalPrinter logicalPrinter = getSelectedLogicalPrinter();
if (logicalPrinter != null) {
printerForm = logicalPrinter.getForms().get(OPDE.getProps().getProperty(SYSPropsTools.KEY_MEDSTOCK_LABEL));
}
return printerForm;
}
public boolean isIdle() {
return printQueue.size() == 0;
}
public PrintProcessor() {
super();
preparedPrintJobs = new HashMap<String, ArrayList<PrintListElement>>();
setName("PrintProcessor");
interrupted = false;
printQueue = new ArrayList();
}
public void run() {
while (!interrupted) {
try {
if (!printQueue.isEmpty()) {
int size = printQueue.size();
int progressbar = 1;
//
// Schritt 1 Vorbereitung
//
for (int i = 0; i < size; i++) {
PrintListElement thisElement = printQueue.get(0);
printQueue.remove(0); // Das wird danach dann direkt aus der Liste gelöscht.
// Aus Geschwindigkeitsgründen (und die sind immens) werden innerhalb eines Drucklaufes
// alle nicht Seitendrucker-Ausgaben innerhalb eines Printjobs (im Sinne des Betriebssystems)
// zusammengefasst.
//
// Da sich die Länge der PrintQueue während der Bearbeitung verändern kann muss hier mit etwas Aufwand unterschieden
// werden. Sobald sich der Druckername (Betriebssystem) bei den Jobs ändert, muss ein PrintJob (OS Notion) erzeugt werden
// Bei Pagedruckern (also meist Postscript, ist dann, wenn direkt Printable Objects erzeugt werden) wird sowieso ein PrintJob
// per PrintListElement erzeug.
// Bleiben die zusammengebastelten Strings der LabelDrucker (epl2, esc2). Die werden mit einem einheitlichen Reset versehen und
// dann werden alle aufeinanderfolgenden Etiketten als Strings drangehangen. Erst bei Ende der Queue oder eben, wenn ein anderer
// Drucker dran kommt, wird der Printjob (OS Notion) erzeugt.
// Der Aufwand lohnt. Ansonsten wird so ein Zebra Drucker UNEEEEENDLICH langsam.
//
// Um das sauber durchzuführen wird in dieser Schleife hier eine Art Vorverarbeitung durchgeführt. Also werden die
// Printjobs praktisch vorbereitet (als PrintJob Preparation). In der nächsten Schleife werden sie dann der Reihe nach dem Betriebssystem
// zur Weiterverarbeitung übergeben.
//
if (!thisElement.getPrinter().isCombinePrintjobs()) {
OPDE.getLogicalPrinters().print(getPrintableObject(thisElement), thisElement.getPrintername(), DocFlavor.SERVICE_FORMATTED.PRINTABLE);
// pb.setValue(progressbar);
OPDE.getDisplayManager().setProgressBarMessage(new DisplayMessage(SYSTools.xx("misc.msg.printing") + " " + SYSTools.xx("misc.msg.number") + " " + progressbar, progressbar, printQueue.size()));
// OPDE.debug("Drucke Nr. " + progressbar);
progressbar++;
} else {
if (!preparedPrintJobs.containsKey(thisElement.getPrintername())) {
preparedPrintJobs.put(thisElement.getPrintername(), new ArrayList<PrintListElement>());
}
preparedPrintJobs.get(thisElement.getPrintername()).add(thisElement);
}
}
//
// Schritt 2 Abschluss
//
// Die PagePrinter Jobs sind jetzt schon durch
// Zu kombinierende Jobs stehen jetzt ggf. hier drin.
if (!preparedPrintJobs.isEmpty()) {
byte[] encoded = null;
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
String printername = "";
LogicalPrinter printerType = null;
String printjob = "";
Collection<ArrayList<PrintListElement>> collection = preparedPrintJobs.values();
for (ArrayList<PrintListElement> printListElements : collection) {
printerType = printListElements.get(0).getPrinter();
printername = printListElements.get(0).getPrintername();
printjob = printerType.getReset();
for (PrintListElement printListElement : printListElements) {
Object printableObject = getPrintableObject(printListElement);
if (printableObject != null) {
printjob += getPrintableObject(printListElement);
} else {
OPDE.error("invalid printer object. can't print a NULL value. please check printers.xml for typos");
}
OPDE.getDisplayManager().setProgressBarMessage(new DisplayMessage(SYSTools.xx("misc.msg.printing") + " " + SYSTools.xx("misc.msg.number") + " " + progressbar, progressbar, printQueue.size()));
progressbar++;
}
printjob += printerType.getFooter();
OPDE.debug(printjob);
try {
encoded = printjob.getBytes(printerType.getEncoding());
OPDE.getLogicalPrinters().print(encoded, printername, flavor);
OPDE.getDisplayManager().setProgressBarMessage(new DisplayMessage(SYSTools.xx("misc.msg.printing") + " " + SYSTools.xx("misc.msg.number") + " " + progressbar, progressbar, printQueue.size()));
progressbar++;
} catch (UnsupportedEncodingException e) {
OPDE.fatal(e);
}
printListElements.clear();
}
preparedPrintJobs.clear();
}
OPDE.getDisplayManager().setProgressBarMessage(null);
}
Thread.sleep(2000); // Millisekunden
} catch (InterruptedException ie) {
interrupted = true;
OPDE.debug("PrintProcessor interrupted!");
}
}
}
private Object getPrintableObject(PrintListElement element) {
Object printableObject = null;
if (element.getObject() instanceof MedStock) {
MedStock bestand = (MedStock) element.getObject();
OPDE.debug("PrintProcessor prints StockID: " + bestand.getID());
printableObject = element.getPrinterForm().getFormtext(MedStockTools.getStock4Printing(bestand));
}
return printableObject;
}
}