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

#include <cassert>

#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>

#include <oleacc.h>
#ifndef _SV_AccObjectWinManager_HXX
#include "AccObjectWinManager.hxx"
#endif
#include "AccEventListener.hxx"
#include "AccComponentEventListener.hxx"
#include "AccContainerEventListener.hxx"
#include "AccDialogEventListener.hxx"
#include "AccWindowEventListener.hxx"
#include "AccFrameEventListener.hxx"
#include "AccMenuEventListener.hxx"
#include "AccObjectContainerEventListener.hxx"
#include "AccParagraphEventListener.hxx"
#include "AccTextComponentEventListener.hxx"
#include "AccListEventListener.hxx"
#include "AccTreeEventListener.hxx"
#include "AccTableEventListener.hxx"
#include "AccObject.hxx"
#include "AccessibleEventId.h"
#include "AccessibleApplication.h"
#include "AccessibleApplication_i.c"
#include "unomsaaevent.hxx"
#include "checkmt.hxx"

#define CHILDID_SELF             0


using namespace std;
using namespace com::sun::star::accessibility;
using namespace com::sun::star::uno;

AccObjectWinManager* g_acc_manager = NULL;
AccObjectWinManager* AccObjectWinManager::me = NULL;

/**
   * Implementation of interface XMSAAService's method getAccObjectPtr() that return the
   * corresponding com interface with the MS event.
   *
   * @param   
   * @return  Com interface.
   */
long GetMSComPtr(long hWnd, long lParam, long wParam)
{
    if( g_acc_manager )
        return (long)g_acc_manager->Get_ToATInterface(HWND((void*)hWnd),lParam,wParam );
    return NULL;
}

/**
   * constructor
   * @param   Agent The agent kept in all listeners,it's the sole interface by which
   *                listener communicate with windows manager.
   *          pEventAccObj The present event accobject.
   *          oldFocus     Last focused object.
   *          isSelectionChanged flag that identifies if there is selection changed.
   *		  selectionChildObj  Selected object.
   *          dChildID	Chile resource ID.
   *          hAcc TopWindowHWND
   * @return  
   */
AccObjectWinManager::AccObjectWinManager( AccObjectManagerAgent* Agent ):
        pAgent( Agent ),
        oldFocus( NULL )
{
	m_bBridgeRegistered =IsBridgeRegisteredAcc();
}

/**
   * Public method to produce manager
   * @param   Agent The agent kept in all listeners,it's the sole interface by which
   *          listener communicate with windows manager.
   * @return  
   */
AccObjectWinManager* AccObjectWinManager::CreateAccObjectWinManagerInstance( AccObjectManagerAgent* Agent )
{
    if( me == NULL )
    {
        me = new AccObjectWinManager( Agent );
        g_acc_manager = me;
        return me;
    }

    return me;
}


/**
   * Destructor,clear all resource.
   * @param   
   * @return  
   */
AccObjectWinManager::~AccObjectWinManager()
{
    XIdAccList.clear();
    HwndXAcc.clear();
    XResIdAccList.clear();
    XHWNDDocList.clear();
#ifdef ACC_DEBUG

    fclose( pFile );
#endif
}


/**
   * Get valid com object interface when notifying some MSAA event
   * @param pWND The top window handle that contains that event control.
   * @param wParam Windows system interface. 
   * @return Com interface with event. 
   */

long AccObjectWinManager::Get_ToATInterface( HWND hWnd, long lParam, long wParam)
{
    vos::OGuard localGuard(maATInterfaceMutex);//

    IMAccessible* pRetIMAcc = NULL;

    if(lParam == OBJID_CLIENT )
    {
        AccObject* topWindowAccObj = GetTopWindowAccObj(hWnd);
        if(topWindowAccObj)
        {
            pRetIMAcc = topWindowAccObj->GetIMAccessible();
            if(pRetIMAcc)
                pRetIMAcc->AddRef();//increase COM reference count
        }
    }

    if ( pRetIMAcc && lParam == OBJID_CLIENT )
    {
        IAccessible* pTemp = dynamic_cast<IAccessible*>( pRetIMAcc );
        HRESULT result = LresultFromObject(IID_IAccessible, wParam, pTemp);
        pTemp->Release();
        return result;
    }
    return 0;
}

/**
   * Search AccObject by XAccessible pointer from our container.
   * @param pXAcc XAccessible interface.
   * @return Pointer of accObject that is found. 
   */
AccObject* AccObjectWinManager::GetAccObjByXAcc( XAccessible* pXAcc)
{
    if( pXAcc == NULL)
        return NULL;

    XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( (void*)pXAcc );
    if ( pIndTemp == XIdAccList.end() )
        return NULL;

    return &(pIndTemp->second);
}

/**
   * Search XAccessible by AccObject pointer from our container.
   * @param pAccObj AccObject pointer.
   * @return Pointer of XAccessible Interface. 
   */
XAccessible* AccObjectWinManager::GetXAccByAccObj(AccObject* pAccObj)
{
    XIdToAccObjHash::iterator iter = XIdAccList.begin();
    while(iter!=XIdAccList.end())
    {
        AccObject* tmp = &(iter->second);
        if(tmp== pAccObj)
            return (XAccessible*)(iter->first);
        iter++;
    }
    return NULL;
}

/**
   * get acc object of top window by its handle
   * @param hWnd, top window handle
   * @return pointer to AccObject
   */
AccObject* AccObjectWinManager::GetTopWindowAccObj(HWND hWnd)
{
    XHWNDToXAccHash::iterator iterResult =HwndXAcc.find(hWnd);
    if(iterResult == HwndXAcc.end())
        return NULL;
    XAccessible* pXAcc = (XAccessible*)(iterResult->second);
    return GetAccObjByXAcc(pXAcc);
}

/**
   * Simulate MSAA event via XAccessible interface and event type.
   * @param pXAcc XAccessible interface.
   * @param state Customize Interface   
   * @return The terminate result that identifies if the call is successful. 
   */
sal_Bool AccObjectWinManager::NotifyAccEvent(XAccessible* pXAcc,short state)
{
    vos::OGuard aGuard(aNotifyMutex);

	if (!m_bBridgeRegistered)
	{
		return sal_False;
	}
    if (!IsInMainThread())
    {
        return sal_False;
    }

    Reference< XAccessibleContext > pRContext;

    if( pXAcc == NULL)
        return sal_False;


    pRContext = pXAcc->getAccessibleContext();
    if( !pRContext.is() )
        return sal_False;


    AccObject* selfAccObj= GetAccObjByXAcc(pXAcc);

    if(selfAccObj==NULL)
        return sal_False;

    int selectNum =0;

    long dChildID = selfAccObj->GetResID();
    HWND hAcc = selfAccObj->GetParentHWND();

    switch(state)
    {
    case UM_EVENT_STATE_FOCUSED:
        {
            UpdateAccFocus(pXAcc);
            if( selfAccObj )
                selfAccObj->UpdateDefaultAction( );
            UpdateValue(pXAcc);
            NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID  );
            break;
        }
    case UM_EVENT_STATE_BUSY:
        NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_STATE_CHECKED:
        NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_STATE_PRESSED:
        NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;

    //Removed fire out selected event
    //case UM_EVENT_STATE_SELECTED:
    //	NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID  );
    //	break;
    case UM_EVENT_STATE_ARMED:
        UpdateAccFocus(pXAcc);
        NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_MENU_START:
        NotifyWinEvent( EVENT_SYSTEM_MENUSTART,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_MENU_END:
        NotifyWinEvent( EVENT_SYSTEM_MENUEND,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_MENUPOPUPSTART:
        NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPSTART,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_MENUPOPUPEND:
        NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPEND,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_SELECTION_CHANGED:
        NotifyWinEvent( EVENT_OBJECT_SELECTION,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_SELECTION_CHANGED_ADD:
       	NotifyWinEvent( EVENT_OBJECT_SELECTIONADD,hAcc, OBJID_CLIENT,dChildID  );
       	break;
    case UM_EVENT_SELECTION_CHANGED_REMOVE:
       	NotifyWinEvent( EVENT_OBJECT_SELECTIONREMOVE,hAcc, OBJID_CLIENT,dChildID  );
       	break;
    case UM_EVENT_SELECTION_CHANGED_WITHIN:
       	NotifyWinEvent( EVENT_OBJECT_SELECTIONWITHIN,hAcc, OBJID_CLIENT,dChildID  );
       	break;
    case UM_EVENT_OBJECT_VALUECHANGE:
        UpdateValue(pXAcc);
        NotifyWinEvent( EVENT_OBJECT_VALUECHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_NAMECHANGE:
        NotifyWinEvent( EVENT_OBJECT_NAMECHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_DESCRIPTIONCHANGE:
        NotifyWinEvent( EVENT_OBJECT_DESCRIPTIONCHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_DEFACTIONCHANGE:
        NotifyWinEvent( IA2_EVENT_ACTION_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_CARETCHANGE:
        NotifyWinEvent( IA2_EVENT_TEXT_CARET_MOVED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_TEXTCHANGE:
        NotifyWinEvent( IA2_EVENT_TEXT_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_ACTIVE_DESCENDANT_CHANGED:
        UpdateAccFocus(pXAcc);
        NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_BOUNDRECT_CHANGED:
        NotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_VISIBLE_DATA_CHANGED:
        NotifyWinEvent( IA2_EVENT_VISIBLE_DATA_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_SHOW :
        NotifyWinEvent( EVENT_OBJECT_SHOW,hAcc, OBJID_CLIENT,dChildID  );
        NotifyWinEvent( EVENT_SYSTEM_FOREGROUND,hAcc, OBJID_CLIENT,dChildID  );
	break;
    case UM_EVENT_TABLE_CAPTION_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_CAPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TABLE_COLUMN_HEADER_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TABLE_MODEL_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_MODEL_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TABLE_ROW_HEADER_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_ROW_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TABLE_SUMMARY_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_SUMMARY_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TABLE_ROW_DESCRIPTION_CHANGED:
        NotifyWinEvent( IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_REORDER:
        NotifyWinEvent( EVENT_OBJECT_REORDER,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_PAGE_CHANGED:
        NotifyWinEvent( IA2_EVENT_PAGE_CHANGED,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_CHILD_REMOVED:
        NotifyWinEvent( EVENT_OBJECT_DESTROY,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_CHILD_ADDED:
        NotifyWinEvent( EVENT_OBJECT_CREATE ,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_OBJECT_PAGECHANGED:
        NotifyWinEvent( IA2_EVENT_PAGE_CHANGED ,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_TEXT_SELECTION_CHANGED:
        NotifyWinEvent( IA2_EVENT_TEXT_SELECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_SECTION_CHANGED:
        NotifyWinEvent( IA2_EVENT_SECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID  );
        break;
    case UM_EVENT_COLUMN_CHANGED:
        NotifyWinEvent( IA2_EVENT_TEXT_COLUMN_CHANGED ,hAcc, OBJID_CLIENT,dChildID  );
        break;
    default:
        break;
    }

    return sal_True;
}

/**
   * Get Parent XAccessible interface by XAccessible interface.
   * @param pXAcc XAccessible interface.
   * @return Parent XAccessible interface.
   */
XAccessible* AccObjectWinManager::GetParentXAccessible( XAccessible* pXAcc )
{
    AccObject* pObj= GetAccObjByXAcc(pXAcc);
    if( pObj ==NULL )
        return NULL;
    if(pObj->GetParentObj())
    {
        pObj = pObj->GetParentObj();
        return pObj->GetXAccessible().get();
    }
    return NULL;
}

/**
   * Get Parent role by XAccessible interface.
   * @param pXAcc XAccessible interface.
   * @return Parent role.
   */
short AccObjectWinManager::GetParentRole( XAccessible* pXAcc )
{
    AccObject* pObj= GetAccObjByXAcc(pXAcc);
    if( pObj ==NULL )
        return -1;
    if(pObj->GetParentObj())
    {
        pObj = pObj->GetParentObj();
        if(pObj->GetXAccessible().is())
        {
            XAccessible* pXAcc = pObj->GetXAccessible().get();
            Reference< XAccessibleContext > pRContext = pXAcc->getAccessibleContext();
            if(pRContext.is())
                return pRContext->getAccessibleRole();
        }
    }
    return -1;
}

/**
   * Update focus objcet by new focused XAccessible interface.
   * @param newFocus New XAccessible interface that gets focus.
   * @return 
   */
void AccObjectWinManager::UpdateAccFocus(XAccessible* newFocus)
{
    AccObject* pAccObjNew = GetAccObjByXAcc(newFocus);
    if(pAccObjNew)
    {
        AccObject* pAccObjOld = GetAccObjByXAcc(oldFocus);
        oldFocus = newFocus;
        pAccObjNew->setFocus();
        //if old == new, the pAccObjNew will be without focused state
        if (pAccObjOld && pAccObjOld != pAccObjNew)
            pAccObjOld->unsetFocus();
    }
}

/**
   * Update selected objcet by new focused XAccessible interface.
   * @param pXAcc XAccessible interface that has selected child changed.
   * @return Selected children count.
   */
int AccObjectWinManager::UpdateAccSelection(XAccessible* pXAcc)
{
    XAccessibleSelection* pSelection = NULL;
    Reference< XAccessibleContext > pRContext;

    if( pXAcc == NULL)
        return sal_False;

    pRContext = pXAcc->getAccessibleContext();
    if( !pRContext.is() )
        return sal_False;

    Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY);
    if( !pRSelection.is() )
        return sal_False;

    AccObject* pAccObj = GetAccObjByXAcc(pXAcc);
    if(pAccObj==NULL)
        return sal_False;

    Reference<XAccessible> pRChild = NULL;
    AccObject* pAccChildObj = NULL;
    int selectNum= pRSelection->getSelectedAccessibleChildCount();

    IAccSelectionList oldSelection = pAccObj->GetSelection();

    if(selectNum > 4)//for selected.
        return selectNum;
    if(selectNum == 1 && oldSelection.size() == 0)
        return 1;

    for (int i=0;i<selectNum;i++)
    {
        pRChild = pRSelection->getSelectedAccessibleChild(i);
        if(!pRChild.is())
        {
            continue;
        }
        Reference<XAccessibleContext> pRChildContext = pRChild->getAccessibleContext();
        if(!pRChildContext.is())
        {
            continue;
        }
        long index = pRChildContext->getAccessibleIndexInParent();
        IAccSelectionList::iterator temp = oldSelection.find(index);
        if ( temp != oldSelection.end() )
        {
            oldSelection.erase(index);
            continue;
        }

        pAccChildObj = NULL;
        pAccChildObj = GetAccObjByXAcc(pRChild.get());
        if(!pAccChildObj)
        {
            InsertAccObj(pRChild.get(), pXAcc,pAccObj->GetParentHWND());
            pAccChildObj = GetAccObjByXAcc(pRChild.get());
        }

        pAccObj->AddSelect(index, pAccChildObj);

        if(pAccChildObj != NULL)
            NotifyWinEvent(EVENT_OBJECT_SELECTIONADD,pAccObj->GetParentHWND(), OBJID_CLIENT,pAccChildObj->GetResID());
    }

    IAccSelectionList::iterator iter = oldSelection.begin();
    while(iter!=oldSelection.end())
    {
        pAccObj->GetSelection().erase(iter->first);
        pAccChildObj = (AccObject*)(iter->second);
        if(pAccChildObj != NULL)
            NotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE,pAccObj->GetParentHWND(), OBJID_CLIENT,pAccChildObj->GetResID());
        iter++;
    }
    return 0;

}

/**
   * Delete child element from children list.
   * @param pObj Child element that should be removed from parant child list.
   * @return 
   */
void AccObjectWinManager::DeleteAccChildNode( AccObject* pObj )
{
    AccObject *parentAccObj = pObj->GetParentObj();
    if( parentAccObj )
        parentAccObj->DeleteChild( pObj );
}

/**
   * Delete XAccessible items in top window handle hashtable
   * @param pXAcc XAccessible interface.
   * @return 
   */
void AccObjectWinManager::DeleteFromHwndXAcc(XAccessible* pXAcc )
{
    XHWNDToXAccHash::iterator iter = HwndXAcc.begin();
    while(iter!=HwndXAcc.end())
    {
        if(iter->second == pXAcc )
        {
            HwndXAcc.erase(iter);
            return;
        }
        iter++;
    }
}

/**
   * Delete Delete all children with the tree root of XAccessible pointer
   * @param pXAcc Tree root XAccessible interface.
   * @return 
   */
void AccObjectWinManager::DeleteChildrenAccObj(XAccessible* pXAcc)
{
    vos::OGuard aGuard( aDeleteMutex );
    AccObject* currentObj=NULL;
    AccObject* childObj=NULL;
    XAccessible* pTmpXAcc=NULL;

    currentObj =  GetAccObjByXAcc( pXAcc);
    if(currentObj)
    {
        childObj = currentObj->NextChild();
        while(childObj)
        {
            pTmpXAcc = GetXAccByAccObj(childObj);
            if(pTmpXAcc)
            {
                DeleteChildrenAccObj(pTmpXAcc);
                DeleteAccObj(pTmpXAcc);
            }
            childObj = currentObj->NextChild();
        }
    }
}

/**
   * Delete Delete Acc object self.
   * @param pXAcc The XAccessible interface.
   * @return 
   */
void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc )
{
    vos::OGuard aGuard( aDeleteMutex );
    if( pXAcc == NULL )
        return;
    XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc);
    if( temp != XIdAccList.end() )
    {
        ResIdGen.SetSub( temp->second.GetResID() );
    }
    else
    {
        return;
    }

    AccObject& accObj = temp->second;
    DeleteAccChildNode( &accObj );
    DeleteAccListener( &accObj );
    if( accObj.GetIMAccessible() )
    {
        accObj.GetIMAccessible()->Release();
    }
    XIdAccList.erase( pXAcc );
    XResIdAccList.erase( accObj.GetResID() );
    DeleteFromHwndXAcc(pXAcc);
}

/**
   * Delete listener that inspects some XAccessible object
   * @param pAccObj Accobject pointer.
   * @return 
   */
void AccObjectWinManager::DeleteAccListener( AccObject*  pAccObj )
{
    AccEventListener* listener = pAccObj->getListener();
    if( listener==NULL )
        return;
    listener->removeMeFromBroadcaster();
    pAccObj->SetListener(NULL);
}

/**
   * Generate a child ID, which is used for AT
   * @param 
   * @return New resource ID.
   */
inline long AccObjectWinManager::ImpleGenerateResID()
{
    return ResIdGen.GenerateNewResID();
}

/**
   * Insert all children of the current acc object
   * @param pXAcc XAccessible interface
   * @param pWnd  Top Window handle
   * @return The calling result.
   */
sal_Bool AccObjectWinManager::InsertChildrenAccObj( com::sun::star::accessibility::XAccessible* pXAcc,
        HWND pWnd)
{
    if(!IsContainer(pXAcc))
        return sal_False;

    Reference< XAccessibleContext > pRContext;

    if( pXAcc == NULL)
        return sal_False;
    pRContext = pXAcc->getAccessibleContext();
    if( !pRContext.is() )
        return sal_False;

    short role = pRContext->getAccessibleRole();

    if(com::sun::star::accessibility::AccessibleRole::DOCUMENT == role )
    {
        if(IsStateManageDescendant(pXAcc))
        {
            return sal_True;
        }
    }

    int count = pRContext->getAccessibleChildCount();
    for (int i=0;i<count;i++)
    {
        Reference<XAccessible> mxAccessible
        = pRContext->getAccessibleChild(i);
        XAccessible* mpAccessible = mxAccessible.get();
        if(mpAccessible != NULL)
        {
            InsertAccObj( mpAccessible,pXAcc,pWnd );
            InsertChildrenAccObj(mpAccessible,pWnd);
        }
    }

    return sal_True;
}

/**
   * Insert child object.
   * @param pCurObj The child object
   * @param pParentObj The parant object
   * @param pWnd Top window handle.
   * @return 
   */
void AccObjectWinManager::InsertAccChildNode( AccObject* pCurObj, AccObject* pParentObj, HWND /* pWnd */ )
{
    if(pCurObj)
    {
        if(pParentObj)
        {
            pParentObj->InsertChild(pCurObj);
        }
        else
        {
            pCurObj->UpdateValidWindow();
        }
    }
}

/**
   * Insert child object.
   * @param pCurObj The child object
   * @param pParentObj The parant object
   * @param pWnd Top window handle.
   * @return 
   */
sal_Bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentXAcc,HWND pWnd )
{
	if (!m_bBridgeRegistered)
	{
		return sal_False;
	}
    XIdToAccObjHash::iterator itXacc = XIdAccList.find( (void*)pXAcc );
    if (itXacc != XIdAccList.end() )
    {
        short nCurRole =GetRole(pXAcc);
        if (AccessibleRole::SHAPE == nCurRole)
        {
            AccObject &objXacc = itXacc->second;
            AccObject *pObjParent = objXacc.GetParentObj();
            if (pObjParent &&
                    pObjParent->GetXAccessible().is() &&
                    pObjParent->GetXAccessible().get() != pParentXAcc)
            {
                XIdToAccObjHash::iterator itXaccParent  = XIdAccList.find( (void*)pParentXAcc );
                if(itXaccParent != XIdAccList.end())
                {
                    objXacc.SetParentObj(&(itXaccParent->second));
                }
            }
        }
        return sal_False;
    }


    Reference< XAccessibleContext > pRContext;

    if( pXAcc == NULL)
        return sal_False;

    pRContext = pXAcc->getAccessibleContext();
    if( !pRContext.is() )
        return sal_False;

    if( pWnd == NULL )
    {
        if(pParentXAcc)
        {
            AccObject* pObj = GetAccObjByXAcc(pParentXAcc);
            if(pObj)
                pWnd = pObj->GetParentHWND();
        }
        if( pWnd == NULL )
            return sal_False;
    }

    AccObject pObj( pXAcc,pAgent );
    if( pObj.GetIMAccessible() == NULL )
        return sal_False;
    pObj.SetResID( this->ImpleGenerateResID());
    pObj.SetParentHWND( pWnd );

    //for file name support
    if ( pObj.GetRole() == DOCUMENT )
    {
        XHWNDToDocumentHash::iterator aIter = XHWNDDocList.find( (long)pWnd );
        if ( aIter != XHWNDDocList.end() )
        {
            XHWNDDocList.erase( aIter );
        }
        XHWNDDocList.insert( XHWNDToDocumentHash::value_type( (long)pWnd, pXAcc ) );

    }
    //end of file name

    AccEventListener* listener = createAccEventListener(pXAcc, pAgent);
    if(listener==NULL)
        return sal_False;
    Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY);
    Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY);
    if (broadcaster.is())
    {
        Reference <XAccessibleEventListener> pp (
            static_cast< XAccessibleEventListener* >(listener),UNO_QUERY );
        if(pp.is())
        {
            broadcaster->addEventListener(pp);
        }
        else
        {
            delete listener;
            return sal_False;
        }
    }
    else
        return sal_False;

    XIdAccList.insert( XIdToAccObjHash::value_type( (void*)pXAcc, pObj ));
    XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( (void*)pXAcc );
    XResIdAccList.insert(XResIdToAccObjHash::value_type(pObj.GetResID(),&(pIndTemp->second)));

    AccObject* pCurObj = GetAccObjByXAcc(pXAcc);
    if( pCurObj )
    {
        pCurObj->SetListener( listener );
        if(listener != NULL)
            listener->acquire();
    }

    AccObject* pParentObj = GetAccObjByXAcc(pParentXAcc);
    InsertAccChildNode(pCurObj,pParentObj,pWnd);
    if( pCurObj )
        pCurObj->UpdateAccessibleInfoFromUnoToMSAA();
    return sal_True;
}


/**
   * save the pair <topwindowhandle, XAccessible>
   * @param hWnd, top window handle
   * @param pXAcc XAccessible interface for top window
   * @return void
   */
void AccObjectWinManager::SaveTopWindowHandle(HWND hWnd, com::sun::star::accessibility::XAccessible* pXAcc)
{
    HwndXAcc.insert( XHWNDToXAccHash::value_type( hWnd,(void*)pXAcc ) );
}


/**
   * create the corresponding listener.
   * @param pXAcc XAccessible interface.
   * @param Agent The agent kept in all listeners,it's the sole interface by which
   *        listener communicate with windows manager.
   * @return 
   */
AccEventListener* AccObjectWinManager::createAccEventListener(XAccessible* pXAcc, AccObjectManagerAgent* /* Agent */ )
{
    AccEventListener* listener = NULL;
    Reference<XAccessibleContext> xContext(pXAcc->getAccessibleContext(),UNO_QUERY);
    if(xContext.is())
    {
        switch( xContext->getAccessibleRole() )
        {
        case /*AccessibleRole::*/DIALOG:
            listener = new AccDialogEventListener(pXAcc,pAgent);
            break;
        case /*AccessibleRole::*/FRAME:
            listener = new AccFrameEventListener(pXAcc,pAgent);
            break;
        case /*AccessibleRole::*/WINDOW:
            listener = new AccWindowEventListener(pXAcc,pAgent);
            break;
        case /*AccessibleRole::*/ROOT_PANE:
            listener = new AccFrameEventListener(pXAcc,pAgent);
            break;
            //Container
        case /*AccessibleRole::*/CANVAS:
        case /*AccessibleRole::*/COMBO_BOX:
        case /*AccessibleRole::*/DOCUMENT:
        case /*AccessibleRole::*/END_NOTE:
        case /*AccessibleRole::*/FILLER:
        case /*AccessibleRole::*/FOOTNOTE:
        case /*AccessibleRole::*/FOOTER:
        case /*AccessibleRole::*/HEADER:
        case /*AccessibleRole::*/LAYERED_PANE:
        case /*AccessibleRole::*/MENU_BAR:
        case /*AccessibleRole::*/POPUP_MENU:
        case /*AccessibleRole::*/OPTION_PANE:
        case /*AccessibleRole::*/PAGE_TAB:
        case /*AccessibleRole::*/PAGE_TAB_LIST:
        case /*AccessibleRole::*/PANEL:
        case /*AccessibleRole::*/SCROLL_PANE:
        case /*AccessibleRole::*/SPLIT_PANE:
        case /*AccessibleRole::*/STATUS_BAR:
        case /*AccessibleRole::*/TABLE_CELL:
        case /*AccessibleRole::*/TOOL_BAR:
        case /*AccessibleRole::*/VIEW_PORT:
            listener = new AccContainerEventListener(pXAcc,pAgent);
            break;
        case /*AccessibleRole::*/PARAGRAPH:
        case /*AccessibleRole::*/HEADING:
            listener = new AccParagraphEventListener(pXAcc,pAgent);
            break;
            //Component
        case /*AccessibleRole::*/CHECK_BOX:
        case /*AccessibleRole::*/ICON:
        case /*AccessibleRole::*/LABEL:
        case /*AccessibleRole::*/MENU_ITEM:
        case /*AccessibleRole::*/CHECK_MENU_ITEM:
        case /*AccessibleRole::*/RADIO_MENU_ITEM:
        case /*AccessibleRole::*/PUSH_BUTTON:
        case /*AccessibleRole::*/RADIO_BUTTON:
        case /*AccessibleRole::*/SCROLL_BAR:
        case /*AccessibleRole::*/SEPARATOR:
        case /*AccessibleRole::*/TOGGLE_BUTTON:
        case /*AccessibleRole::*/BUTTON_DROPDOWN:
        case /*AccessibleRole::*/TOOL_TIP:
        case /*AccessibleRole::*/SPIN_BOX:
        case DATE_EDITOR:
            listener = new AccComponentEventListener(pXAcc,pAgent);
            break;
            //text component
        case /*AccessibleRole::*/TEXT:
            listener = new AccTextComponentEventListener(pXAcc,pAgent);
            break;
            //menu
        case /*AccessibleRole::*/MENU:
            listener = new AccMenuEventListener(pXAcc,pAgent);
            break;
            //object container
        case /*AccessibleRole::*/SHAPE:

        case /*AccessibleRole::*/EMBEDDED_OBJECT:
        case /*AccessibleRole::*/GRAPHIC:
        case /*AccessibleRole::*/TEXT_FRAME:
            listener = new AccObjectContainerEventListener(pXAcc,pAgent);
            break;
            //descendmanager
        case /*AccessibleRole::*/LIST:
            listener = new AccListEventListener(pXAcc,pAgent);
            break;
        case /*AccessibleRole::*/TREE:
            listener = new AccTreeEventListener(pXAcc,pAgent);
            break;
            //special
        case /*AccessibleRole::*/COLUMN_HEADER:
        case /*AccessibleRole::*/TABLE:
            listener = new AccTableEventListener(pXAcc,pAgent);
            break;
        default:
            listener = new AccContainerEventListener(pXAcc,pAgent);
            break;
        }
    }

    return listener;
}

/**
   * state is a combination integer, each bit of which represents a single state,
   * such as focused,1 for the state on,0 for the state off. Here call COM interface
   * to modify the state value, including DecreaseState.
   * @param pXAcc XAccessible interface.
   * @param pState Changed state.
   * @return 
   */
void AccObjectWinManager::DecreaseState( XAccessible* pXAcc,unsigned short pState )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->DecreaseState( pState );
}

/**
   * state is a combination integer, each bit of which represents a single state,such as focused,1 for
   * the state on,0 for the state off. Here call COM interface to modify the state value, including 
   * IncreaseState.
   * @param pXAcc XAccessible interface.
   * @param pState Changed state.
   * @return 
   */
void AccObjectWinManager::IncreaseState( XAccessible* pXAcc,unsigned short pState )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->IncreaseState( pState );
}

void  AccObjectWinManager::UpdateState( com::sun::star::accessibility::XAccessible* pXAcc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->UpdateState( );
}

/**
   * Set corresponding com object's accessible name via XAccessilbe interface and new
   * name
   * @param pXAcc XAccessible interface.
   * @return 
   */
void  AccObjectWinManager::UpdateAccName( XAccessible* pXAcc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->UpdateName();
}

void  AccObjectWinManager::UpdateAction( XAccessible* pXAcc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->UpdateAction();
}

void AccObjectWinManager::UpdateDescription( XAccessible* pXAcc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if ( pAccObj )
        pAccObj->UpdateDescription();
}

/**
   * Set corresponding com object's accessible location via XAccessilbe interface and new
   * location.
   * @param pXAcc XAccessible interface.
   * @return 
   */
void  AccObjectWinManager::SetLocation( XAccessible* pXAcc, long /*top*/, long /*left*/, long /*width*/, long /*height*/ )
{
    AccObject* pObj = GetAccObjByXAcc( pXAcc );
    //get the location from XComponent.
    Reference< XAccessibleContext > pRContext = pXAcc->getAccessibleContext();
    if( pObj )
        pObj->UpdateLocation();
}

/**
   * Set corresponding com object's value  via XAccessilbe interface and new value.
   * @param pXAcc XAccessible interface.
   * @param pAny new value.
   * @return 
   */
void  AccObjectWinManager::SetValue( XAccessible* pXAcc, Any pAny )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->SetValue( pAny );
}

/**
   * Set corresponding com object's value  via XAccessilbe interface.
   * @param pXAcc XAccessible interface.
   * @return 
   */
void  AccObjectWinManager::UpdateValue( XAccessible* pXAcc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->UpdateValue();
}

/**
   * Set corresponding com object's name via XAccessilbe interface and new name.
   * @param pXAcc XAccessible interface.
   * @param newName new name
   * @return 
   */
void  AccObjectWinManager::SetAccName( XAccessible* pXAcc, Any newName)
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->SetName( newName );
}

/**
   * Set corresponding com object's description via XAccessilbe interface and new description.
   * @param pXAcc XAccessible interface.
   * @param newDesc new description
   * @return 
   */
void  AccObjectWinManager::SetDescription( XAccessible* pXAcc, Any newDesc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->SetDescription( newDesc );
}

/**
   * Set corresponding com object's role via XAccessilbe interface and new role.
   * @param pXAcc XAccessible interface.
   * @param Role new role
   * @return 
   */
void  AccObjectWinManager::SetRole( XAccessible* pXAcc, long Role )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if( pAccObj )
        pAccObj->SetRole( (short)Role );
}

/**
   * Judge if a XAccessible object is a container object.
   * @param pAccessible XAccessible interface.
   * @return If XAccessible object is container.
   */
sal_Bool AccObjectWinManager::IsContainer(XAccessible* pAccessible)
{
    try
    {
        if(pAccessible)
        {
            Reference<XAccessibleContext> xContext(pAccessible->getAccessibleContext(),UNO_QUERY);
            if(xContext.is())
            {
                switch( xContext->getAccessibleRole() )
                {
                case /*AccessibleRole::*/DIALOG:
                case /*AccessibleRole::*/FRAME:
                case /*AccessibleRole::*/WINDOW:
                case /*AccessibleRole::*/ROOT_PANE:
                case /*AccessibleRole::*/CANVAS:
                case /*AccessibleRole::*/COMBO_BOX:
                case /*AccessibleRole::*/DOCUMENT:
                case /*AccessibleRole::*/EMBEDDED_OBJECT:
                case /*AccessibleRole::*/END_NOTE:
                case /*AccessibleRole::*/FILLER:
                case /*AccessibleRole::*/FOOTNOTE:
                case /*AccessibleRole::*/FOOTER:
                case /*AccessibleRole::*/GRAPHIC:
                case /*AccessibleRole::*/GROUP_BOX:
                case /*AccessibleRole::*/HEADER:
                case /*AccessibleRole::*/LAYERED_PANE:
                case /*AccessibleRole::*/MENU_BAR:
                case /*AccessibleRole::*/POPUP_MENU:
                case /*AccessibleRole::*/OPTION_PANE:
                case /*AccessibleRole::*/PAGE_TAB:
                case /*AccessibleRole::*/PAGE_TAB_LIST:
                case /*AccessibleRole::*/PANEL:
                case /*AccessibleRole::*/SCROLL_PANE:
                case /*AccessibleRole::*/SPLIT_PANE:
                case /*AccessibleRole::*/STATUS_BAR:
                case /*AccessibleRole::*/TABLE_CELL:
                case /*AccessibleRole::*/TEXT_FRAME:
                case /*AccessibleRole::*/TOOL_BAR:
                case /*AccessibleRole::*/VIEW_PORT:
                case /*AccessibleRole::*/SHAPE:
                    return sal_True;
                    break;
                case /*AccessibleRole::*/COLUMN_HEADER:
                case /*AccessibleRole::*/TABLE:
                    if(!IsStateManageDescendant(pAccessible))
                        return sal_True;
                    break;
                case /*AccessibleRole::*/MENU:
                    return sal_True;
                    break;
                default:
                    return sal_False;
                }
            }
        }
    }
    catch(...)
    {
        return sal_False;
    }
    return sal_False;
}

/**
   * Judge if a XAccessible object has ManageDescendant event.
   * @param pAccessible XAccessible interface.
   * @return If XAccessible object is managedescendant.
   */
bool AccObjectWinManager::IsStateManageDescendant(XAccessible* pAccessible)
{
    if(pAccessible)
    {
        Reference<XAccessibleContext> xContext(pAccessible->getAccessibleContext(),UNO_QUERY);
        if(xContext.is())
        {
            Reference< XAccessibleStateSet > pRState = xContext->getAccessibleStateSet();
            if( !pRState.is() )
                return sal_False;

            Sequence<short> pStates = pRState->getStates();
            int count = pStates.getLength();
            for( int iIndex = 0;iIndex < count;iIndex++ )
            {
                if(pStates[iIndex] == /*AccessibleStateType::*/MANAGES_DESCENDANTS)
                    return sal_True;
            }
        }
    }
    return sal_False;
}

/**
   * Query and get IAccessible interface by XAccessible interface from list.
   * @param pXAcc XAccessible interface.
   * @return Com accobject interface.
   */
IMAccessible* AccObjectWinManager::GetIMAccByXAcc(XAccessible* pXAcc)
{
    AccObject* pAccObj = GetAccObjByXAcc(pXAcc);
    if(pAccObj)
    {
        return pAccObj->GetIMAccessible();
    }
    else
    {
        return NULL;
    }
}

/**
   * Query and get IAccessible interface by child id from list.
   * @param resID, childID.
   * @return Com accobject interface.
   */
IMAccessible * AccObjectWinManager::GetIAccessibleFromResID(long resID)
{
    XResIdToAccObjHash::iterator pIndTemp = XResIdAccList.find( resID );
    if ( pIndTemp == XResIdAccList.end() )
        return NULL;

    AccObject* pObj = pIndTemp->second;

    if(pObj->GetIMAccessible())
        return pObj->GetIMAccessible();
    return NULL;
}
/**
   * Notify some object will be destroyed.
   * @param pXAcc XAccessible interface.
   * @return Com accobject interface.
   */
void AccObjectWinManager::NotifyDestroy(XAccessible* pXAcc)
{
    AccObject* accObj = GetAccObjByXAcc(pXAcc);
    if(accObj)
    {
        accObj->NotifyDestroy(sal_True);
    }
}


void AccObjectWinManager::UpdateChildState(com::sun::star::accessibility::XAccessible* pAccSubMenu)
{
    Reference<com::sun::star::accessibility::XAccessibleContext> xContext(pAccSubMenu,UNO_QUERY);
    if (!xContext.is())
    {
        return;
    }
    sal_Int32 nCount = xContext->getAccessibleChildCount();
    for (sal_Int32 i = 0 ; i < nCount ; ++i)
    {
        Reference<com::sun::star::accessibility::XAccessible> xChild = xContext->getAccessibleChild(i);
        if (xChild.is())
        {
            AccObject *pObj =  GetAccObjByXAcc(xChild.get());
            if (pObj)
            {
                pObj->UpdateState();
            }
        }
    }
}


bool AccObjectWinManager::IsSpecialToolboItem(com::sun::star::accessibility::XAccessible* pXAcc)
{
    if (pXAcc && oldFocus != pXAcc)
    {
        if(GetParentRole(pXAcc) == TOOL_BAR)
        {
            Reference< XAccessibleContext > pRContext(pXAcc->getAccessibleContext());
            if (pRContext.is())
            {
                if(pRContext->getAccessibleRole() == TOGGLE_BUTTON)
                {
                    return true;
                }
            }
        }
    }
    return false;
}

short AccObjectWinManager::GetRole(com::sun::star::accessibility::XAccessible* pXAcc)
{
    assert(pXAcc != NULL);
    Reference<com::sun::star::accessibility::XAccessibleContext> xContext(pXAcc->getAccessibleContext(),UNO_QUERY);
    if(xContext.is())
    {
        return xContext->getAccessibleRole();
    }
    return -1;
}

XAccessible* AccObjectWinManager::GetAccDocByHWND( long pWnd )
{
    XHWNDToDocumentHash::iterator aIter;
    aIter = XHWNDDocList.find( pWnd );
    if ( aIter != XHWNDDocList.end() )
    {
        return aIter->second;
    }

    return NULL;
}

XAccessible* AccObjectWinManager::GetAccDocByAccTopWin( XAccessible* pXAcc )
{
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    long pWnd = (long)( pAccObj->GetParentHWND() );
    return GetAccDocByHWND( pWnd );
}

bool AccObjectWinManager::IsTopWinAcc( com::sun::star::accessibility::XAccessible* pXAcc )
{
    bool bRet = false;
    AccObject* pAccObj = GetAccObjByXAcc( pXAcc );
    if ( pAccObj )
    {
        bRet = ( pAccObj->GetParentObj() == NULL );
    }
    return bRet;
}