/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


package fr.gouv.finances.cp.xemelios.importers.docetatProvider;

import fr.gouv.finances.cp.utils.xml.SAXWriter;
import fr.gouv.finances.cp.xemelios.common.config.DocumentModel;
import fr.gouv.finances.cp.xemelios.common.config.NSModel;
import java.io.OutputStream;
import java.util.Stack;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.apache.log4j.Logger;
import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
 *
 * @author chm
 */
public abstract class AbstractWriter extends SAXWriter {
    private static final Logger logger = Logger.getLogger(AbstractWriter.class);
        private AttributesHolder attHolder;
        private NodesHolder nodeHolder;
        protected Stack<QName> stack;
        private DocumentModel dm;
//        private String header,  footer;

        public AbstractWriter(DocumentModel dm,OutputStream out, String encoding, AttributesHolder attHolder, NodesHolder nodeHolder, NamespaceHolder ns) {
            super(out, encoding);
            this.attHolder = attHolder;
            this.nodeHolder = nodeHolder;
            stack = new Stack<QName>();
            this.dm=dm;
        }

        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
            for(NSModel ns:dm.getNamespaces().getMappings()) {
                startPrefixMapping(ns.getPrefix(), ns.getUri());
            }
        }

        @Override
        public void endDocument() throws SAXException {
            super.endDocument();
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
            super.startElement(uri, localName, qName, atts);
            QName name = new QName(uri, localName!=null ? localName : qName);
            stack.push(name);
            String xpath = getXPath();
            AttributeHolder at = attHolder.getAttrsAt(xpath);
            if (at != null) {
                StringBuilder sb = new StringBuilder();
                sb.append(at.getName()).append("=\"").append(at.getValue()).append("\" ");
                output(sb.toString());
            }
        }

        public String getXPath() {
            StringBuilder sb = new StringBuilder();
            for (QName qn : stack) {
                sb.append("/");
                String prefix = getnsContext().getPrefix(qn.getNamespaceURI());
                if (prefix != null && prefix.length() > 0) {
                    sb.append(prefix).append(":");
                }
                sb.append(qn.getLocalPart());
            }
            return sb.toString();
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
            QName name = stack.pop();
        }

        protected void writeNode(Node node) {
            short type = node.getNodeType();
            switch (type) {
                case Node.DOCUMENT_NODE:
                    //document(writer, (Document)node);
                    break;

                case Node.DOCUMENT_FRAGMENT_NODE:
                    writeChildren(node);
                    break;

                case Node.DOCUMENT_TYPE_NODE:
                    //documentType((DocumentType) node);
                    break;

                case Node.ELEMENT_NODE:
                    element((Element) node);
                    break;

                case Node.ATTRIBUTE_NODE:
                    //attribute(writer, (Attr) node);
                    break;

                case Node.ENTITY_REFERENCE_NODE:
                    //entityReference(writer, (EntityReference) node);
                    break;

                case Node.ENTITY_NODE:
                    //entity(writer, (Entity) node);
                    break;

                case Node.NOTATION_NODE:
                    //notation(writer, (Notation) node);
                    break;

                case Node.PROCESSING_INSTRUCTION_NODE:
                    //procInst(writer, (ProcessingInstruction) node);
                    break;

                case Node.TEXT_NODE:
                    text((Text) node);
                    break;

                case Node.CDATA_SECTION_NODE:
                    //cDataSection(writer, (CDATASection) node);
                    break;

                case Node.COMMENT_NODE:
                    comment((Comment) node);
                    break;
            }
        }

        private void writeChildren(Node node) {
            NodeList l = node.getChildNodes();
            int size = l.getLength();
            for (int i = 0; i < size; i++) {
                Node n = l.item(i);
                writeNode(n);
            }
        }

        private void element(Element elem) {
            AttributesImpl atts = new AttributesImpl();
            NamedNodeMap a = elem.getAttributes();
            int size = a.getLength();
            for (int i = 0; i < size; i++) {
                Attr att = (Attr) a.item(i);
                if(att!=null) {
                    try {
                        atts.addAttribute(att.getNamespaceURI()==null ? XMLConstants.NULL_NS_URI : att.getNamespaceURI(), att.getLocalName()==null ? att.getName() : att.getLocalName(), att.getName(), "CDATA", att.getValue());
                    } catch(NullPointerException npEx) {
                        logger.debug("... really strange !");
                    }
                } else {
                    logger.info("strange, getting a null attribute...");
                }
            }
            try {
                startElement(elem.getNamespaceURI(), elem.getLocalName(), elem.getTagName(), atts);
            } catch(SAXException saxEx) {}

            if (elem.hasChildNodes()) {
                writeChildren(elem);
            }
            try {
                endElement(elem.getNamespaceURI(), elem.getLocalName(), elem.getTagName());
            } catch(SAXException saxEx) {}
        }

        private void text(Text text) {
            writeEscapedText(text.getData());
        }


        private void comment(Comment comment) {
            output("<!--");
            output(comment.getData());
            output("-->\n");
        }

}
