package org.docx4j.samples;

import java.io.File;
import java.util.List;

import jakarta.xml.bind.JAXBException;

import org.docx4j.XmlUtils;
import org.docx4j.jaxb.XPathBinderAssociationIsPartialException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.JaxbXmlPartXPathAware;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;

public class XPathOverDir {

	
	/**
	 * Example of how to find an object in document.xml
	 * via XPath.
	 * 
	 * As explained in Getting Started, there are limitations 
	 * in the JAXB reference implementation which make this
	 * approach buggy:
	 * 
	 * 1. the xpath expressions are evaluated against the XML 
	 * document as it was when first opened in docx4j.  You 
	 * can update the associated XML document once only, by
	 * passing true into getJAXBNodesViaXPath. Updating it again 
	 * (with current JAXB 2.1.x or 2.2.x) will cause an error.
	 * 
	 * 2. For some objects,JAXB can’t get parent (with getParent)
	 * 
	 * 3. For some document, JAXB can’t set up the XPath at all!
	 * 
	 * If these problems affect you, you could try using
	 * MOXy as your JAXB implementation (which docx4j supports
	 * as from forthcoming docx4j 3.0).  See 
	 * http://www.docx4java.org/forums/docx-java-f6/moxy-t1242.html
	 * 
	 * Alternatively, the tried and tested approach is
	 * to use TraversalUtil;
	 * see the OpenMainDocumentAndTraverse sample.
	 * 
	 */
	public static void main(String[] args) throws Exception {
		
		String inputdir = System.getProperty("user.dir") + "/dd/";
		
		File dir = new File(inputdir);
		
		if (dir.isDirectory()) {
			
			String[] files = dir.list();
			
			for (int i = 0; i<files.length; i++  ) {
				System.out.println("\n" + files[i] + "\n\n");
				
				if (files[i].endsWith("docx")) {
					WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputdir + "/" + files[i]));		
					MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
					
					xpathQuery(documentPart, "//w:fldChar[count(w:ffData)=1]");
				}
			}
			
		}

						
	}

	private static void xpathQuery(JaxbXmlPartXPathAware part, String xpath) throws XPathBinderAssociationIsPartialException, JAXBException {
		
//		String xpath = "//w:t[contains(text(),'scaled')]";
		//String xpath = "//w:r[w:t[contains(text(),'scaled')]]";
		
		List<Object> list = part.getJAXBNodesViaXPath(xpath, false);
		
		System.out.println("got " + list.size() + " matching " + xpath );
		
		for (Object o : list) {
			
			//System.out.println(o.getClass().getName() );
			
			Object o2 = XmlUtils.unwrap(o);
			// this is ok, provided the results of the Callback
			// won't be marshalled			
			
			if (o2 instanceof org.docx4j.wml.Text) {
				
				org.docx4j.wml.Text txt = (org.docx4j.wml.Text)o2;
				
				System.out.println( txt.getValue() );
				
				// Demonstrate the getParent bug
				//Object parent = txt.getParent();			
				//System.out.println( "parent: " +  XmlUtils.unwrap(parent).getClass().getName() );
			} else {
				System.out.println( XmlUtils.marshaltoString(o, true, true));
			}
		
			
			
		}
		
	}
		
}
