/*
 *  Copyright 2007-2008, Plutext Pty Ltd.
 *   
 *  This file is part of docx4j.

    docx4j is licensed under the Apache License, Version 2.0 (the "License"); 
    you may not use this file except in compliance with the License. 

    You may obtain a copy of the License at 

        http://www.apache.org/licenses/LICENSE-2.0 

    Unless required by applicable law or agreed to in writing, software 
    distributed under the License is distributed on an "AS IS" BASIS, 
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    See the License for the specific language governing permissions and 
    limitations under the License.

 */

package org.docx4j.samples;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;

import org.docx4j.XmlUtils;
import org.docx4j.convert.out.flatOpcXml.FlatOpcXmlCreator;
import org.docx4j.convert.out.html.AbstractHtmlExporter;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * The idea here was to display a docx
 * in the browser by converting it to 
 * Flat OPC XML, then applying CSS to it.
 * 
 * @author jharrop
 *
 */
public class CreateXmlCss {
	
	public final static String HTML_TOP = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"
		+"\n<html>"
		+"\n<head>"
		+"\n<style type=\"text/css\">";
	
	public final static String CSS_FOR_TABLES = "\n\n/* TABLE STYLES */"
		+ "\n.table { display:table; table-layout:fixed; border-color: #600; border-style: solid; border-width: 0 0 1px 1px; border-spacing: 0; border-collapse: collapse;}"
		+ "\n.tr { display:table-row;}"
		+ "\n.td { display:table-cell; border-color: #600; border-style: solid; margin: 0; padding: 4px; border-width: 1px 1px 0 0; background-color: #FFC;}\n";
	
	public final static String HTML_MIDDLE =  "</style>"
		+ "\n</head>\n<body>";

	public final static String HTML_TAIL =  "\n  </body>"
		    + "\n  <script type=\"text/javascript\" src=\"javeline_xpath.js\"></script>" 
			+ "\n  <script type=\"text/javascript\" src=\"wml_fix.js\"></script>"
			+ "\n</html>";
	
	    public static void main(String[] args) 
	            throws Exception {

	    	boolean save = true;
	    	
	    	// If you want to be able to display non-external images,
	    	// or you are extending wml_fix.js to do client-side
	    	// style resolution, you'll want to embed the entire
	    	// Flat OPC, rather than just document.xml
	    	boolean useFlatOPC = true;
	    	    	
//			String inputfilepath = System.getProperty("user.dir") + "/sample-docs/numbering-multilevel.docx";
	    	//String inputfilepath = System.getProperty("user.dir") + "/test3.docx";
//			 String inputfilepath = "/home/dev/workspace/docx4all/sample-docs/docx4all-CurrentDocxFeatures.docx";
			 String inputfilepath = "/home/dev/workspace/docx4j/sample-docs/StyleResolution.xml";
	    	
			System.out.println(inputfilepath);
			WordprocessingMLPackage wordMLPackage;
			org.docx4j.xmlPackage.Package flatOPC = null;
			if (inputfilepath.endsWith(".xml")) {
				
				JAXBContext jc = Context.jcXmlPackage;
				Unmarshaller u = jc.createUnmarshaller();
				u.setEventHandler(new org.docx4j.jaxb.JaxbValidationEventHandler());

				flatOPC = (org.docx4j.xmlPackage.Package)((JAXBElement)u.unmarshal(
						new javax.xml.transform.stream.StreamSource(new FileInputStream(inputfilepath)))).getValue(); 

				org.docx4j.convert.in.FlatOpcXmlImporter xmlPackage = new org.docx4j.convert.in.FlatOpcXmlImporter( flatOPC); 

				wordMLPackage = (WordprocessingMLPackage)xmlPackage.get(); 
			
			} else {
				wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath));
			}
			
			// Convert it to HTML (ie no self-closing tags)
			Object o;
			Document doc;
			if (useFlatOPC) {
				if (flatOPC==null) {
					// We must have started with a .docx
					FlatOpcXmlCreator worker = new FlatOpcXmlCreator(wordMLPackage);
					o = worker.get();
				} else {
					o = flatOPC;
				}
				doc = XmlUtils.marshaltoW3CDomDocument(o, Context.jcXmlPackage);
			} else {
				o = wordMLPackage.getMainDocumentPart().getJaxbElement();
				doc = XmlUtils.marshaltoW3CDomDocument(o);
			}
			
			StringBuffer buff = new StringBuffer();
			serialise(doc, buff, "  " );
			
			// Generate CSS   	
			String css_other = AbstractHtmlExporter.getCssForStyles(wordMLPackage); 			
			
			// Join it all together
			String result = HTML_TOP + CSS_FOR_TABLES + css_other + HTML_MIDDLE + buff.toString() + HTML_TAIL;
						
						
			OutputStream os; 
			if (save) {
				os = new java.io.FileOutputStream(inputfilepath + ".html");
			} else {
				os = System.out;
			}
			os.write(result.getBytes());
			os.close();
			if (save) {
				System.out.println("Saved: " + inputfilepath + ".html ");
			} 
	        	        
	    }
	    
		public static void serialise( Node sourceNode, StringBuffer result, String indent ) {
		    	
	    	//log.debug("node type" + sourceNode.getNodeType());
		    	
            switch (sourceNode.getNodeType() ) {

            	case Node.DOCUMENT_NODE: // type 9
            
                    // recurse on each child
                    NodeList nodes = sourceNode.getChildNodes();
                    if (nodes != null) {
                        for (int i=0; i<nodes.getLength(); i++) {
                        	serialise((Node)nodes.item(i), result, indent);
                        }
                    }
                    break;
                case Node.ELEMENT_NODE:
                    
                    // Copy of the node itself
                	result.append("\n" + indent + "<" + sourceNode.getNodeName() );                    
            		
            		// .. its attributes
                	NamedNodeMap atts = sourceNode.getAttributes();
                	for (int i = 0 ; i < atts.getLength() ; i++ ) {
                		Attr attr = (Attr)atts.item(i);
                		
//		                		if (attr.getNamespaceURI()!=null
//		                				&& attr.getNamespaceURI().equals("http://www.w3.org/2000/xmlns/")) {
//			                		result.append(" " + attr.getLocalName() + "=\"" + attr.getValue() + "\"");
//		                		} else {
//			                		result.append(" " + attr.getName() + "=\"" + attr.getValue() + "\"");
//		                		}
                		result.append(" " + attr.getName() + "=\"" + attr.getValue() + "\"");
                	}

                	result.append(">");
                	
                	if (sourceNode.getChildNodes() == null
                			|| sourceNode.getChildNodes().getLength() ==0) {
                		// this is where we force tags to be
                		// non self-closing
                		result.append("</" + sourceNode.getNodeName() + ">" );
                	} else {
	                    // recurse on each child
                		NodeList children = sourceNode.getChildNodes();
                		boolean hasNonTextChild = false;
	                    if (children != null) {
	                        for (int i=0; i<children.getLength(); i++) {
	                        	//treeCopy( (DTMNodeProxy)children.item(i), newChild);
	                        	if (children.item(i).getNodeType() != Node.TEXT_NODE) {
	                        		hasNonTextChild = true;
	                        	}
	                        	serialise( (Node)children.item(i), result, indent+ "  ");
	                        }
	                    }
	                    if (hasNonTextChild) {
	                    	result.append("\n" + indent);
	                    }
	                    result.append("</" + sourceNode.getNodeName() + ">" );
                	}
                    break;

                case Node.TEXT_NODE:
                	//Node textNode = destParent.getOwnerDocument().createTextNode(sourceNode.getNodeValue());       
                	result.append(sourceNode.getNodeValue());
                    break;

//                case Node.CDATA_SECTION_NODE:
//                    writer.write("<![CDATA[" +
//                                 node.getNodeValue() + "]]>");
//                    break;
//
//                case Node.COMMENT_NODE:
//                    writer.write(indentLevel + "<!-- " +
//                                 node.getNodeValue() + " -->");
//                    writer.write(lineSeparator);
//                    break;
//
//                case Node.PROCESSING_INSTRUCTION_NODE:
//                    writer.write("<?" + node.getNodeName() +
//                                 " " + node.getNodeValue() +
//                                 "?>");
//                    writer.write(lineSeparator);
//                    break;
//
//                case Node.ENTITY_REFERENCE_NODE:
//                    writer.write("&" + node.getNodeName() + ";");
//                    break;
//
//                case Node.DOCUMENT_TYPE_NODE:
//                    DocumentType docType = (DocumentType)node;
//                    writer.write("<!DOCTYPE " + docType.getName());
//                    if (docType.getPublicId() != null)  {
//                        System.out.print(" PUBLIC \"" +
//                            docType.getPublicId() + "\" ");
//                    } else {
//                        writer.write(" SYSTEM ");
//                    }
//                    writer.write("\"" + docType.getSystemId() + "\">");
//                    writer.write(lineSeparator);
//                    break;
            }
        }	

	    
	}