/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.shtrih.fiscalprinter.model;

/**
 *
 * @author V.Kravtsov
 */
import jpos.*;
import java.io.*;
import java.util.*;
import javax.xml.parsers.*;
// DOM
import org.w3c.dom.*;
import org.xml.sax.*;
// apache
import org.apache.log4j.*;
import org.xml.sax.*;
import org.apache.xml.serialize.*;
import org.apache.xerces.dom.*;
import org.apache.xerces.parsers.*;
// this
import com.shtrih.util.*;
import com.shtrih.fiscalprinter.command.*;

public class XmlModelsReader {

    private final PrinterModels models;
    private static Logger logger = Logger.getLogger(XmlModelsReader.class);

    public XmlModelsReader(PrinterModels models) {
        this.models = models;
    }

    public Node getChildNode(Node node, String nodeName)
            throws Exception {
        Node result = null;
        NodeList list = node.getChildNodes();
        for (int i = 0; i < list.getLength(); i++) {
            result = list.item(i);
            if (result.getNodeName().equalsIgnoreCase(nodeName)) {
                return result;
            }
        }
        throw new Exception("Child node not found");
    }

    public void load(String fileName)
            throws Exception {
        models.clear();
        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
        f.setValidating(false);
        DocumentBuilder builder = f.newDocumentBuilder();
        Document doc = builder.parse(new File(fileName));

        Element root = doc.getDocumentElement();
        Node modelsNode = getChildNode(root, "models");
        NodeList list = modelsNode.getChildNodes();
        for (int i = 0; i < list.getLength(); i++) {
            Node modelNode = list.item(i);
            if (modelNode.getNodeName().equalsIgnoreCase("model")) {
                loadModel(modelNode);
            }
        }
    }

    private String readParameterStr(Node node, String paramName)
            throws Exception {
        Element element = (Element) node;
        Node paramNode = element.getElementsByTagName(paramName).item(0);
        return paramNode.getFirstChild().getNodeValue();
    }

    private int readParameterInt(Node node, String paramName)
            throws Exception {
        String s = readParameterStr(node, paramName);
        return Integer.valueOf(s).intValue();
    }

    private int[] readParameterIntArray(Node node, String paramName)
            throws Exception {
        String s = readParameterStr(node, paramName);
        return StringUtils.strToIntArray(s);
    }

    private boolean readParameterBool(Node node, String paramName)
            throws Exception {
        return !readParameterStr(node, paramName).equalsIgnoreCase("0");
    }

    private void loadModel(Node node)
            throws Exception {
        try {
            PrinterModel model = new PrinterModelImpl();
            model.setName(readParameterStr(node, "Name"));
            model.setId(readParameterInt(node, "Id"));
            model.setModelID(readParameterInt(node, "ModelID"));
            model.setProtocolVersion(readParameterInt(node, "ProtocolVersion"));
            model.setProtocolSubVersion(readParameterInt(node, "ProtocolSubVersion"));
            model.setCapEJPresent(readParameterBool(node, "CapEJPresent"));
            model.setCapFMPresent(readParameterBool(node, "CapFMPresent"));
            model.setCapRecPresent(readParameterBool(node, "CapRecPresent"));
            model.setCapJrnPresent(readParameterBool(node, "CapJrnPresent"));
            model.setCapSlpPresent(readParameterBool(node, "CapSlpPresent"));
            model.setCapSlpEmptySensor(readParameterBool(node, "CapSlpEmptySensor"));
            model.setCapSlpNearEndSensor(readParameterBool(node, "CapSlpNearEndSensor"));
            model.setCapRecEmptySensor(readParameterBool(node, "CapRecEmptySensor"));
            model.setCapRecEmptySensor(readParameterBool(node, "CapRecEmptySensor"));
            model.setCapRecNearEndSensor(readParameterBool(node, "CapRecNearEndSensor"));
            model.setCapRecLeverSensor(readParameterBool(node, "CapRecLeverSensor"));
            model.setCapJrnEmptySensor(readParameterBool(node, "CapJrnEmptySensor"));
            model.setCapJrnNearEndSensor(readParameterBool(node, "CapJrnNearEndSensor"));
            model.setCapJrnLeverSensor(readParameterBool(node, "CapJrnLeverSensor"));
            model.setCapPrintGraphicsLine(readParameterBool(node, "CapPrintGraphicsLine"));
            model.setCapHasVatTable(readParameterBool(node, "CapHasVatTable"));
            model.setCapCoverSensor(readParameterBool(node, "CapCoverSensor"));
            model.setCapDoubleWidth(readParameterBool(node, "CapDoubleWidth"));
            model.setCapDuplicateReceipt(readParameterBool(node, "CapDuplicateReceipt"));
            model.setCapFullCut(readParameterBool(node, "CapFullCut"));
            model.setCapPartialCut(readParameterBool(node, "CapPartialCut"));
            model.setCapGraphics(readParameterBool(node, "CapGraphics"));
            model.setCapGraphicsEx(readParameterBool(node, "CapGraphicsEx"));
            model.setCapPrintStringFont(readParameterBool(node, "CapPrintStringFont"));
            model.setCapShortStatus(readParameterBool(node, "CapShortStatus"));
            model.setCapFontMetrics(readParameterBool(node, "CapFontMetrics"));
            model.setCapOpenReceipt(readParameterBool(node, "CapOpenReceipt"));
            model.setNumVatRates(readParameterInt(node, "NumVatRates"));
            model.setAmountDecimalPlace(readParameterInt(node, "AmountDecimalPlace"));
            model.setNumHeaderLines(readParameterInt(node, "NumHeaderLines"));
            model.setNumTrailerLines(readParameterInt(node, "NumTrailerLines"));
            model.setTrailerTableNumber(readParameterInt(node, "TrailerTableNumber"));
            model.setHeaderTableNumber(readParameterInt(node, "HeaderTableNumber"));
            model.setHeaderTableRow(readParameterInt(node, "HeaderTableRow"));
            model.setTrailerTableRow(readParameterInt(node, "TrailerTableRow"));
            model.setMinHeaderLines(readParameterInt(node, "MinHeaderLines"));
            model.setMinTrailerLines(readParameterInt(node, "MinTrailerLines"));
            model.setMaxGraphicsWidth(readParameterInt(node, "MaxGraphicsWidth"));
            model.setMaxGraphicsHeight(readParameterInt(node, "MaxGraphicsHeight"));
            model.setPrintWidth(readParameterInt(node, "PrintWidth"));
            model.setTextLength(readParameterIntArray(node, "TextLength"));
            model.setSupportedBaudRates(readParameterIntArray(node, "SupportedBaudRates"));
            loadParameters(node, model.getParameters());
            
            models.add(model);
        } catch (Exception e) {
            logger.error(e);
        }
    }

    public void loadParameters(Node node, PrinterParameters items)
            throws Exception {
        Element element = (Element) node;
        Element element2 = (Element) element.getElementsByTagName("parameters").item(0);
        NodeList nodes = element2.getElementsByTagName("parameter");
        for (int i = 0; i < nodes.getLength(); i++) {
            Node paramNode = nodes.item(i);
            PrinterParameter parameter = new PrinterParameter();
            parameter.setId(readParameterInt(paramNode, "ID"));
            parameter.setTableNumber(readParameterInt(paramNode, "TableNumber"));
            parameter.setRowNumber(readParameterInt(paramNode, "RowNumber"));
            parameter.setFieldNumber(readParameterInt(paramNode, "FieldNumber"));
            loadValues(parameter.getValues(), paramNode);
            items.add(parameter);
        }
    }

    public void loadValues(ParameterValues values, Node node)
            throws Exception {
        Element element = (Element) node;
        Node paramsNode = element.getElementsByTagName("values").item(0);
        NodeList nodes = element.getElementsByTagName("value");
        for (int i = 0; i < nodes.getLength(); i++) {
            Node itemNode = nodes.item(i);
            ParameterValue item = new ParameterValue();
            item.setValue(readParameterInt(itemNode, "Value"));
            item.setFieldValue(readParameterInt(itemNode, "FieldValue"));
            values.add(item);
        }
    }
}
