/**
*
* NORD POS is a fork of Openbravo POS.
*
* Copyright (C) 2009-2016 Nord Trading Ltd. <http://www.nordpos.com>
*
* This file is part of NORD POS.
*
* NORD POS 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 3 of the License, or (at your option) any later
* version.
*
* NORD POS 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
* NORD POS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nordpos.device.ticket;
import com.nordpos.device.display.DeviceDisplayBase;
import com.nordpos.device.receiptprinter.DevicePrinter;
import com.openbravo.data.loader.LocalRes;
import com.openbravo.pos.forms.DataLogicSystem;
import com.nordpos.device.fiscalprinter.DeviceFiscalPrinter;
import com.nordpos.device.labelprinter.DeviceLabelPrinter;
import com.nordpos.device.util.StringUtils;
import com.openbravo.pos.scripting.ScriptEngine;
import com.openbravo.pos.scripting.ScriptException;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.Scanner;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* @author Andrey Svininykh <svininykh@gmail.com>
* @author Gennady Kovalev <gik@bigur.ru>
* @author Artur Akchurin <akartkam@gmail.com>
* @version NORD POS 3
*/
public class TicketParser extends DefaultHandler {
private static SAXParser m_sp = null;
private static XMLReader m_sr = null;
private final DeviceTicketFactory printer;
private DataLogicSystem m_system;
private StringBuffer text;
private String bctype;
private String bcposition;
private int m_iTextAlign;
private int m_iTextLength;
private int m_iTextStyle;
private StringBuffer m_sVisorLine;
private int m_iVisorAnimation;
private String m_sVisorLine1;
private String m_sVisorLine2;
private double m_dValue1;
private double m_dValue2;
private int attribute3;
private String m_sPaymentType;
private Integer integerCharacterSize;
private String sUnderline;
private boolean bBold;
private int m_iOutputType;
private static final int OUTPUT_NONE = 0;
private static final int OUTPUT_DISPLAY = 1;
private static final int OUTPUT_TICKET = 2;
private static final int OUTPUT_FISCAL = 3;
private static final int OUTPUT_FISCALREP = 4;
private static final int OUTPUT_FISCALCASH = 5;
private static final int OUTPUT_LABEL = 6;
private DevicePrinter m_oOutputPrinter;
private DeviceFiscalPrinter m_oFiscalPrinter;
private DeviceLabelPrinter m_oLabelPrinter;
private String sLabelTextFontType;
private String sLabelTextOrientation;
private String sLabelTextX;
private String sLabelTextY;
private String sLabelTextFontHeight;
private String sLabelTextFontWidth;
private String sLabelTextFontWeight;
private String sLabelBarcodeOrientation;
private String sLabelBarcodeX;
private String sLabelBarcodeY;
private String sLabelBarcodeHeight;
private String sLabelBarcodesDimension;
private final InputStream shemaFile;
public TicketParser(InputStream shemaFile, DeviceTicketFactory printer) {
this.shemaFile = shemaFile;
this.printer = printer;
}
public void printTicket(InputStream scriptFile, ScriptEngine script) throws TicketPrinterException, ScriptException {
String sXML = new Scanner(scriptFile, "UTF-8").useDelimiter("\\A").next();
printTicket(new StringReader(script.eval(sXML).toString()));
}
public void printTicket(Reader in) throws TicketPrinterException {
try {
if (m_sp == null) {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setValidating(false);
spf.setNamespaceAware(true);
SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
spf.setSchema(schemaFactory.newSchema(new Source[]{new StreamSource(shemaFile)}));
m_sp = spf.newSAXParser();
m_sr = m_sp.getXMLReader();
}
m_sr.setContentHandler(this);
m_sr.parse(new InputSource(in));
} catch (ParserConfigurationException ePC) {
throw new TicketPrinterException(LocalRes.getIntString("exception.parserconfig"), ePC);
} catch (SAXException eSAX) {
throw new TicketPrinterException(LocalRes.getIntString("exception.xmlfile"), eSAX);
} catch (IOException eIO) {
throw new TicketPrinterException(LocalRes.getIntString("exception.iofile"), eIO);
}
}
@Override
public void startDocument() throws SAXException {
// inicalizo las variables pertinentes
text = null;
bctype = null;
bcposition = null;
m_sVisorLine = null;
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_NULL;
m_sVisorLine1 = null;
m_sVisorLine2 = null;
m_iOutputType = OUTPUT_NONE;
m_oOutputPrinter = null;
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
switch (m_iOutputType) {
case OUTPUT_NONE:
if ("opendrawer".equals(qName)) {
printer.getDevicePrinter(readString(attributes.getValue("printer"), "1")).openDrawer();
} else if ("play".equals(qName)) {
text = new StringBuffer();
} else if ("ticket".equals(qName)) {
m_iOutputType = OUTPUT_TICKET;
m_oOutputPrinter = printer.getDevicePrinter(readString(attributes.getValue("printer"), "1"));
m_oOutputPrinter.beginReceipt();
} else if ("display".equals(qName)) {
m_iOutputType = OUTPUT_DISPLAY;
String animation = readString(attributes.getValue("animation"), "none");
if ("scroll".equals(animation)) {
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_SCROLL;
} else if ("flyer".equals(animation)) {
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_FLYER;
} else if ("blink".equals(animation)) {
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_BLINK;
} else if ("curtain".equals(animation)) {
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_CURTAIN;
} else { // "none"
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_NULL;
}
m_sVisorLine1 = null;
m_sVisorLine2 = null;
m_oOutputPrinter = null;
} else if ("fiscalreceipt".equals(qName)) {
try {
m_iOutputType = OUTPUT_FISCAL;
m_oFiscalPrinter = printer.getFiscalPrinter();
m_oFiscalPrinter.beginReceipt(
readString(attributes.getValue("type"), "sale"),
parseInt(attributes.getValue("number")),
readString(attributes.getValue("date"), "01.01.2012"),
readString(attributes.getValue("time"), "00:00"),
readString(attributes.getValue("cashier"), "Администратор"));
} catch (TicketPrinterException ex) {
throw new SAXException(ex);
}
} else if ("fiscalreport".equals(qName)) {
m_iOutputType = OUTPUT_FISCALREP;
} else if ("fiscalcash".equals(qName)) {
m_iOutputType = OUTPUT_FISCALCASH;
} else if ("label".equals(qName)) {
m_iOutputType = OUTPUT_LABEL;
m_oLabelPrinter = printer.getLabelPrinter();
m_oLabelPrinter.beginLabel(
readString(attributes.getValue("charset"), ""),
readString(attributes.getValue("length"), "0"),
readString(attributes.getValue("width"), "0"),
readString(attributes.getValue("gap"), "0"),
readString(attributes.getValue("x"), "0"),
readString(attributes.getValue("y"), "0"),
readString(attributes.getValue("rotation"), "0"),
readString(attributes.getValue("resolution"), ""));
}
break;
case OUTPUT_TICKET:
switch (qName) {
case "image":
text = new StringBuffer();
break;
case "line":
m_oOutputPrinter.beginLine(parseInt(attributes.getValue("size"), 0));
break;
case "barcode":
text = new StringBuffer();
bctype = readString(attributes.getValue("type"), "EAN13");
bcposition = readString(attributes.getValue("position"), "bottom");
break;
case "text":
text = new StringBuffer();
integerCharacterSize = parseInteger(attributes.getValue("size"));
sUnderline = readString(attributes.getValue("underline"), "none");
bBold = attributes.getValue("bold").equals("true");
String sAlign = readString(attributes.getValue("align"), "left");
switch (sAlign) {
case "right":
m_iTextAlign = DevicePrinter.ALIGN_RIGHT;
break;
case "center":
m_iTextAlign = DevicePrinter.ALIGN_CENTER;
break;
default:
m_iTextAlign = DevicePrinter.ALIGN_LEFT;
break;
}
m_iTextLength = parseInt(attributes.getValue("length"), 0);
case "cutpaper":
m_oOutputPrinter.cutPaper(readBoolean(attributes.getValue("complete"), true));
}
break;
case OUTPUT_DISPLAY:
if ("line".equals(qName)) { // line 1 or 2 of the display
m_sVisorLine = new StringBuffer();
} else if ("line1".equals(qName)) { // linea 1 del visor
m_sVisorLine = new StringBuffer();
} else if ("line2".equals(qName)) { // linea 2 del visor
m_sVisorLine = new StringBuffer();
} else if ("text".equals(qName)) {
text = new StringBuffer();
String sAlign = readString(attributes.getValue("align"), "center");
if ("right".equals(sAlign)) {
m_iTextAlign = DevicePrinter.ALIGN_RIGHT;
} else if ("center".equals(sAlign)) {
m_iTextAlign = DevicePrinter.ALIGN_CENTER;
} else {
m_iTextAlign = DevicePrinter.ALIGN_LEFT;
}
m_iTextLength = parseInt(attributes.getValue("length"), 0);
}
break;
case OUTPUT_FISCAL:
if ("line".equals(qName)) {
text = new StringBuffer();
m_dValue1 = parseDouble(attributes.getValue("price"), 0.0);
m_dValue2 = parseDouble(attributes.getValue("units"), 1.0);
attribute3 = parseInt(attributes.getValue("tax"), 0);
} else if ("message".equals(qName)) {
text = new StringBuffer();
} else if ("total".equals(qName)) {
text = new StringBuffer();
m_dValue1 = parseDouble(attributes.getValue("paid"), 0.0);
m_sPaymentType = readString(attributes.getValue("type"), "cash");
} else if ("cutpaper".equals(qName)) {
try {
m_oFiscalPrinter.cutPaper(readBoolean(attributes.getValue("complete"), true));
} catch (TicketPrinterException ex) {
throw new SAXException(ex);
}
}
break;
case OUTPUT_FISCALREP:
try {
m_oFiscalPrinter = printer.getFiscalPrinter();
if ("fiscalzreport".equals(qName)) {
m_oFiscalPrinter.printZReport();
} else if ("fiscalxreport".equals(qName)) {
m_oFiscalPrinter.printXReport();
} else if ("cutpaper".equals(qName)) {
m_oFiscalPrinter.cutPaper(readBoolean(attributes.getValue("complete"), true));
}
} catch (TicketPrinterException ex) {
throw new SAXException(ex);
}
case OUTPUT_FISCALCASH:
try {
m_oFiscalPrinter = printer.getFiscalPrinter();
if ("fiscalcashin".equals(qName)) {
m_oFiscalPrinter.printCashIn(parseDouble(attributes.getValue("value"), 0.0));
} else if ("fiscalcashout".equals(qName)) {
m_oFiscalPrinter.printCashOut(parseDouble(attributes.getValue("value"), 0.0));
} else if ("cutpaper".equals(qName)) {
m_oFiscalPrinter.cutPaper(readBoolean(attributes.getValue("complete"), true));
}
} catch (TicketPrinterException ex) {
throw new SAXException(ex);
}
case OUTPUT_LABEL:
if ("text".equals(qName)) {
text = new StringBuffer();
sLabelTextFontType = readString(attributes.getValue("font"), "");
sLabelTextOrientation = readString(attributes.getValue("orientation"), "0");
sLabelTextX = readString(attributes.getValue("x"), "0");
sLabelTextY = readString(attributes.getValue("y"), "0");
sLabelTextFontHeight = readString(attributes.getValue("font-height"), "1");
sLabelTextFontWidth = readString(attributes.getValue("font-width"), "1");
sLabelTextFontWeight = readString(attributes.getValue("font-weight"), "");
} else if ("barcode".equals(qName)) {
text = new StringBuffer();
sLabelBarcodeOrientation = readString(attributes.getValue("orientation"), "0");
sLabelBarcodeX = readString(attributes.getValue("x"), "0");
sLabelBarcodeY = readString(attributes.getValue("y"), "0");
sLabelBarcodeHeight = readString(attributes.getValue("height"), "1");
bctype = readString(attributes.getValue("type"), "EAN13");
bcposition = readString(attributes.getValue("position"), "bottom");
sLabelBarcodesDimension = readString(attributes.getValue("dimension"));
} else if ("rectangle".equals(qName)) {
m_oLabelPrinter.drawRectangle(
readString(attributes.getValue("fill"), ""),
readString(attributes.getValue("x-begin"), "0"),
readString(attributes.getValue("y-begin"), "0"),
readString(attributes.getValue("x-end"), "0"),
readString(attributes.getValue("y-end"), "0"));
} else if ("line".equals(qName)) {
m_oLabelPrinter.drawLine(
readString(attributes.getValue("thickness"), "1"),
readString(attributes.getValue("x-begin"), "0"),
readString(attributes.getValue("y-begin"), "0"),
readString(attributes.getValue("x-end"), "0"),
readString(attributes.getValue("y-end"), "0"));
} else if ("frame".equals(qName)) {
m_oLabelPrinter.drawFrame(
readString(attributes.getValue("thickness"), "1"),
readString(attributes.getValue("x-begin"), "0"),
readString(attributes.getValue("y-begin"), "0"),
readString(attributes.getValue("x-end"), "0"),
readString(attributes.getValue("y-end"), "0"));
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
switch (m_iOutputType) {
case OUTPUT_NONE:
if ("play".equals(qName)) {
try {
AudioClip oAudio = Applet.newAudioClip(getClass().getClassLoader().getResource(text.toString()));
oAudio.play();
} catch (Exception fnfe) {
//throw new ResourceNotFoundException( fnfe.getMessage() );
}
text = null;
}
break;
case OUTPUT_TICKET:
switch (qName) {
case "image":
try {
// BufferedImage image = ImageIO.read(getClass().getClassLoader().getResourceAsStream(m_sText.toString()));
BufferedImage image = m_system.getResourceAsImage(text.toString());
if (image != null) {
m_oOutputPrinter.printImage(image);
}
} catch (Exception fnfe) {
//throw new ResourceNotFoundException( fnfe.getMessage() );
}
text = null;
break;
case "barcode":
m_oOutputPrinter.printBarCode(
bctype,
bcposition,
readString(text.toString(), "0"));
text = null;
break;
case "text":
if (m_iTextLength > 0) {
switch (m_iTextAlign) {
case DevicePrinter.ALIGN_RIGHT:
m_oOutputPrinter.printText(integerCharacterSize, sUnderline, bBold, StringUtils.alignRight(text.toString(), m_iTextLength));
break;
case DevicePrinter.ALIGN_CENTER:
m_oOutputPrinter.printText(integerCharacterSize, sUnderline, bBold, StringUtils.alignCenter(text.toString(), m_iTextLength));
break;
default:
m_oOutputPrinter.printText(integerCharacterSize, sUnderline, bBold, StringUtils.alignLeft(text.toString(), m_iTextLength));
break;
}
} else {
m_oOutputPrinter.printText(integerCharacterSize, sUnderline, bBold, text.toString());
}
text = null;
break;
case "line":
m_oOutputPrinter.endLine();
break;
case "ticket":
m_oOutputPrinter.endReceipt();
m_iOutputType = OUTPUT_NONE;
m_oOutputPrinter = null;
break;
}
break;
case OUTPUT_DISPLAY:
if ("line".equals(qName)) { // line 1 or 2 of the display
if (m_sVisorLine1 == null) {
m_sVisorLine1 = m_sVisorLine.toString();
} else {
m_sVisorLine2 = m_sVisorLine.toString();
}
m_sVisorLine = null;
} else if ("line1".equals(qName)) { // linea 1 del visor
m_sVisorLine1 = m_sVisorLine.toString();
m_sVisorLine = null;
} else if ("line2".equals(qName)) { // linea 2 del visor
m_sVisorLine2 = m_sVisorLine.toString();
m_sVisorLine = null;
} else if ("text".equals(qName)) {
if (m_iTextLength > 0) {
switch (m_iTextAlign) {
case DevicePrinter.ALIGN_RIGHT:
m_sVisorLine.append(StringUtils.alignRight(text.toString(), m_iTextLength));
break;
case DevicePrinter.ALIGN_CENTER:
m_sVisorLine.append(StringUtils.alignCenter(text.toString(), m_iTextLength));
break;
default: // DevicePrinter.ALIGN_LEFT
m_sVisorLine.append(StringUtils.alignLeft(text.toString(), m_iTextLength));
break;
}
} else {
m_sVisorLine.append(text);
}
text = null;
} else if ("display".equals(qName)) {
printer.getDeviceDisplay().writeVisor(m_iVisorAnimation, m_sVisorLine1, m_sVisorLine2);
m_iVisorAnimation = DeviceDisplayBase.ANIMATION_NULL;
m_sVisorLine1 = null;
m_sVisorLine2 = null;
m_iOutputType = OUTPUT_NONE;
m_oOutputPrinter = null;
}
break;
case OUTPUT_FISCAL:
try {
if ("fiscalreceipt".equals(qName)) {
m_oFiscalPrinter.endReceipt();
m_iOutputType = OUTPUT_NONE;
} else if ("line".equals(qName)) {
m_oFiscalPrinter.printLine(text.toString(), m_dValue1, m_dValue2, attribute3);
text = null;
} else if ("message".equals(qName)) {
m_oFiscalPrinter.printMessage(text.toString());
text = null;
} else if ("total".equals(qName)) {
m_oFiscalPrinter.printTotal(text.toString(), m_dValue1, m_sPaymentType);
text = null;
}
} catch (TicketPrinterException ex) {
throw new SAXException(ex);
}
break;
case OUTPUT_FISCALREP:
if ("fiscalreport".equals(qName)) {
m_iOutputType = OUTPUT_NONE;
}
break;
case OUTPUT_FISCALCASH:
if ("fiscalcash".equals(qName)) {
m_iOutputType = OUTPUT_NONE;
}
break;
case OUTPUT_LABEL:
if ("label".equals(qName)) {
m_oLabelPrinter.endLabel();
m_iOutputType = OUTPUT_NONE;
} else if ("text".equals(qName)) {
m_oLabelPrinter.drawText(
sLabelTextFontType,
sLabelTextOrientation,
sLabelTextX,
sLabelTextY,
sLabelTextFontWidth,
sLabelTextFontHeight,
sLabelTextFontWeight,
readString(text.toString(), "???"));
text = null;
} else if ("barcode".equals(qName)) {
m_oLabelPrinter.drawBarCode(
bctype,
bcposition,
sLabelBarcodeOrientation,
sLabelBarcodeX,
sLabelBarcodeY,
sLabelBarcodeHeight,
sLabelBarcodesDimension,
readString(text.toString(), "???"));
text = null;
}
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (text != null) {
text.append(ch, start, length);
}
}
private int parseInt(String sValue, int iDefault) {
try {
return Integer.parseInt(sValue);
} catch (NumberFormatException eNF) {
return iDefault;
}
}
private int parseInt(String sValue) {
return parseInt(sValue, 0);
}
private Integer parseInteger(String sValue) {
try {
return Integer.parseInt(sValue);
} catch (NumberFormatException eNF) {
return 12;
}
}
private double parseDouble(String sValue, double ddefault) {
try {
return Double.parseDouble(sValue);
} catch (NumberFormatException eNF) {
return ddefault;
}
}
private double parseDouble(String sValue) {
return parseDouble(sValue, 0.0);
}
private String readString(String sValue) {
if (sValue == null || sValue.equals("")) {
return null;
} else {
return sValue;
}
}
private String readString(String sValue, String sDefault) {
if (sValue == null || sValue.equals("")) {
return sDefault;
} else {
return sValue;
}
}
private boolean readBoolean(String sValue, boolean bDefault) {
if (sValue == null || sValue.equals("")) {
return bDefault;
} else {
return Boolean.parseBoolean(sValue);
}
}
}