package Examples;

// Copyright (c) 2001-2025 Aspose Pty Ltd. All Rights Reserved.
//
// This file is part of Aspose.Words. The source code in this file
// is only intended as a supplement to the documentation, and is provided
// "as is", without warranty of any kind, either expressed or implied.
//////////////////////////////////////////////////////////////////////////

import com.aspose.words.*;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

@Test
public class ExNodeImporter extends ApiExampleBase {
    @Test(dataProvider = "keepSourceNumberingDataProvider")
    public void keepSourceNumbering(boolean keepSourceNumbering) throws Exception {
        //ExStart
        //ExFor:ImportFormatOptions.KeepSourceNumbering
        //ExFor:NodeImporter.#ctor(DocumentBase, DocumentBase, ImportFormatMode, ImportFormatOptions)
        //ExSummary:Shows how to resolve list numbering clashes in source and destination documents.
        // Open a document with a custom list numbering scheme, and then clone it.
        // Since both have the same numbering format, the formats will clash if we import one document into the other.
        Document srcDoc = new Document(getMyDir() + "Custom list numbering.docx");
        Document dstDoc = srcDoc.deepClone();

        // When we import the document's clone into the original and then append it,
        // then the two lists with the same list format will join.
        // If we set the "KeepSourceNumbering" flag to "false", then the list from the document clone
        // that we append to the original will carry on the numbering of the list we append it to.
        // This will effectively merge the two lists into one.
        // If we set the "KeepSourceNumbering" flag to "true", then the document clone
        // list will preserve its original numbering, making the two lists appear as separate lists. 
        ImportFormatOptions importFormatOptions = new ImportFormatOptions();
        importFormatOptions.setKeepSourceNumbering(keepSourceNumbering);

        NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KEEP_DIFFERENT_STYLES, importFormatOptions);
        for (Paragraph paragraph : srcDoc.getFirstSection().getBody().getParagraphs()) {
            Node importedNode = importer.importNode(paragraph, true);
            dstDoc.getFirstSection().getBody().appendChild(importedNode);
        }

        dstDoc.updateListLabels();

        if (keepSourceNumbering) {
            Assert.assertEquals(
                    "6. Item 1\r\n" +
                            "7. Item 2 \r\n" +
                            "8. Item 3\r\n" +
                            "9. Item 4\r\n" +
                            "6. Item 1\r\n" +
                            "7. Item 2 \r\n" +
                            "8. Item 3\r\n" +
                            "9. Item 4", dstDoc.getFirstSection().getBody().toString(SaveFormat.TEXT).trim());
        } else {
            Assert.assertEquals(
                    "6. Item 1\r\n" +
                            "7. Item 2 \r\n" +
                            "8. Item 3\r\n" +
                            "9. Item 4\r\n" +
                            "10. Item 1\r\n" +
                            "11. Item 2 \r\n" +
                            "12. Item 3\r\n" +
                            "13. Item 4", dstDoc.getFirstSection().getBody().toString(SaveFormat.TEXT).trim());
        }
        //ExEnd
    }

    @DataProvider(name = "keepSourceNumberingDataProvider")
    public static Object[][] keepSourceNumberingDataProvider() {
        return new Object[][]
                {
                        {false},
                        {true},
                };
    }

    //ExStart
    //ExFor:Paragraph.IsEndOfSection
    //ExFor:NodeImporter
    //ExFor:NodeImporter.#ctor(DocumentBase, DocumentBase, ImportFormatMode)
    //ExFor:NodeImporter.ImportNode(Node, Boolean)
    //ExSummary:Shows how to insert the contents of one document to a bookmark in another document.
    @Test//ExSkip
    public void insertAtBookmark() throws Exception {
        Document doc = new Document();
        DocumentBuilder builder = new DocumentBuilder(doc);

        builder.startBookmark("InsertionPoint");
        builder.write("We will insert a document here: ");
        builder.endBookmark("InsertionPoint");

        Document docToInsert = new Document();
        builder = new DocumentBuilder(docToInsert);

        builder.write("Hello world!");

        docToInsert.save(getArtifactsDir() + "NodeImporter.InsertAtMergeField.docx");

        Bookmark bookmark = doc.getRange().getBookmarks().get("InsertionPoint");
        insertDocument(bookmark.getBookmarkStart().getParentNode(), docToInsert);

        Assert.assertEquals("We will insert a document here: " +
                "\rHello world!", doc.getText().trim());
    }

    /// <summary>
    /// Inserts the contents of a document after the specified node.
    /// </summary>
    static void insertDocument(Node insertionDestination, Document docToInsert) {
        if (((insertionDestination.getNodeType()) == (NodeType.PARAGRAPH)) || ((insertionDestination.getNodeType()) == (NodeType.TABLE))) {
            CompositeNode destinationParent = insertionDestination.getParentNode();

            NodeImporter importer =
                    new NodeImporter(docToInsert, insertionDestination.getDocument(), ImportFormatMode.KEEP_SOURCE_FORMATTING);

            // Loop through all block-level nodes in the section's body,
            // then clone and insert every node that is not the last empty paragraph of a section.
            for (Section srcSection : docToInsert.getSections())
                for (Node srcNode : srcSection.getBody()) {
                    if (((srcNode.getNodeType()) == (NodeType.PARAGRAPH))) {
                        Paragraph para = (Paragraph) srcNode;
                        if (para.isEndOfSection() && !para.hasChildNodes())
                            continue;
                    }

                    Node newNode = importer.importNode(srcNode, true);

                    destinationParent.insertAfter(newNode, insertionDestination);
                    insertionDestination = newNode;
                }
        } else {
            throw new IllegalArgumentException("The destination node should be either a paragraph or table.");
        }
    }
    //ExEnd

    @Test
    public void insertAtMergeField() throws Exception {
        Document doc = new Document();
        DocumentBuilder builder = new DocumentBuilder(doc);
        builder.write("A document will appear here: ");
        builder.insertField(" MERGEFIELD Document_1 ");

        Document subDoc = new Document();
        builder = new DocumentBuilder(subDoc);
        builder.write("Hello world!");

        subDoc.save(getArtifactsDir() + "NodeImporter.InsertAtMergeField.docx");

        doc.getMailMerge().setFieldMergingCallback(new InsertDocumentAtMailMergeHandler());

        // The main document has a merge field in it called "Document_1".
        // Execute a mail merge using a data source that contains a local system filename
        // of the document that we wish to insert into the MERGEFIELD.
        doc.getMailMerge().execute(new String[]{"Document_1"},
                new Object[]{getArtifactsDir() + "NodeImporter.InsertAtMergeField.docx"});

        Assert.assertEquals("A document will appear here: \r" +
                "Hello world!", doc.getText().trim());
    }

    /// <summary>
    /// If the mail merge encounters a MERGEFIELD with a specified name,
    /// this handler treats the current value of a mail merge data source as a local system filename of a document.
    /// The handler will insert the document in its entirety into the MERGEFIELD instead of the current merge value.
    /// </summary>
    private static class InsertDocumentAtMailMergeHandler implements IFieldMergingCallback {
        public void /*IFieldMergingCallback.*/fieldMerging(FieldMergingArgs args) throws Exception {
            if ("Document_1".equals(args.getDocumentFieldName())) {
                DocumentBuilder builder = new DocumentBuilder(args.getDocument());
                builder.moveToMergeField(args.getDocumentFieldName());

                Document subDoc = new Document((String) args.getFieldValue());

                insertDocument(builder.getCurrentParagraph(), subDoc);

                if (!builder.getCurrentParagraph().hasChildNodes())
                    builder.getCurrentParagraph().remove();

                args.setText(null);
            }
        }

        public void /*IFieldMergingCallback.*/imageFieldMerging(ImageFieldMergingArgs args) {
            // Do nothing.
        }
    }
}
