/**************************************************************
 * 
 * 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.
 * 
 *************************************************************/

import com.sun.star.accessibility.*;
import com.sun.star.uno.UnoRuntime;

import javax.swing.tree.*;
import javax.swing.event.*;



/** listen to tree model changes in order to update XAccessibleText objects
*/
class TextUpdateListener implements TreeModelListener
{
    public void treeNodesChanged(TreeModelEvent e)
    {
        try {
        // if the change is to the first child of a DefaultMutableTreeNode
        // with an XAccessibleText child, then we call updateText
        int[] aIndices = e.getChildIndices();
        if( (aIndices != null) &&
            (aIndices.length > 0) )
        {
            // we have a parent... lets check for XAccessibleText then
            DefaultMutableTreeNode aParent = (DefaultMutableTreeNode)
                (e.getTreePath().getLastPathComponent());
            DefaultMutableTreeNode aNode = (DefaultMutableTreeNode)
                (aParent.getChildAt(aIndices[0]));
            if( aParent.getUserObject() instanceof XAccessibleText)
            {
                // aha! we have an xText. So we can now check for
                // the various cases we support
                XAccessibleText xText = 
                    (XAccessibleText)aParent.getUserObject();

                if( aIndices[0] == 0 )
                {
                    // first child! Then we call updateText
                    updateText( xText, aNode.toString() );
                }
                else
                {
                    // JDK 1.4:
                    //                        // check for pattern "Selection:"
                    //                         Matcher m = Pattern.compile(
                    //                             "selection: \\[(-?[0-9]+),(-?[0-9]+)\\] \".*" ).
                    //                             matcher( aNode.toString() );
                    //                         if( m.matches() )
                    //                         {
                    //                             try
                    //                             {
                    //                                 // aha! Selection:
                    //                                 setSelection( xText, 
                    //                                               Integer.parseInt(m.group(1)), 
                    //                                               Integer.parseInt(m.group(2)) );
                    //                             }
                    //                             catch( NumberFormatException f )
                    //                             {
                    //                                 // ignore
                    //                             }
                    //                         }
                }
            }
        }
        }
        catch (com.sun.star.lang.IndexOutOfBoundsException aException)
        {}
    }

    // don't care:
    public void treeNodesInserted(TreeModelEvent e) { ; }
    public void treeNodesRemoved(TreeModelEvent e) { ; }
    public void treeStructureChanged(TreeModelEvent e) { ; }

    /** update the text */
    boolean updateText( XAccessibleText xText, String sNew )
        throws com.sun.star.lang.IndexOutOfBoundsException
    {
        // is this text editable? if not, fudge you and return
        XAccessibleEditableText xEdit = 
            (XAccessibleEditableText) UnoRuntime.queryInterface (
                XAccessibleEditableText.class, xText);
        if (xEdit == null)
            return false;

        String sOld = xText.getText();

        // false alarm? Early out if no change was done!
        if( sOld.equals( sNew ) )
            return false;

        // get the minimum length of both strings
        int nMinLength = sOld.length();
        if( sNew.length() < nMinLength )
            nMinLength = sNew.length();

        // count equal characters from front and end
        int nFront = 0;
        while( (nFront < nMinLength) &&
            (sNew.charAt(nFront) == sOld.charAt(nFront)) )
            nFront++;
        int nBack = 0;
        while( (nBack < nMinLength) &&
            ( sNew.charAt(sNew.length()-nBack-1) == 
                sOld.charAt(sOld.length()-nBack-1)    ) )
            nBack++;
        if( nFront + nBack > nMinLength )
            nBack = nMinLength - nFront;

        // so... the first nFront and the last nBack characters
        // are the same. Change the others!
        String sDel = sOld.substring( nFront, sOld.length() - nBack );
        String sIns = sNew.substring( nFront, sNew.length() - nBack );

        System.out.println("edit text: " + 
            sOld.substring(0, nFront) +
            " [ " + sDel + " -> " + sIns + " ] " +
            sOld.substring(sOld.length() - nBack) );

        boolean bRet = false;
        try
        {
            // edit the text, and use
            // (set|insert|delete|replace)Text as needed
            if( nFront+nBack == 0 )
                bRet = xEdit.setText( sIns );
            else if( sDel.length() == 0 )
                bRet = xEdit.insertText( sIns, nFront );
            else if( sIns.length() == 0 )
                bRet = xEdit.deleteText( nFront, sOld.length()-nBack );
            else
                bRet = xEdit.replaceText(nFront, sOld.length()-nBack,sIns);
        }
        catch( IndexOutOfBoundsException e )
        {
            bRet = false;
        }

        return bRet;
    }

    boolean setSelection( XAccessibleText xText, int p1, int p2 )
    {
        try
        {
            return xText.setSelection( p1, p2 );
        }
        catch( com.sun.star.lang.IndexOutOfBoundsException f )
        {
            return false;
        }
    }

    //         /** replace the given node with a new xText node */
    //         void updateNode( XAccessibleText xText, 
    //                          DefaultMutableTreeNode aNode )
    //         {
    //             // create a new node
    //             DefaultMutableTreeNode aNew = newTextTreeNode( xText );
    // 
    //             // get parent (must be DefaultMutableTreeNode)
    //             DefaultMutableTreeNode aParent = 
    //                 (DefaultMutableTreeNode)aNode.getParent();
    //             if( aParent != null )
    //             {
    //                 // remove old sub-tree, and insert new one
    //                 int nIndex = aParent.getIndex( aNode );
    //                 aParent.remove( nIndex );
    //                 aParent.insert( aNew, nIndex );
    //             }
    //         }
}
