/** Bind the content controls of the passed document to the xml. */
  public static void bind(WordprocessingMLPackage wmlPackage, Document xmlDocument, int flags)
      throws Docx4JException {
    OpenDoPEHandler openDoPEHandler = null;
    CustomXmlDataStoragePart customXmlDataStoragePart = null;
    RemovalHandler removalHandler = null;
    String xpathStorageItemId = null;

    if (flags == FLAG_NONE) {
      // do everything
      flags =
          (FLAG_BIND_INSERT_XML | FLAG_BIND_BIND_XML | FLAG_BIND_REMOVE_SDT | FLAG_BIND_REMOVE_XML);
    }

    xpathStorageItemId = findXPathStorageItemIdInXPathsPart(wmlPackage);
    if ((xpathStorageItemId == null) && (flags == FLAG_BIND_INSERT_XML)) {
      // If no XPathsPart found and the user only wants to inject the XML
      // then search for a storageItemId via the content controls.
      // If the user wants to do more, then it won't work as the BindingHandler
      // relies on the XPathsPart
      xpathStorageItemId = findXPathStorageItemIdInContentControls(wmlPackage);
    }
    if (xpathStorageItemId == null) {
      throw new Docx4JException(
          "No xpathStorageItemId found, does the document contain content controls that are bound?");
    }

    if ((flags & FLAG_BIND_INSERT_XML) == FLAG_BIND_INSERT_XML) {
      insertXMLData(wmlPackage, xpathStorageItemId, xmlDocument);
    }
    if ((flags & FLAG_BIND_BIND_XML) == FLAG_BIND_BIND_XML) {
      openDoPEHandler = new OpenDoPEHandler(wmlPackage);
      openDoPEHandler.preprocess();
      BindingHandler.applyBindings(wmlPackage);
    }
    if ((flags & FLAG_BIND_REMOVE_SDT) == FLAG_BIND_REMOVE_SDT) {
      removeSDTs(wmlPackage);
    }
    if ((flags & FLAG_BIND_REMOVE_XML) == FLAG_BIND_REMOVE_XML) {
      removeDefinedCustomXmlParts(wmlPackage, xpathStorageItemId);
    }
  }
  /** @param args */
  public static void main(String[] args) throws Exception {

    String inputfilepath =
        System.getProperty("user.dir") + "/sample-docs/word/databinding/invoice.docx";

    String data = System.getProperty("user.dir") + "/sample-docs/word/databinding/invoice-data.xml";

    WordprocessingMLPackage wordMLPackage =
        WordprocessingMLPackage.load(new java.io.File(inputfilepath));

    filepathprefix = inputfilepath.substring(0, inputfilepath.lastIndexOf("."));
    System.out.println(filepathprefix);

    StringBuilder timingSummary = new StringBuilder();

    // Find custom xml item id and inject data_file.xml
    long startTime = System.currentTimeMillis();
    CustomXmlDataStoragePart customXmlDataStoragePart =
        CustomXmlDataStoragePartSelector.getCustomXmlDataStoragePart(wordMLPackage);
    if (customXmlDataStoragePart == null) {
      throw new RuntimeException("no xml");
    }
    customXmlDataStoragePart.getData().setDocument(new FileInputStream(new File(data)));
    long endTime = System.currentTimeMillis();
    timingSummary.append("\nmerge data: " + (endTime - startTime));
    System.out.println("data merged");

    SaveToZipFile saver = new SaveToZipFile(wordMLPackage);
    saver.save(new File(System.getProperty("user.dir") + "/OUT_injected.docx"));

    // Process conditionals and repeats
    startTime = System.currentTimeMillis();
    OpenDoPEHandler odh = new OpenDoPEHandler(wordMLPackage);
    odh.preprocess();
    endTime = System.currentTimeMillis();
    timingSummary.append("OpenDoPEHandler: " + (endTime - startTime));

    //		System.out.println(
    //				XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true)
    //				);
    saver.save(filepathprefix + "_1_preprocessed.docx");
    System.out.println("Saved: " + filepathprefix + "_1_preprocessed.docx");

    startTime = System.currentTimeMillis();
    OpenDoPEIntegrity odi = new OpenDoPEIntegrity();
    odi.process(wordMLPackage);
    endTime = System.currentTimeMillis();
    timingSummary.append("\nOpenDoPEIntegrity: " + (endTime - startTime));

    //		System.out.println(
    //				XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true)
    //				);
    saver = new SaveToZipFile(wordMLPackage);
    saver.save(filepathprefix + "_2_integrity.docx");
    System.out.println("Saved: " + filepathprefix + "_2_integrity.docx");

    // Apply the bindings
    saver = new SaveToZipFile(wordMLPackage);

    BindingHandler.setHyperlinkStyle("Hyperlink");
    startTime = System.currentTimeMillis();

    //			AtomicInteger bookmarkId = odh.getNextBookmarkId();
    AtomicInteger bookmarkId = new AtomicInteger();

    BindingHandler bh = new BindingHandler(wordMLPackage);
    bh.setStartingIdForNewBookmarks(bookmarkId);
    bh.applyBindings(wordMLPackage.getMainDocumentPart());

    endTime = System.currentTimeMillis();
    timingSummary.append("\nBindingHandler.applyBindings: " + (endTime - startTime));
    //		System.out.println(
    //				XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true)
    //				);
    saver.save(filepathprefix + "_3_bound.docx");
    System.out.println("Saved: " + filepathprefix + "_3_bound.docx");

    // Either demonstrate reverter, or stripping of controls;
    // you can't do both. So comment out one or the other.
    //		reverter(inputfilepath, filepathprefix + "_bound.docx");
    //
    // Strip content controls
    startTime = System.currentTimeMillis();
    RemovalHandler rh = new RemovalHandler();
    rh.removeSDTs(wordMLPackage, Quantifier.ALL);
    endTime = System.currentTimeMillis();
    timingSummary.append("\nRemovalHandler: " + (endTime - startTime));

    saver.save(filepathprefix + "_4_stripped.docx");
    System.out.println("Saved: " + filepathprefix + "_4_stripped.docx");

    System.out.println(timingSummary);
  }
  /** @param args */
  public static void main(String[] args) throws Exception {

    String inputfilepath =
        System.getProperty("user.dir") + "/sample-docs/word/databinding/invoice2.docx";

    WordprocessingMLPackage wordMLPackage =
        WordprocessingMLPackage.load(new java.io.File(inputfilepath));

    filepathprefix = inputfilepath.substring(0, inputfilepath.lastIndexOf("."));
    System.out.println(filepathprefix);

    StringBuilder timingSummary = new StringBuilder();

    // Process conditionals and repeats
    long startTime = System.currentTimeMillis();
    OpenDoPEHandler odh = new OpenDoPEHandler(wordMLPackage);
    odh.preprocess();
    long endTime = System.currentTimeMillis();
    timingSummary.append("OpenDoPEHandler: " + (endTime - startTime));

    System.out.println(
        XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true));
    SaveToZipFile saver = new SaveToZipFile(wordMLPackage);
    saver.save(filepathprefix + "_1_preprocessed.docx");
    System.out.println("Saved: " + filepathprefix + "_1_preprocessed.docx");

    startTime = System.currentTimeMillis();
    OpenDoPEIntegrity odi = new OpenDoPEIntegrity();
    odi.process(wordMLPackage);
    endTime = System.currentTimeMillis();
    timingSummary.append("\nOpenDoPEIntegrity: " + (endTime - startTime));

    System.out.println(
        XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true));
    saver = new SaveToZipFile(wordMLPackage);
    saver.save(filepathprefix + "_2_integrity.docx");
    System.out.println("Saved: " + filepathprefix + "_2_integrity.docx");

    // Apply the bindings
    BindingHandler.setHyperlinkStyle("Hyperlink");
    startTime = System.currentTimeMillis();
    BindingHandler.applyBindings(wordMLPackage.getMainDocumentPart());
    endTime = System.currentTimeMillis();
    timingSummary.append("\nBindingHandler.applyBindings: " + (endTime - startTime));
    System.out.println(
        XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true));
    saver.save(filepathprefix + "_3_bound.docx");
    System.out.println("Saved: " + filepathprefix + "_3_bound.docx");

    // Either demonstrate reverter, or stripping of controls;
    // you can't do both. So comment out one or the other.
    //		reverter(inputfilepath, filepathprefix + "_bound.docx");
    //
    // Strip content controls
    startTime = System.currentTimeMillis();
    RemovalHandler rh = new RemovalHandler();
    rh.removeSDTs(wordMLPackage, Quantifier.ALL);
    endTime = System.currentTimeMillis();
    timingSummary.append("\nRemovalHandler: " + (endTime - startTime));

    saver.save(filepathprefix + "_4_stripped.docx");
    System.out.println("Saved: " + filepathprefix + "_4_stripped.docx");

    System.out.println(timingSummary);
  }