/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 complex.writer;

import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.text.XTextDocument;
import com.sun.star.uno.UnoRuntime;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openoffice.test.OfficeConnection;
import static org.junit.Assert.*;

/**
 *
 * @author od138299
 */
public class CheckCrossReferences {

    private com.sun.star.container.XEnumeration xParaEnum;
    private com.sun.star.container.XEnumeration xPortionEnum;
    private com.sun.star.util.XRefreshable xFldsRefresh;

    public com.sun.star.text.XTextField getNextField()
        throws com.sun.star.uno.Exception
    {
        if ( xPortionEnum != null ) {
            while ( xPortionEnum.hasMoreElements() ) {
                com.sun.star.beans.XPropertySet xPortionProps =
                    (com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
                        com.sun.star.beans.XPropertySet.class , xPortionEnum.nextElement());
                final String sPortionType =
                    xPortionProps.getPropertyValue( "TextPortionType" ).toString();
                if ( sPortionType.equals( "TextField") ) {
                    com.sun.star.text.XTextField xField = (com.sun.star.text.XTextField)UnoRuntime.queryInterface(
                        com.sun.star.text.XTextField.class,
                        xPortionProps.getPropertyValue( "TextField" ) );
                    assertNotNull("Cannot retrieve next field.", xField);
                    return xField;
                }
            }
        }

        while ( xParaEnum.hasMoreElements() ) {
            com.sun.star.container.XEnumerationAccess aPara =
                (com.sun.star.container.XEnumerationAccess)UnoRuntime.queryInterface(
                    com.sun.star.container.XEnumerationAccess.class, xParaEnum.nextElement());
            xPortionEnum = aPara.createEnumeration();
            while ( xPortionEnum.hasMoreElements() ) {
                com.sun.star.beans.XPropertySet xPortionProps =
                    (com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
                        com.sun.star.beans.XPropertySet.class , xPortionEnum.nextElement());
                final String sPortionType =
                    xPortionProps.getPropertyValue( "TextPortionType" ).toString();
                if ( sPortionType.equals( "TextField") ) {
                    com.sun.star.text.XTextField xField = (com.sun.star.text.XTextField)UnoRuntime.queryInterface(
                        com.sun.star.text.XTextField.class,
                        xPortionProps.getPropertyValue( "TextField" ) );
                    assertNotNull("Cannot retrieve next field.", xField);
                    return xField;
                }
            }
        }

        fail("Cannot retrieve next field.");
        return null; // unreachable
    }

    public com.sun.star.beans.XPropertySet getFieldProps(
            com.sun.star.text.XTextField xField ) {
        com.sun.star.beans.XPropertySet xProps =
                (com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
                com.sun.star.beans.XPropertySet.class, xField );

        assertNotNull("Cannot retrieve field properties.", xProps);

        return xProps;
    }

    public void checkField( com.sun.star.text.XTextField xField,
            com.sun.star.beans.XPropertySet xProps,
            short nFormat,
            String aExpectedFldResult )
        throws com.sun.star.uno.Exception
    {
        // set requested format
        xProps.setPropertyValue("ReferenceFieldPart", new Short(nFormat));

        // refresh fields in order to get new format applied
        xFldsRefresh.refresh();

        String aFldResult = xField.getPresentation( false );
        assertEquals( "set reference field format doesn't result in correct field result",
                      aExpectedFldResult, aFldResult);
    }

    @Test public void checkCrossReferences() throws com.sun.star.uno.Exception {
        // setup paragraph enumeration
        {
            com.sun.star.container.XEnumerationAccess xParaEnumAccess =
                    (com.sun.star.container.XEnumerationAccess)UnoRuntime.queryInterface(
                    com.sun.star.container.XEnumerationAccess.class, document.getText());
            xParaEnum = xParaEnumAccess.createEnumeration();
        }

        // get field refresher
        {
            com.sun.star.text.XTextFieldsSupplier xFieldSupp =
                    (com.sun.star.text.XTextFieldsSupplier)UnoRuntime.queryInterface(
                    com.sun.star.text.XTextFieldsSupplier.class, document);
            xFldsRefresh = (com.sun.star.util.XRefreshable)UnoRuntime.queryInterface(
                    com.sun.star.util.XRefreshable.class, xFieldSupp.getTextFields());
        }

        // check first reference field
        {
            // strings for checking
            final String FldResult1 = "*i*";
            final String FldResult2 = "+b+*i*";
            final String FldResult3 = "-1-+b+*i*";
            final String FldResult4 = "1.";
            final String FldResult5 = " 1.";
            final String FldResult6 = "A. 1.";

            // variables for current field
            com.sun.star.text.XTextField xField = null;
            com.sun.star.beans.XPropertySet xProps = null;

            xField = getNextField();
            xProps = getFieldProps( xField );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER, FldResult2 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_NO_CONTEXT, FldResult1 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_FULL_CONTEXT, FldResult3 );

            xField = getNextField();
            xProps = getFieldProps( xField );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER, FldResult1 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_NO_CONTEXT, FldResult1 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_FULL_CONTEXT, FldResult3 );

            xField = getNextField();
            xProps = getFieldProps( xField );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER, FldResult3 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_NO_CONTEXT, FldResult1 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_FULL_CONTEXT, FldResult3 );

            xField = getNextField();
            xProps = getFieldProps( xField );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER, FldResult5 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_NO_CONTEXT, FldResult4 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_FULL_CONTEXT, FldResult6 );

            xField = getNextField();
            xProps = getFieldProps( xField );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER, FldResult4 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_NO_CONTEXT, FldResult4 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_FULL_CONTEXT, FldResult6 );

            xField = getNextField();
            xProps = getFieldProps( xField );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER, FldResult6 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_NO_CONTEXT, FldResult4 );
            checkField( xField, xProps, com.sun.star.text.ReferenceFieldPart.NUMBER_FULL_CONTEXT, FldResult6 );
        }

        // insert a certain cross-reference bookmark and a reference field to this bookmark
        {
            // restart paragraph enumeration
            com.sun.star.container.XEnumerationAccess xParaEnumAccess =
                    (com.sun.star.container.XEnumerationAccess)UnoRuntime.queryInterface(
                    com.sun.star.container.XEnumerationAccess.class, document.getText());
            xParaEnum = xParaEnumAccess.createEnumeration();

            // iterate on the paragraphs to find certain paragraph to insert the bookmark
            com.sun.star.text.XTextRange xParaTextRange = null;
            while ( xParaEnum.hasMoreElements() ) {
                xParaTextRange = (com.sun.star.text.XTextRange)UnoRuntime.queryInterface(
                    com.sun.star.text.XTextRange.class, xParaEnum.nextElement());
                if ( xParaTextRange.getString().equals( "J" ) ) {
                    break;
                }
                else {
                    xParaTextRange = null;
                }
            }
            assertNotNull(
                "Cannot find paragraph to insert cross-reference bookmark.",
                xParaTextRange);

            // insert bookmark
            XMultiServiceFactory xFac = (XMultiServiceFactory)UnoRuntime.queryInterface(
                    XMultiServiceFactory.class, document);
            final String cBookmarkName = "__RefNumPara__47114711";
            com.sun.star.text.XTextContent xBookmark =
                (com.sun.star.text.XTextContent)UnoRuntime.queryInterface(
                    com.sun.star.text.XTextContent.class,
                    xFac.createInstance( "com.sun.star.text.Bookmark" ) );
            if ( xBookmark != null ) {
                com.sun.star.container.XNamed xName =
                        (com.sun.star.container.XNamed)UnoRuntime.queryInterface(
                        com.sun.star.container.XNamed.class, xBookmark );
                xName.setName( cBookmarkName );
                xBookmark.attach(xParaTextRange.getStart());
            }

            // insert reference field, which references the inserted bookmark
            com.sun.star.text.XTextContent xNewField =
                (com.sun.star.text.XTextContent)UnoRuntime.queryInterface(
                    com.sun.star.text.XTextContent.class,
                    xFac.createInstance( "com.sun.star.text.TextField.GetReference" ) );
            if ( xNewField != null ) {
                com.sun.star.beans.XPropertySet xFieldProps =
                        (com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
                        com.sun.star.beans.XPropertySet.class, xNewField );
                xFieldProps.setPropertyValue( "ReferenceFieldPart", new Short(com.sun.star.text.ReferenceFieldPart.TEXT) );
                xFieldProps.setPropertyValue( "ReferenceFieldSource", new Short(com.sun.star.text.ReferenceFieldSource.BOOKMARK) );
                xFieldProps.setPropertyValue( "SourceName", cBookmarkName );
                com.sun.star.text.XTextRange xFieldTextRange =
                        (com.sun.star.text.XTextRange)UnoRuntime.queryInterface(
                        com.sun.star.text.XTextRange.class, xParaEnum.nextElement());
                xNewField.attach(xFieldTextRange.getEnd());
                xFldsRefresh.refresh();
            }

            // check inserted reference field
            com.sun.star.text.XTextField xField =
                    (com.sun.star.text.XTextField)UnoRuntime.queryInterface(
                    com.sun.star.text.XTextField.class, xNewField );
            assertEquals( "inserted reference field doesn't has correct field result",
                          "J", xField.getPresentation( false ) );

            xParaTextRange.getStart().setString( "Hallo new bookmark: " );
            xFldsRefresh.refresh();
            assertEquals( "inserted reference field doesn't has correct field result",
                          "Hallo new bookmark: J", xField.getPresentation( false ) );
        }
    }

    @Before public void setUpDocument() throws com.sun.star.uno.Exception {
        document = util.WriterTools.loadTextDoc(
            UnoRuntime.queryInterface(
                XMultiServiceFactory.class,
                connection.getComponentContext().getServiceManager()),
            TestDocument.getUrl("CheckCrossReferences.odt"));
    }

    @After public void tearDownDocument() {
        util.DesktopTools.closeDoc(document);
    }

    private XTextDocument document = null;

    @BeforeClass public static void setUpConnection() throws Exception {
        connection.setUp();
    }

    @AfterClass public static void tearDownConnection()
        throws InterruptedException, com.sun.star.uno.Exception
    {
        connection.tearDown();
    }

    private static final OfficeConnection connection = new OfficeConnection();
}