/**************************************************************
* 
* 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 "stdafx.h"
#include "UAccCOM2.h"
#include "MAccessible.h"

#include <algorithm>
#include "AccAction.h"

#include <com/sun/star/accessibility/XAccessibleText.hpp>
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
#include <com/sun/star/accessibility/XAccessibleImage.hpp>
#include <com/sun/star/accessibility/XAccessibleTable.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
#include <com/sun/star/accessibility/XAccessibleAction.hpp>
#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
#include <com/sun/star/accessibility/XAccessibleHyperText.hpp>
#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp>
#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/XAccessibleGroupPosition.hpp>
#include <com/sun/star/accessibility/XAccessibleValue.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
#include <com/sun/star/style/LineSpacing.hpp>
#include <com/sun/star/style/TabStop.hpp>
#include <com/sun/star/container/XIndexReplace.hpp>

#include "act.hxx"

using namespace com::sun::star::accessibility::AccessibleStateType;

// IA2 states mapping, and name
// maintenance the consistency, change one array, change the three all
long IA2_STATES[] =
{
	IA2_STATE_ACTIVE,					// =					0x1;
	IA2_STATE_ARMED,					// =					0x2;
	IA2_STATE_DEFUNCT,					// =					0x4;
	IA2_STATE_EDITABLE,					// =					0x8;
	IA2_STATE_HORIZONTAL,				// =					0x10;
	IA2_STATE_ICONIFIED,				// =					0x20;
	IA2_STATE_INVALID_ENTRY,			// =					0x80;
	IA2_STATE_MANAGES_DESCENDANTS,		// =					0x100;
	IA2_STATE_MODAL,					// =					0x200;
	IA2_STATE_MULTI_LINE,				// =					0x400;
	IA2_STATE_OPAQUE,					// =					0x800;
	IA2_STATE_REQUIRED,					// =					0x2000;
	IA2_STATE_SELECTABLE_TEXT,			// =					0x3000;
	IA2_STATE_SINGLE_LINE,				// =					0x4000;
	IA2_STATE_STALE,					// =					0x8000;
	IA2_STATE_SUPPORTS_AUTOCOMPLETION,	// =					0x10000;
	IA2_STATE_TRANSIENT,				//=						0x20000;
	IA2_STATE_VERTICAL					// =					0x40000;
};
/*

<=== map ===>  

*/
short UNO_STATES[] =
{
	ACTIVE,			// = (sal_Int16)1;
	ARMED,			// = (sal_Int16)2;
	DEFUNC,			// = (sal_Int16)5;
	EDITABLE,		// = (sal_Int16)6;
	HORIZONTAL,		// = (sal_Int16)12;
	ICONIFIED,		// = (sal_Int16)13;
	-1,				//IA2_STATE_INVALID_ENTRY
	MANAGES_DESCENDANTS, // = (sal_Int16)15;
	MODAL,			// = (sal_Int16)16;
	MULTI_LINE,		// = (sal_Int16)17;
	OPAQUE,			// = (sal_Int16)19;
	-1,				//IA2_STATE_REQUIRED
	-1,				//IA2_STATE_SELECTABLE_TEXT
	SINGLE_LINE,	// = (sal_Int16)26;
	STALE,			// = (sal_Int16)27;
	-1,				//IA2_STATE_SUPPORTS_AUTOCOMPLETION
	TRANSIENT,		//IA2_STATE_TRANSIENT
	VERTICAL		// = (sal_Int16)29;
};

//  <=== map ===>

BSTR IA2_STATES_NAME[] =
{
	_T("Active"),
	_T("Armed"),
	_T("Defunct"),
	_T("Editable"),
	_T("Horizontal"),
	_T("Iconified"),
	_T("Invalid Entry"),
	_T("Manages Decendents"),
	_T("Modal"),
	_T("Multi Line"),
	_T("Opaque"),
	_T("Required"),
	_T("Selectable Text"),
	_T("Single Line"),
	_T("Stale"),
	_T("Supports Autocompletion"),
	_T("Transient"),
	_T("Vertical")
};

// IA2 states mapping, and name
// maintenance the consistency. change one, change them all

BSTR UNO_ALL_STATES[] =
{
	_T("INVALID"),			// 	INVALID	( 0 )
	_T("ACTIVE"),			// 	ACTIVE	( 1 )
	_T("ARMED"),			// 	ARMED	( 2 )
	_T("BUSY"),				// 	BUSY	( 3 )
	_T("CHECKED"),			// 	CHECKED	( 4 )
	_T("DEFUNC"),			// 	DEFUNC	( 5 )
	_T("EDITABLE"),			// 	EDITABLE	( 6 )
	_T("ENABLED"),			// 	ENABLED	( 7 )
	_T("EXPANDABLE"),		// 	EXPANDABLE	( 8 )
	_T("EXPANDED"),			// 	EXPANDED	( 9 )
	_T("FOCUSABLE"),		// 	FOCUSABLE	( 10 )
	_T("FOCUSED"),			// 	FOCUSED	( 11 )
	_T("HORIZONTAL"),		// 	HORIZONTAL	( 12 )
	_T("ICONIFIED"),		// 	ICONIFIED	( 13 )
	_T("INDETERMINATE"),	// 	INDETERMINATE	( 14 )
	_T("MANAGES_DESCENDANTS"),// 	MANAGES_DESCENDANTS	( 15 )
	_T("MODAL"),			// 	MODAL	( 16 )
	_T("MULTI_LINE"),		// 	MULTI_LINE	( 17 )
	_T("MULTI_SELECTABLE"),	// 	MULTI_SELECTABLE	( 18 )
	_T("OPAQUE"),			// 	OPAQUE	( 19 )
	_T("PRESSED"),			// 	PRESSED	( 20 )
	_T("RESIZABLE"),		// 	RESIZABLE	( 21 )
	_T("SELECTABLE"),		// 	SELECTABLE	( 22 )
	_T("SELECTED"),			// 	SELECTED	( 23 )
	_T("SENSITIVE"),		// 	SENSITIVE	( 24 )
	_T("SHOWING"),			// 	SHOWING	( 25 )
	_T("SINGLE_LINE"),		// 	SINGLE_LINE	( 26 )
	_T("STALE"),			// 	STALE	( 27 )
	_T("TRANSIENT"),		// 	TRANSIENT	( 28 )
	_T("VERTICAL"),			// 	VERTICAL	( 29 )
	_T("VISIBLE"),			// 	VISIBLE	( 30 )
	_T("MOVEABLE"),			//  MOVEABLE ( 31 )
	_T("OFFSCREEN"),		//  OFFSCREEN ( 32 )
	_T("COLLAPSE"),			//  COLLAPSE ( 33 )
	_T("DEFAULT")			//  DEFAULT ( 34 )
};


using namespace com::sun::star::accessibility::AccessibleRole;



#define QUERYXINTERFACE(ainterface)	\
{							\
	if(pXAcc == NULL)		\
	return FALSE;		\
	pRContext = pXAcc->getAccessibleContext();	\
	if( !pRContext.is() )	\
{						\
	return FALSE;		\
}						\
	Reference<X##ainterface> pRXI(pRContext,UNO_QUERY);\
	if( !pRXI.is() )		\
{						\
	return FALSE;		\
}						\
	*ppXI = (XInterface*)pRXI.get();		\
	return TRUE;			\
}

#define ISDESTROY()	\
	if(m_isDestroy)	\
	return S_FALSE;


AccObjectManagerAgent* CMAccessible::g_pAgent = NULL;

CMAccessible::CMAccessible():
m_iRole(0x00),
m_dState(0x00),
m_dChildID(0x00),
m_dFocusChildID(UACC_NO_FOCUS),
m_hwnd(NULL),
m_pIParent(NULL),
m_pszName(NULL),
m_pszValue(NULL),
m_pszDescription(NULL),
m_isDestroy(FALSE),
m_pszActionDescription(NULL),
m_pXAction(NULL),
m_bRequiresSave(FALSE),
pUNOInterface(NULL)
{
	m_sLocation.m_dLeft=0;
	m_sLocation.m_dTop = 0;
	m_sLocation.m_dWidth=0;
	m_sLocation.m_dHeight=0;
	CEnumVariant::Create(&m_pEnumVar);
	m_containedObjects.clear();
}

CMAccessible::~CMAccessible()
{
	if(m_pszName!=NULL)
	{
		SAFE_SYSFREESTRING(m_pszName);
		m_pszName=NULL;
	}
	if(m_pszValue!=NULL)
	{
		SAFE_SYSFREESTRING(m_pszValue);
		m_pszValue=NULL;
	}
	if(m_pszDescription!=NULL)
	{
		SAFE_SYSFREESTRING(m_pszDescription);
		m_pszDescription=NULL;
	}

	if(m_pszActionDescription!=NULL)
	{
		SAFE_SYSFREESTRING(m_pszActionDescription);
		m_pszActionDescription=NULL;
	}

	if(m_pIParent)
	{
		m_pIParent->Release();
		m_pIParent=NULL;
	}
	pRef = NULL;
	m_pEnumVar->Release();
	m_containedObjects.clear();
	pRContext = NULL;
}

/**
* Returns the Parent IAccessible interface pointer to AT. 
* It should add reference, and the client should release the component.
* It should return E_FAIL when the parent point is null.
* @param	ppdispParent [in,out] used to return the parent interface point.
*			when the point is null, should return null.
* @return   S_OK if successful and E_FAIL if the m_pIParent is NULL.
*/
STDMETHODIMP CMAccessible::get_accParent(IDispatch **ppdispParent)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(ppdispParent == NULL)
		{
			return E_INVALIDARG;
		}

		if(m_pIParent)
		{
			*ppdispParent = m_pIParent;
			(*ppdispParent)->AddRef();
			return S_OK;
		}
		else if(m_hwnd)
		{
			HRESULT hr = AccessibleObjectFromWindow(m_hwnd, OBJID_WINDOW, IID_IAccessible, (void**)ppdispParent);
			if( ! SUCCEEDED( hr ) || ! ppdispParent )
			{
				return S_FALSE;
			}
			return S_OK;
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns child count of current COM object. 
* @param	pcountChildren [in,out] used to return the children count.
* @return   S_OK if successful.
*/
STDMETHODIMP CMAccessible::get_accChildCount(long *pcountChildren)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pcountChildren == NULL)
		{
			return E_INVALIDARG;
		}

		if(!pUNOInterface)
			return S_FALSE;

		Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
		if( pRContext.is() )
		{
			*pcountChildren = pRContext->getAccessibleChildCount();
		}

		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns child interface pointer for AT according to input child ID. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	ppdispChild, [in,out] use to return the child interface point.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(ppdispChild == NULL)
		{
			return E_INVALIDARG;
		}
		if(varChild.vt==VT_I4)
		{
			//get child interface pointer due to child ID
			if(varChild.lVal==CHILDID_SELF)
			{
				AddRef();
				*ppdispChild = this;
				return S_OK;
			}
			*ppdispChild = GetChildInterface(varChild.lVal);
			(*ppdispChild)->AddRef();
			return (*ppdispChild)?S_OK:S_FALSE;
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible name of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszName, [in,out] use to return the name of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accName(VARIANT varChild, BSTR *pszName)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pszName == NULL)
		{
			return E_INVALIDARG;
		}
		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal==CHILDID_SELF)
			{
				SAFE_SYSFREESTRING(*pszName);
				*pszName = SysAllocString(m_pszName);
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->get_accName(varChild,pszName);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible value of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszValue, [in,out] use to return the value of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accValue(VARIANT varChild, BSTR *pszValue)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if( pszValue == NULL )
		{
			return E_INVALIDARG;
		}
		if( varChild.vt==VT_I4 )
		{
			if(varChild.lVal==CHILDID_SELF)
			{
				if(m_dState & STATE_SYSTEM_PROTECTED)
					return E_ACCESSDENIED;

				if ( m_pszValue !=NULL && wcslen(m_pszValue) == 0 )
					return S_OK;

				SAFE_SYSFREESTRING(*pszValue);
				*pszValue = SysAllocString(m_pszValue);
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->get_accValue(varChild,pszValue);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible description of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszDescription, [in,out] use to return the description of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accDescription(VARIANT varChild, BSTR *pszDescription)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pszDescription == NULL)
		{
			return E_INVALIDARG;
		}
		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal==CHILDID_SELF)
			{
				SAFE_SYSFREESTRING(*pszDescription);
				*pszDescription = SysAllocString(m_pszDescription);
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->get_accDescription(varChild,pszDescription);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible role of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pvarRole, [in,out] use to return the role of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarRole == NULL)
		{
			return E_INVALIDARG;
		}
		if(varChild.vt == VT_I4)
		{

			if(varChild.lVal == CHILDID_SELF)
			{
				if( m_iRole < IA2_ROLE_CAPTION )
				{
					VariantInit(pvarRole);
					pvarRole->vt = VT_I4;
					pvarRole->lVal = m_iRole;
				}
				else
				{
					VariantInit(pvarRole);
					pvarRole->vt = VT_I4;
					pvarRole->lVal = ROLE_SYSTEM_CLIENT;
				}
				return S_OK;
			}


			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->get_accRole(varChild,pvarRole);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible state of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pvarState, [in,out] use to return the state of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accState(VARIANT varChild, VARIANT *pvarState)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarState == NULL)
		{
			return E_INVALIDARG;
		}
		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal == CHILDID_SELF)
			{
				if(pUNOInterface)
				{
					Reference< XAccessibleContext > pContext = pUNOInterface->getAccessibleContext();
					if(pContext.is())
					{
						// add the STATE_SYSTEM_LINKED state
						Reference< XAccessibleHypertext > pRHypertext(pContext,UNO_QUERY);
						if(pRHypertext.is())
						{
							if( pRHypertext->getHyperLinkCount() > 0 )
								m_dState |= STATE_SYSTEM_LINKED;
							else
								m_dState &= ~STATE_SYSTEM_LINKED;
						}
						else
							m_dState &= ~STATE_SYSTEM_LINKED;
					}
				}

				VariantInit(pvarState);
				pvarState->vt = VT_I4;
				pvarState->lVal = m_dState;
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->get_accState(varChild,pvarState);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible helpString of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszHelp, [in,out] use to return the helpString of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accHelp(VARIANT, BSTR *)
{
	return E_NOTIMPL;
}

/**
* Returns the accessible HelpTopic of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszHelpFile, [in,out] use to return the HelpTopic of the proper object.
* @param	pidTopic, use to return the HelpTopic ID of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
* Not implemented yet
*/
STDMETHODIMP CMAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
{
	return E_NOTIMPL;
}

static void GetMnemonicChar( const ::rtl::OUString& aStr, WCHAR* wStr)
{
	int  nLen    = aStr.pData->length;
	int  i       = 0;
	WCHAR* text = aStr.pData->buffer;

	while ( i < nLen )
	{
		if ( text[i] == L'~' )
			if ( text[i+1] != L'~' )
			{
				wStr[0] = text[i+1];
				break;
			}
			i++;
	}
}

/**
* Returns the accessible keyboard shortcut of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszKeyboardShortcut, [in,out] use to return the kbshortcut of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK

		ISDESTROY()
		// #CHECK#
		if(pszKeyboardShortcut == NULL)
		{
			return E_INVALIDARG;
		}

		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal == CHILDID_SELF)
			{
				if( pUNOInterface )
				{
					Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
					if( !pRContext.is() )
						return S_FALSE;

					Reference<XAccessibleAction> pRXI(pRContext,UNO_QUERY);

					OLECHAR wString[64]={0};

					if( pRXI.is() && pRXI->getAccessibleActionCount() >= 1)
					{
						Reference< XAccessibleKeyBinding > binding = pRXI->getAccessibleActionKeyBinding(0);
						if( binding.is() )
						{
							long nCount = binding->getAccessibleKeyBindingCount();
							if(nCount >= 1)
							{
								CAccAction::GetkeyBindingStrByXkeyBinding( binding->getAccessibleKeyBinding(0),wString );
							}
						}
					}
					if(wString[0] == 0)
					{
						Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
						if(!pRrelationSet.is())
						{
							return S_FALSE;
						}

						long nRelCount = pRrelationSet->getRelationCount();

						// Modified by Steve Yin, for SODC_1552
						if( /*nRelCount <= 0 &&*/ m_iRole == ROLE_SYSTEM_TEXT )
						{
							VARIANT varParentRole;
							VariantInit( &varParentRole );

							m_pIParent->get_accRole(varChild, &varParentRole);

							if( m_pIParent && varParentRole.lVal == ROLE_SYSTEM_COMBOBOX ) // edit in comoboBox
							{
								m_pIParent->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
								return S_OK;
							}
						}

						AccessibleRelation *paccRelation = NULL;
						AccessibleRelation accRelation;
						for(int i=0; i<nRelCount ; i++)
						{
							if( pRrelationSet->getRelation(i).RelationType == 6 )
							{
								accRelation = pRrelationSet->getRelation(i);
								paccRelation = &accRelation;
							}
						}

						if(paccRelation == NULL)
							return S_FALSE;

						Sequence< Reference< XInterface > > xTargets = paccRelation->TargetSet;
						Reference<XInterface> pRAcc = xTargets[0];

						XAccessible* pXAcc = (XAccessible*)pRAcc.get();

						Reference<XAccessibleContext> pRLebelContext = pXAcc->getAccessibleContext();
						if(!pRLebelContext.is())
							return S_FALSE;

						pRrelationSet = pRLebelContext->getAccessibleRelationSet();
						nRelCount = pRrelationSet->getRelationCount();

						paccRelation = NULL;
						for(int j=0; j<nRelCount ; j++)
						{
							if( pRrelationSet->getRelation(j).RelationType == 5 )
							{
								accRelation = pRrelationSet->getRelation(j);
								paccRelation = &accRelation;
							}
						}

						if(paccRelation)
						{
							xTargets = paccRelation->TargetSet;
							pRAcc = xTargets[0];
							if(pUNOInterface != (XAccessible*)pRAcc.get())
								return S_FALSE;
						}

						Reference<XAccessibleExtendedComponent> pRXIE(pRLebelContext,UNO_QUERY);
						if(!pRXIE.is())
							return S_FALSE;

						::rtl::OUString ouStr = pRXIE->getTitledBorderText();
						WCHAR key[2] = {NULL};
						GetMnemonicChar(ouStr, key);
						if(key[0] != 0)
						{
							wcscat(wString, L"Alt+");
							wcscat(wString, key);
						}
						else
							return S_FALSE;
					}

					SAFE_SYSFREESTRING(*pszKeyboardShortcut);
					*pszKeyboardShortcut = SysAllocString(wString);

					return S_OK;
				}
				else
				{
					return S_FALSE;
				}
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;

			return pChild->get_accKeyboardShortcut(varChild,pszKeyboardShortcut);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the current focused child to AT. 
* @param	pvarChild, [in,out] vt member of pvarChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accFocus(VARIANT *pvarChild)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarChild == NULL)
		{
			return E_INVALIDARG;
		}
		if( m_dFocusChildID==UACC_NO_FOCUS )
		{
			pvarChild->vt = VT_EMPTY;//no focus on the object and its children
			return S_OK;
		}
		//if the descendant of current object has focus indicated by m_dFocusChildID, return the IDispatch of this focused object
		else
		{
			IMAccessible* pIMAcc = NULL;
			g_pAgent->GetIAccessibleFromResID(m_dFocusChildID,&pIMAcc);
			pIMAcc->AddRef();
			pvarChild->vt = VT_DISPATCH;
			pvarChild->pdispVal = pIMAcc;

		}
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the selection of the current COM object to AT. 
* @param	pvarChildren,[in,out]
* if selection num is 0,return VT_EMPTY for vt,
* if selection num is 1,return VT_I4 for vt,and child index for lVal
* if selection num >1,return VT_UNKNOWN for vt, and IEnumVariant* for punkVal
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accSelection(VARIANT *pvarChildren)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarChildren == NULL)
		{
			return E_INVALIDARG;
		}
		switch(m_pEnumVar->GetCountOfElements())
		{
		case 0:
			pvarChildren->vt = VT_EMPTY;
			break;
		case 1:
			VARIANT varTmp[1];
			ULONG count;
			VariantInit(&varTmp[0]);
			m_pEnumVar->Next(1,varTmp,&count);
			if(count!=1)
				return S_FALSE;
			pvarChildren->vt = VT_I4;
			pvarChildren->lVal = varTmp[0].lVal;
			VariantClear(&varTmp[0]);
			m_pEnumVar->Reset();
			break;
		default:
			pvarChildren->vt = VT_UNKNOWN;
			m_pEnumVar->AddRef();
			pvarChildren->punkVal = m_pEnumVar;
			break;
		}
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the location of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pxLeft, [in,out] use to return the x-coordination of the proper object.
* @param	pyTop,  [in,out] use to return the y-coordination of the proper object.
* @param	pcxWidth, [in,out] use to return the x-coordination width of the proper object.
* @param	pcyHeight, [in,out] use to return the y-coordination height of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pxLeft == NULL || pyTop == NULL || pcxWidth == NULL || pcyHeight == NULL)
		{
			return E_INVALIDARG;
		}

		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal==CHILDID_SELF)
			{

				if(pUNOInterface)
				{
					Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
					if( !pRContext.is() )
						return S_FALSE;
					Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY);
					if( !pRComponent.is() )
						return S_FALSE;

					::com::sun::star::awt::Point pCPoint = pRComponent->getLocationOnScreen();
					::com::sun::star::awt::Size pCSize = pRComponent->getSize();
					*pxLeft = pCPoint.X;
					*pyTop =  pCPoint.Y;
					*pcxWidth = pCSize.Width;
					*pcyHeight = pCSize.Height;
					return S_OK;
				}
				else
				{
					*pxLeft = m_sLocation.m_dLeft;
					*pyTop = m_sLocation.m_dTop;
					*pcxWidth = m_sLocation.m_dWidth;
					*pcyHeight = m_sLocation.m_dHeight;
					return S_OK;
				}
			}

		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Returns the current focused child to AT. 
* @param	navDir, the direction flag of the navigation.
* @param	varStart, the start child id of this navigation action.
* @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarEndUpAt == NULL)
		{
			return E_INVALIDARG;
		}
		HRESULT ret = E_FAIL;
		switch (navDir)
		{
		case NAVDIR_FIRSTCHILD:
			ret = GetFirstChild(varStart,pvarEndUpAt);
			break;
		case NAVDIR_LASTCHILD:
			ret = GetLastChild(varStart,pvarEndUpAt);
			break;
		case NAVDIR_NEXT:
			ret = GetNextSibling(varStart,pvarEndUpAt);
			break;
		case NAVDIR_PREVIOUS:
			ret = GetPreSibling(varStart,pvarEndUpAt);
			break;
		case NAVDIR_DOWN://do not implement temporarily
			break;
		case NAVDIR_UP://do not implement temporarily
			break;
		case NAVDIR_LEFT://do not implement temporarily
			break;
		case NAVDIR_RIGHT://do not implement temporarily
			break;
		default:
			break;
		};
		return ret;

		LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarChild)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarChild == NULL)
		{
			return E_INVALIDARG;
		}
		long x, y, w, h;
		VARIANT varSelf;
		VariantInit(&varSelf);
		varSelf.vt = VT_I4;
		varSelf.lVal = CHILDID_SELF;
		accLocation(&x,&y,&w,&h,varSelf);
		if( (x < xLeft && (x + w) >xLeft) && (y < yTop && (y + h) >yTop) )
		{
			int i, nCount;
			pvarChild->vt = VT_EMPTY;
			Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
			nCount = pRContext->getAccessibleChildCount();
			if(nCount > 256)
				return E_FAIL;
			IMAccessible* child = NULL;
			for( i = 0; i<nCount; i++)
			{

				child = GetChildInterface(i + 1);
				if(child && child->accHitTest(xLeft,yTop,pvarChild) == S_OK)
					break;
			}

			if(pvarChild->vt == VT_DISPATCH)
				return S_OK;

			if( i < nCount)
			{
				pvarChild->vt = VT_DISPATCH;
				pvarChild->pdispVal = child;
				child->AddRef();
			}
			else
			{
				pvarChild->vt = VT_I4;
				pvarChild->lVal = CHILDID_SELF;
			}
			return S_OK;
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* Get The other Interface from CMAccessible. 
* @param	guidService, must be IID_IAccessible here.
* @param	riid, the IID interface .
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::QueryService(REFGUID guidService, REFIID riid, void** ppvObject)
{
	if( InlineIsEqualGUID(guidService, IID_IAccessible) )
		return QueryInterface(riid, ppvObject);
	return S_FALSE;
}

/**
* Set the accessible name of the current COM object self or its one child from UNO. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	szName, the name used to set the name of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::put_accName(VARIANT varChild, BSTR szName)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal==CHILDID_SELF)
			{
				SAFE_SYSFREESTRING(m_pszName);
				m_pszName=SysAllocString(szName);
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->put_accName(varChild,szName);
		}
		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible value of the current COM object self or its one child from UNO. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	szValue, the value used to set the value of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::put_accValue(VARIANT varChild, BSTR szValue)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal==CHILDID_SELF)
			{
				SysAllocString(m_pszValue);
				m_pszValue=SysAllocString(szValue);
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->put_accValue(varChild,szValue);
		}
		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible name of the current COM object self from UNO. 
* @param	pszName, the name value used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccName(const OLECHAR __RPC_FAR *pszName)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pszName == NULL)
		{
			return E_INVALIDARG;
		}

		SAFE_SYSFREESTRING(m_pszName);//??
		m_pszName = SysAllocString(pszName);
		if(m_pszName==NULL)
			return E_FAIL;
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible role of the current COM object self from UNO. 
* @param	pRole, the role value used to set the role of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccRole(unsigned short pRole)
{
	m_iRole = pRole;
	return S_OK;
}

/**
* Add one state into the current state set for the current COM object from UNO. 
* @param	pXSate, the state used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::DecreaseState(DWORD pXSate)
{
	m_dState &= (~pXSate);
	return S_OK;
}

/**
* Delete one state into the current state set for the current COM object from UNO. 
* @param	pXSate, the state used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::IncreaseState(DWORD pXSate)
{
	m_dState |= pXSate;
	return S_OK;
}

/**
* Set state into the current state set for the current COM object from UNO. 
* @param	pXSate, the state used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::SetState(DWORD pXSate)
{
	m_dState = pXSate;
	return S_OK;
}



/**
* Set the accessible description of the current COM object self from UNO. 
* @param	pszDescription, the name used to set the description of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccDescription(const OLECHAR __RPC_FAR *pszDescription)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pszDescription == NULL)
		{
			return E_INVALIDARG;
		}

		SAFE_SYSFREESTRING(m_pszDescription);
		m_pszDescription = SysAllocString(pszDescription);

		if(m_pszDescription==NULL)
			return E_FAIL;
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible value of the current COM object self from UNO. 
* @param	pszAccValue, the name used to set the value of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccValue(const OLECHAR __RPC_FAR *pszAccValue)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pszAccValue == NULL)
		{
			return E_INVALIDARG;
		}
		SAFE_SYSFREESTRING(m_pszValue);
		m_pszValue = SysAllocString(pszAccValue);
		if(m_pszValue==NULL)
			return E_FAIL;
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Set the HWND value of the current COM object self from UNO. It should set the parent IAccessible
* Object through the method AccessibleObjectFromWindow(...).
* @param	hwnd, the HWND used to set the value of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccWindowHandle(HWND hwnd)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		m_hwnd = hwnd;
	return S_OK;

	LEAVE_PROTECTED_BLOCK
}

/**
* Set accessible focus by specifying child ID
* @param	dChildID, the child id identifies the focus child.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccFocus(long dChildID)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()

		if(dChildID==CHILDID_SELF)
		{
			if(m_pIParent)
			{
				m_pIParent->Put_XAccFocus(m_dChildID);
			}
		}
		else
		{
			m_dFocusChildID = dChildID;
			//traverse all ancestors to set the focused child ID so that when the get_accFocus is called on 
			//any of the ancestors, this id can be used to get the IAccessible of focused object. 
			if(m_pIParent)
			{
				m_pIParent->Put_XAccFocus(dChildID);
			}
		}
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
*Set accessible object location for the current COM object
* @param	sLocation, the location of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccLocation(const Location sLocation)
{

	this->m_sLocation = sLocation;
	return S_OK;
}

/**
* Set accessible parent object for the current COM object if 
* the current object is a child of some COM object
* @param	pIParent, the parent of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccParent(IMAccessible __RPC_FAR *pIParent)
{
	this->m_pIParent = pIParent;

	if(pIParent)
		m_pIParent->AddRef();

	return S_OK;
}

/**
* Set unique child id to COM
* @param	dChildID, the id of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccChildID(long dChildID)
{

	this->m_dChildID = dChildID;
	return S_OK;
}

/**
* Set AccObjectManagerAgent object pointer to COM
* @param	pAgent, the AccObjectManagerAgent point.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccAgent(long pAgent)
{
	g_pAgent = (AccObjectManagerAgent*)pAgent;
	return S_OK;
}

/**
* When a UNO control disposing, it disposes its listeners,
* then notify AccObject in bridge management, then notify 
* COM that the XAccessible is invalid,so set pUNOInterface as NULL
* @param	isDestroy, true is it need to be destroyed.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::NotifyDestroy(BOOL isDestroy)
{

	m_isDestroy = isDestroy;
	pUNOInterface = NULL;
	return S_OK;
}

/**
*private methods that help implement public functions
*/

/**
* Return child interface pointer by child ID,note: need to call AddRef()
* @param	lChildID, specify child index,which AT(such as Inspect32) gives.
* @return  IMAccessible*, pointer to the corresponding child object.
*/
IMAccessible* CMAccessible::GetChildInterface(long dChildID)//for test
{

	long dChildIndex = 0;
	if(dChildID<0)
	{
		if(g_pAgent)
		{
			IMAccessible* pIMAcc = NULL;
			g_pAgent->GetIAccessibleFromResID(dChildID,&pIMAcc);
			return pIMAcc;
		}
		return NULL;
	}
	else
	{
		Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
		if( !pRContext.is() )
			return NULL;

		if(dChildID<1 || dChildID>pRContext->getAccessibleChildCount())
			return NULL;

		IAccessible* pChild = NULL;
		Reference< XAccessible > pXChild = pRContext->getAccessibleChild(dChildID-1);
		BOOL isGet = get_IAccessibleFromXAccessible((long)pXChild.get(),&pChild);

		if(!isGet)
		{
			g_pAgent->InsertAccObj(pXChild.get(),pUNOInterface,(long)m_hwnd);
			isGet = get_IAccessibleFromXAccessible((long)pXChild.get(),&pChild);
		}

		if(isGet)
		{
			IMAccessible* pIMAcc =  (IMAccessible*)pChild;
			return pIMAcc;
		}
	}

	return NULL;
}

/**
* For List, tree and table,these roles belong to manage_decendant in UNO,
* need to process specifically when navigate
* @return  BOOL, if it is decendantmanager, return true.
*/
BOOL CMAccessible::IsDecendantManage()
{

	return (m_iRole==ROLE_SYSTEM_LIST)||(m_iRole==ROLE_SYSTEM_OUTLINE)||(m_iRole==ROLE_SYSTEM_TABLE);
}

/**
* for decendantmanager circumstance,provide child interface when navigate
* @param	varCur, the current child.
* @param	flags, the navigation direction.
* @return  IMAccessible*, the child of the end up node.
*/
IMAccessible* CMAccessible::GetNavigateChildForDM(VARIANT varCur, short flags)
{

	XAccessibleContext* pXContext = GetContextByXAcc(pUNOInterface);
	if(pXContext==NULL)
	{
		return NULL;
	}

	int count = pXContext->getAccessibleChildCount();
	if(count<1)
	{
		return NULL;
	}

	IMAccessible* pCurChild = NULL;
	XAccessible* pChildXAcc = NULL;
	Reference<XAccessible> pRChildXAcc;
	XAccessibleContext* pChildContext = NULL;
	int index = 0,delta=0;
	switch(flags)
	{
	case DM_FIRSTCHILD:
		pRChildXAcc = pXContext->getAccessibleChild(0);
		break;
	case DM_LASTCHILD:
		pRChildXAcc = pXContext->getAccessibleChild(count-1);
		break;
	case DM_NEXTCHILD:
	case DM_PREVCHILD:
		pCurChild = GetChildInterface(varCur.lVal);
		if(pCurChild==NULL)
		{
			return NULL;
		}
		pCurChild->GetUNOInterface((long*)&pChildXAcc);
		if(pChildXAcc==NULL)
		{
			return NULL;
		}
		pChildContext = GetContextByXAcc(pChildXAcc);
		if(pChildContext == NULL)
		{
			return NULL;
		}
		delta = (flags==DM_NEXTCHILD)?1:-1;
		//currently, getAccessibleIndexInParent is error in UNO for
		//some kind of List,such as ValueSet, the index will be less 1 than
		//what should be, need to fix UNO code
		index = pChildContext->getAccessibleIndexInParent()+delta;
		if((index>=0)&&(index<=count-1))
		{
			pRChildXAcc = pXContext->getAccessibleChild(index);
		}
		break;
	default:
		break;
	}

	if(!pRChildXAcc.is())
	{
		return NULL;
	}
	pChildXAcc = pRChildXAcc.get();
	g_pAgent->InsertAccObj(pChildXAcc,pUNOInterface);
	return g_pAgent->GetIMAccByXAcc(pChildXAcc);
}

/**
*the following 4 private methods are for accNavigate implementation
*/

/**
* Return first child for parent container, process differently according 
* to whether it is decendant manage
* @param	varStart, the start child id of this navigation action.
* @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return   S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetFirstChild(VARIANT varStart,VARIANT* pvarEndUpAt)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarEndUpAt == NULL)
		{
			return E_INVALIDARG;
		}
		if(varStart.vt != VT_I4)
		{
			pvarEndUpAt->vt = VT_EMPTY;
			return E_INVALIDARG;
		}

		pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_FIRSTCHILD);
		if(pvarEndUpAt->pdispVal)
		{
			pvarEndUpAt->pdispVal->AddRef();
			pvarEndUpAt->vt = VT_DISPATCH;
			return S_OK;
		}

		pvarEndUpAt->vt = VT_EMPTY;
		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

/**
* Return last child for parent container, process differently according 
* to whether it is decendant manage
* @param	varStart, the start child id of this navigation action.
* @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return   S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetLastChild(VARIANT varStart,VARIANT* pvarEndUpAt)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarEndUpAt == NULL)
		{
			return E_INVALIDARG;
		}
		if(varStart.vt != VT_I4)
		{
			pvarEndUpAt->vt = VT_EMPTY;
			return E_INVALIDARG;
		}

		pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_LASTCHILD);
		if(pvarEndUpAt->pdispVal)
		{
			pvarEndUpAt->pdispVal->AddRef();
			pvarEndUpAt->vt = VT_DISPATCH;
			return S_OK;
		}
		pvarEndUpAt->vt = VT_EMPTY;
		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

/**
* The method GetNextSibling is general, whatever it is decendant manage or not
* Get the next sibling object.
* @param	varStart, the start child id of this navigation action.
* @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return   S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetNextSibling(VARIANT varStart,VARIANT* pvarEndUpAt)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(varStart.vt != VT_I4)
		{
			pvarEndUpAt->vt = VT_EMPTY;
			return E_INVALIDARG;
		}

		Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
		if(pRContext.is())
		{
			varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent() + 2);
			if(m_pIParent)
				if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK)
				{
					pvarEndUpAt->vt = VT_DISPATCH;
					return S_OK;
				}
		}
		pvarEndUpAt->vt = VT_EMPTY;
		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

/**
*the method GetPreSibling is general, whatever it is decendant manage or not
* @param	varStart, the start child id of this navigation action.
* @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return   S_OK if successful and E_FAIL if failure.
*/
HRESULT CMAccessible::GetPreSibling(VARIANT varStart,VARIANT* pvarEndUpAt)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pvarEndUpAt == NULL)
		{
			return E_INVALIDARG;
		}
		if(varStart.vt != VT_I4)
		{
			pvarEndUpAt->vt = VT_EMPTY;
			return E_INVALIDARG;
		}

		Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
		if(pRContext.is())
		{
			varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent());
			if(m_pIParent && varStart.iVal > 0)
				if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK)
				{
					pvarEndUpAt->vt = VT_DISPATCH;
					return S_OK;
				}
		}
		pvarEndUpAt->vt = VT_EMPTY;
		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

/**
* For IAccessible2 implementation methods
*/
STDMETHODIMP CMAccessible::get_nRelations( long __RPC_FAR *nRelations)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK

		// #CHECK#
		if(nRelations == NULL)
		{
			return E_INVALIDARG;
		}

		*nRelations = 0;

		if( !pRContext.is() )
			return E_FAIL;
		Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
		if(!pRrelationSet.is())
		{
			*nRelations = 0;
			return S_OK;
		}

		*nRelations = pRrelationSet->getRelationCount();
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::get_relation( long relationIndex, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(relation == NULL)
		{
			return E_INVALIDARG;
		}

		if( !pRContext.is() )
			return E_FAIL;


		long nMax = 0;
		long nReal = 0;
		get_nRelations(&nMax);

		*relation = (IAccessibleRelation*)::CoTaskMemAlloc(sizeof(IAccessibleRelation));

		// #CHECK Memory Allocation#
		if(*relation == NULL)
		{
			return E_FAIL;
		}

		if( relationIndex < nMax )
		{


			Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
			if(!pRrelationSet.is())
			{

				return E_FAIL;
			}

			IAccessibleRelation* pRelation = NULL;
			ActivateActContext();
			HRESULT hr = CoCreateInstance( CLSID_AccRelation, NULL, CLSCTX_SERVER ,
				IID_IAccessibleRelation,
				(void **)&pRelation);
			DeactivateActContext();
			if(SUCCEEDED(hr))
			{
				IUNOXWrapper* wrapper = NULL;
				hr = pRelation->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
				if(SUCCEEDED(hr))
				{
					AccessibleRelation accRelation = pRrelationSet->getRelation(relationIndex);
					wrapper->put_XSubInterface((long)&accRelation);
					wrapper->Release();
					*relation = pRelation;
					return S_OK;
				}

			}
		}

		return E_FAIL;

		LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::get_relations( long, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation, long __RPC_FAR *nRelations)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK

		// #CHECK#
		if(relation == NULL || nRelations == NULL)
		{
			return E_INVALIDARG;
		}
		// #CHECK XInterface#

		if( !pRContext.is() )
			return E_FAIL;

		Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
		if(!pRrelationSet.is())
		{
			*nRelations = 0;
			return S_OK;
		}

		long nCount = pRrelationSet->getRelationCount();

		*relation = (IAccessibleRelation*)::CoTaskMemAlloc(nCount*sizeof(IAccessibleRelation));

		// #CHECK Memory Allocation#
		if(*relation == NULL)
		{
			return E_FAIL;
		}

		for(int i=0; i<nCount ; i++)
		{
			IAccessibleRelation* pRelation = NULL;
			ActivateActContext();
			HRESULT hr = CoCreateInstance( CLSID_AccRelation, NULL, CLSCTX_SERVER ,
				IID_IAccessibleRelation,
				(void **)&pRelation);
			DeactivateActContext();
			if(SUCCEEDED(hr))
			{
				IUNOXWrapper* wrapper = NULL;
				hr = pRelation->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
				if(SUCCEEDED(hr))
				{
					AccessibleRelation accRelation = pRrelationSet->getRelation(i);
					wrapper->put_XSubInterface((long)&accRelation);
					wrapper->Release();
				}
				(relation)[i] = pRelation;
			}
		}

		*nRelations = nCount;
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::role(long __RPC_FAR *role)
{
	ENTER_PROTECTED_BLOCK

		(*role) = m_iRole;

	return S_OK;

	LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_nActions(long __RPC_FAR *nActions)
{

	try
	{
		ISDESTROY()
			// #CHECK#
			if(nActions == NULL)
			{
				return E_INVALIDARG;
			}
			*nActions = 0L;
			IAccessibleAction* pAcc = NULL;
			HRESULT hr = QueryInterface(IID_IAccessibleAction, (void**)&pAcc);
			if( hr == S_OK )
			{
				pAcc->nActions(nActions);
				pAcc->Release();
			}

			return S_OK;
	}
	catch(...)
	{
		*nActions = 0L;
		return S_OK;
	}
}


STDMETHODIMP CMAccessible:: scrollToPoint(enum IA2CoordinateType, long, long)
{

	ENTER_PROTECTED_BLOCK
	ISDESTROY()
	return E_NOTIMPL;
	LEAVE_PROTECTED_BLOCK

}
STDMETHODIMP CMAccessible:: scrollTo(enum IA2ScrollType)
{

	ENTER_PROTECTED_BLOCK
	ISDESTROY()

	return E_NOTIMPL;

	LEAVE_PROTECTED_BLOCK
}

static XAccessible* getTheParentOfMember(XAccessible* pXAcc)
{
	// #CHECK#
	if(pXAcc == NULL)
	{
		return NULL;
	}
	Reference<XAccessibleContext> pRContext = pXAcc->getAccessibleContext();
	Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
	long nRelations = pRrelationSet->getRelationCount();
	for(int i=0 ; i<nRelations ; i++)
	{
		AccessibleRelation accRelation = pRrelationSet->getRelation(i);
		if(accRelation.RelationType == 7)
		{
			Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet;
			return (XAccessible*)xTargets[0].get();
		}
	}
	return NULL;
}

STDMETHODIMP CMAccessible:: get_groupPosition(long __RPC_FAR *groupLevel,long __RPC_FAR *similarItemsInGroup,long __RPC_FAR *positionInGroup)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(groupLevel == NULL || similarItemsInGroup == NULL || positionInGroup == NULL)
		{
			return E_INVALIDARG;
		}

		Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
		if(!pRContext.is())
			return E_FAIL;
		long Role = pRContext->getAccessibleRole();

		*groupLevel = 0;
		*similarItemsInGroup = 0;
		*positionInGroup = 0;

		if (Role != AccessibleRole::DOCUMENT)
		{
			Reference< XAccessibleGroupPosition > xGroupPosition( pRContext, UNO_QUERY );
			if ( xGroupPosition.is() )
			{
				Sequence< sal_Int32 > rSeq = xGroupPosition->getGroupPosition( makeAny( pRContext ) );
				sal_Int32* pSeq = rSeq.getArray();
				if ( pSeq )
				{
					*groupLevel = pSeq[0];
					*similarItemsInGroup = pSeq[1];
					*positionInGroup = pSeq[2];
					return S_OK;
				}
				return S_OK;
			}
		}

		Reference< XAccessible> pParentAcc = pRContext->getAccessibleParent();
		if( !pParentAcc.is() )
		{
			return S_OK;
		}

		Reference<XAccessibleContext> pRParentContext = pParentAcc->getAccessibleContext();

		int level = 0;
		int index = 0;
		int number = 0;

		if( Role ==  RADIO_BUTTON )
		{
			Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
			long nRel = pRrelationSet->getRelationCount();
			for(int i=0 ; i<nRel ; i++)
			{
				AccessibleRelation accRelation = pRrelationSet->getRelation(i);
				if(accRelation.RelationType == 7)
				{
					Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet;
					int nCount = xTargets.getLength();

					Reference<XInterface> pRAcc = xTargets[0];
					for(int j=0; j<pRParentContext->getAccessibleChildCount(); j++)
					{
						if( getTheParentOfMember(pRParentContext->getAccessibleChild(j).get())
							== (XAccessible*)pRAcc.get() &&
							pRParentContext->getAccessibleChild(j)->getAccessibleContext()->getAccessibleRole() == RADIO_BUTTON)
							number++;
						if(pRParentContext->getAccessibleChild(j).get() == pUNOInterface)
							index = number;
					}
				}
			}
			*groupLevel = 1;
			*similarItemsInGroup = number;
			*positionInGroup = index;
			return S_OK;
		}

		else if ( COMBO_BOX == Role )
		{
			*groupLevel = 1;
			*similarItemsInGroup = 0;
			*positionInGroup = -1;

			long nCount = pRContext->getAccessibleChildCount();
			if( 2 != nCount)
			{
				return S_OK;
			}
			Reference<XAccessible> xList=pRContext->getAccessibleChild(1);
			if (!xList.is())
			{
				return S_OK;
			}
			Reference<XAccessibleContext> xListContext(xList,UNO_QUERY);
			if (!xListContext.is())
			{
				return S_OK;
			}
			Reference<XAccessibleSelection> xListSel(xList,UNO_QUERY);
			if (!xListSel.is())
			{
				return S_OK;
			}
			*similarItemsInGroup = xListContext->getAccessibleChildCount();
			if (*similarItemsInGroup > 0 )
			{
				try
				{
					Reference<XAccessible> xChild = xListSel->getSelectedAccessibleChild(0);
					if (xChild.is())
					{
						Reference<XAccessibleContext> xChildContext(xChild,UNO_QUERY);
						if (xChildContext.is())
						{
							*positionInGroup=xChildContext->getAccessibleIndexInParent() + 1 ;
							return S_OK;
						}
					}
				}
				catch(...)
				{}
			}
			return S_OK;
		}
		else if ( PAGE_TAB == Role )
		{
			*groupLevel = 1;
			*similarItemsInGroup = pRParentContext->getAccessibleChildCount();

			if (*similarItemsInGroup > 0 )
			{
				*positionInGroup=pRContext->getAccessibleIndexInParent() + 1 ;
			}
			else
			{
				*positionInGroup = -1;
			}
			return S_OK;
		}


		BOOL isFound = FALSE;
		while( pParentAcc.is() && !isFound)
		{
			level++;
			pRParentContext = pParentAcc->getAccessibleContext();
			Role = pRParentContext->getAccessibleRole();
			if( (Role == TREE) || (Role == LIST) )
				isFound = TRUE;
			pParentAcc = pRParentContext->getAccessibleParent();
		}

		if( isFound )
		{
			Reference< XAccessible> pTempAcc = pRContext->getAccessibleParent();
			pRParentContext = pTempAcc->getAccessibleContext();
			*groupLevel = level;
			*similarItemsInGroup = pRParentContext->getAccessibleChildCount();
			*positionInGroup = pRContext->getAccessibleIndexInParent() + 1;
		}
		else
		{
			*groupLevel = 0;
			*similarItemsInGroup = 0;
			*positionInGroup = 0;
		}
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible:: get_extendedStates( long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()

		return E_NOTIMPL;

	LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_uniqueID(long __RPC_FAR *uniqueID)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(uniqueID == NULL)
		{
			return E_INVALIDARG;
		}
		*uniqueID = m_dChildID;
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible:: get_windowHandle(HWND __RPC_FAR *windowHandle)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(windowHandle == NULL)
		{
			return E_INVALIDARG;
		}

		HWND nHwnd = m_hwnd;
		IAccessible* pParent = m_pIParent;
		CMAccessible* pChild = this;
		while((nHwnd==0) && pParent)
		{
			pChild = (CMAccessible*)pParent;
			if(pChild)
			{
				pParent = (IAccessible*)pChild->m_pIParent;
				nHwnd = (HWND)pChild->m_hwnd;
			}
			else
				pParent = NULL;
		}

		*windowHandle = nHwnd;
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Get XAccessibleContext directly from UNO by the stored XAccessible pointer
* @param	pXAcc, UNO XAccessible object point.
* @return   XAccessibleContext*, the context of the pXAcc.
*/
XAccessibleContext* CMAccessible::GetContextByXAcc( XAccessible* pXAcc )
{
	Reference< XAccessibleContext > pRContext;
	if( pXAcc == NULL)
		return NULL;

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

/**
* Return the member variable m_pXAccessibleSelection, instead of 
* get XAccessibleSelection according to XAccessibleContext because if so,it will 
* depend on the UNO implementation code,so when COM is created, put XAccessibleSelection
* by bridge management system
* @return   XAccessibleSelection*, the selection of the current object.
*/
Reference< XAccessibleSelection > CMAccessible::GetSelection()
{
	if( pUNOInterface == NULL )
		return NULL;
	Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
	if(pRContext.is())
	{
		Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY);
		return pRSelection;
	}
	return NULL;
}

/**
* Select one XAccessible item, for accSelect implementation
* @param	pItem, the item should be selected.
* @return  S_OK if successful.
*/
HRESULT CMAccessible::SelectChild(XAccessible* pItem)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		XAccessibleContext* pParentContext = GetContextByXAcc( pUNOInterface );
	XAccessibleContext* pContext = GetContextByXAcc( pItem );
	if( pParentContext == NULL || pContext == NULL )
		return E_FAIL;

	Reference< XAccessibleSelection > pRSelection = GetSelection();
	if( !pRSelection.is() )
		return E_FAIL;
	long Index = pContext->getAccessibleIndexInParent();
	pRSelection->selectAccessibleChild( Index );
	return S_OK;

	LEAVE_PROTECTED_BLOCK
}

/**
* Deselect one XAccessible item, for accSelect implimentation
* @param	pItem, the item should be deselected.
* @return  S_OK if successful.
*/
HRESULT CMAccessible::DeSelectChild(XAccessible* pItem)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		XAccessibleContext* pParentContext = GetContextByXAcc( pUNOInterface );
	;
	XAccessibleContext* pContext = GetContextByXAcc( pItem );
	if( pParentContext == NULL || pContext == NULL )
		return E_INVALIDARG;

	Reference< XAccessibleSelection > pRSelection = GetSelection();
	if( !pRSelection.is() )
		return E_FAIL;
	long Index = pContext->getAccessibleIndexInParent();
	pRSelection->deselectAccessibleChild( Index );

	return S_OK;

	LEAVE_PROTECTED_BLOCK
}

/**
* Select multiple XAccessible items,for implementation of accSelect
* @param	pItem, the items should be selected.
* @param	size, the size of the items.
* @return  S_OK if successful.
*/
HRESULT	CMAccessible::SelectMutipleChidren( XAccessible** pItem,int size )
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pItem == NULL)
		{
			return E_INVALIDARG;
		}
		for(int index = 0;index < size;index++)
		{
			SelectChild( pItem[index] );
		}
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* Deselect multiple XAccessible items,for implementation of accSelect
* @param	pItem, the items should be selected.
* @param	size, the size of the items.
* @return  S_OK if successful.
*/
HRESULT CMAccessible::DeSelectMutipleChildren( XAccessible** pItem,int size )
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pItem == NULL)
		{
			return E_INVALIDARG;
		}
		for(int index = 0;index < size;index++)
		{
			DeSelectChild( pItem[index] );
		}
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

/**
* When COM is created, UNO set XAccessible pointer to it
* in order to COM can operate UNO information
* @param	pXAcc, the XAccessible object of current object.
* @return  S_OK if successful.
*/
STDMETHODIMP CMAccessible::SetXAccessible(long pXAcc)
{
	pUNOInterface = (XAccessible*)pXAcc;
	pRef = pUNOInterface;
	m_pEnumVar->PutSelection(/*XAccessibleSelection*/(long)pUNOInterface);

	pRContext = pUNOInterface->getAccessibleContext();
	pRContextInterface = (XAccessibleContext*)pRContext.is();

	return S_OK;
}

/**
* accSelect method has many optional flags, needs to process comprehensively
* Mozilla and Microsoft do not implement SELFLAG_EXTENDSELECTION flag. 
* The implementation of this flag is a little trouble-shooting,so we also
* do not implement it now
* @param	flagsSelect, the selection flag of the select action.
* @param	varChild, the child object pointer of current action.
* @return  S_OK if successful.
*/
STDMETHODIMP CMAccessible::accSelect(long flagsSelect, VARIANT varChild)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if( (flagsSelect&SELFLAG_ADDSELECTION) &&
			(SELFLAG_REMOVESELECTION&flagsSelect) )
			return E_INVALIDARG;

	if ( (flagsSelect&SELFLAG_TAKESELECTION) &&
		(
		(flagsSelect&SELFLAG_ADDSELECTION) ||
		(flagsSelect&SELFLAG_REMOVESELECTION) ||
		(flagsSelect&SELFLAG_EXTENDSELECTION )
		)
		)
		return E_INVALIDARG;

	if ( varChild.vt !=	VT_I4 )
		return E_INVALIDARG;

	IMAccessible* pSelectAcc;
	if( varChild.lVal == CHILDID_SELF )
	{
		pSelectAcc = this;
		pSelectAcc->AddRef();
	}
	else
	{
		pSelectAcc = GetChildInterface(varChild.lVal);
	}

	if( pSelectAcc == NULL )
		return E_INVALIDARG;

	if( flagsSelect&SELFLAG_TAKEFOCUS )
	{
		long pTempUNO = 0;
		pSelectAcc->GetUNOInterface( &pTempUNO);

		if( pTempUNO == NULL )
			return NULL;

		Reference< XAccessibleContext > pRContext = ( (XAccessible*)pTempUNO)->getAccessibleContext();
		Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY);
		Reference< XAccessible > pRParentXAcc = pRContext->getAccessibleParent();
		Reference< XAccessibleContext > pRParentContext = pRParentXAcc->getAccessibleContext();
		Reference< XAccessibleComponent > pRParentComponent(pRParentContext,UNO_QUERY);
		Reference< XAccessibleSelection > pRParentSelection(pRParentContext,UNO_QUERY);


		pRComponent->grabFocus();

		if( flagsSelect & SELFLAG_TAKESELECTION )
		{
			pRParentSelection->clearAccessibleSelection();
			pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() );
		}

		if( flagsSelect & SELFLAG_ADDSELECTION  )
		{
			pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() );
		}

		if( flagsSelect & SELFLAG_REMOVESELECTION )
		{
			pRParentSelection->deselectAccessibleChild( pRContext->getAccessibleIndexInParent() );
		}

		if( flagsSelect & SELFLAG_EXTENDSELECTION  )
		{
			long indexInParrent = pRContext->getAccessibleIndexInParent();

			if( pRParentSelection->isAccessibleChildSelected( indexInParrent + 1 ) ||
				pRParentSelection->isAccessibleChildSelected( indexInParrent - 1 ) )
			{
				pRParentSelection->selectAccessibleChild( indexInParrent );
			}
		}

	}

	pSelectAcc->Release();
	return S_OK;

	LEAVE_PROTECTED_BLOCK
}

/**
* Return XAccessible interface pointer when needed
* @param pXAcc, [in, out] the Uno interface of the current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::GetUNOInterface(long* pXAcc)
{
	// #CHECK#
	if(pXAcc == NULL)
		return E_INVALIDARG;

	*pXAcc = (long)pUNOInterface;
	return S_OK;
}

/**
* Helper method for Implementation of get_accDefaultAction
* @param pAction, the default action point of the current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::SetDefaultAction(long pAction)
{
	m_pXAction = (XAccessibleAction*)pAction;
	return S_OK;
}

/**
* This method is called when AT open some UI elements initially
* the UI element takes the default action defined here
* @param varChild, the child id of the defaultaction.
* @param pszDefaultAction,[in/out] the description of the current action.
* @return S_OK if successful.
*/
HRESULT STDMETHODCALLTYPE CMAccessible::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(pszDefaultAction == NULL)
		{
			return E_INVALIDARG;
		}
		if(varChild.vt==VT_I4)
		{
			if(varChild.lVal==CHILDID_SELF)
			{
				if( m_pXAction == NULL )
					return DISP_E_MEMBERNOTFOUND;
				SAFE_SYSFREESTRING(*pszDefaultAction);
				*pszDefaultAction = SysAllocString(m_pszActionDescription);
				return S_OK;
			}

			long lVal = varChild.lVal;
			varChild.lVal = CHILDID_SELF;
			IMAccessible *pChild = this->GetChildInterface(lVal);
			if(!pChild)
				return E_FAIL;
			return pChild->get_accDefaultAction(varChild,pszDefaultAction);
		}
		return S_FALSE;

		LEAVE_PROTECTED_BLOCK
}

/**
* AT call this method to operate application
* @param varChild, the child id of the action object.
* @return S_OK if successful.
*/
HRESULT STDMETHODCALLTYPE CMAccessible::accDoDefaultAction(VARIANT varChild)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if( varChild.vt != VT_I4 )
			return E_INVALIDARG;
	if( m_pXAction == NULL )
		return E_FAIL;
	if( m_pXAction->getAccessibleActionCount() == 0 )
		return E_FAIL;

	if(varChild.lVal==CHILDID_SELF)
	{
		if(m_pXAction->getAccessibleActionCount() > 0)
			m_pXAction->doAccessibleAction(0);
		return S_OK;
	}

	long lVal = varChild.lVal;
	varChild.lVal = CHILDID_SELF;
	IMAccessible *pChild = this->GetChildInterface(lVal);
	if(!pChild)
		return E_FAIL;
	return pChild->accDoDefaultAction( varChild );

	LEAVE_PROTECTED_BLOCK
}

/**
* UNO set description information for action to COM.
* @param szAction, the action description of the current object.
* @return S_OK if successful.
*/
STDMETHODIMP CMAccessible::Put_ActionDescription( const OLECHAR* szAction)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(szAction == NULL)
		{
			return E_INVALIDARG;
		}
		SAFE_SYSFREESTRING(m_pszActionDescription );
		m_pszActionDescription = SysAllocString( szAction );
		return S_OK;

		LEAVE_PROTECTED_BLOCK
}

BOOL CMAccessible::GetXInterfaceFromXAccessible(XAccessible* pXAcc, XInterface** ppXI, int index)
{
	Reference< XAccessibleContext > pRContext;

	switch(index)
	{
	case XI_COMPONENT:
		QUERYXINTERFACE(AccessibleComponent)
			break;
	case XI_TEXT:
		QUERYXINTERFACE(AccessibleText)
			break;
	case XI_EDITABLETEXT:
		QUERYXINTERFACE(AccessibleEditableText)
			break;
	case XI_TABLE:
		QUERYXINTERFACE(AccessibleTable)
			break;
	case XI_SELECTION:
		QUERYXINTERFACE(AccessibleSelection)
			break;
	case XI_EXTENDEDCOMP:
		QUERYXINTERFACE(AccessibleExtendedComponent)
			break;
	case XI_KEYBINDING:
		QUERYXINTERFACE(AccessibleKeyBinding)
			break;
	case XI_ACTION:
		QUERYXINTERFACE(AccessibleAction)
			break;
	case XI_VALUE:
		QUERYXINTERFACE(AccessibleValue)
			break;
	case XI_HYPERTEXT:
		QUERYXINTERFACE(AccessibleHypertext)
			break;
	case XI_HYPERLINK:
		QUERYXINTERFACE(AccessibleHyperlink)
			break;
	case XI_IMAGE:
		QUERYXINTERFACE(AccessibleImage)
			break;
	default:
		break;
	}

	return FALSE;
}

HRESULT WINAPI CMAccessible::SmartQI(void* pv, REFIID iid, void** ppvObject)
{
	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if( ImplIsEqualGUID(iid,IID_IAccIdentity) ||
			ImplIsEqualGUID(iid,IID_IStdMarshalInfo) ||
			ImplIsEqualGUID(iid,IID_IMarshal) ||
			ImplIsEqualGUID(iid,IID_IExternalConnection)||
			ImplIsEqualGUID(iid,IID_IOleWindow))
			return E_FAIL;


	_UNO_AGGMAP_ENTRY* pMap = _GetAggEntries();
	while(pMap && pMap->piid)
	{
		if(ImplIsEqualGUID(iid, *pMap->piid))
		{
			XInterface* pXI = NULL;
			BOOL bFound = GetXInterfaceFromXAccessible(pUNOInterface,&pXI,pMap->XIFIndex);
			if(!bFound)
			{
				return E_FAIL;
			}

			XGUIDToComObjHash::iterator pIndTemp = m_containedObjects.find( iid );
			if ( pIndTemp != m_containedObjects.end() )
			{
				return pIndTemp->second.p->QueryInterface( iid, ppvObject );
			}
			else
			{
				ActivateActContext();
				HRESULT hr = pMap->pfnCreateInstance(pv, iid, ppvObject);
				DeactivateActContext();
				if(hr == S_OK)
				{
					m_containedObjects.insert(XGUIDToComObjHash::value_type(*pMap->piid,(IUnknown*)*ppvObject));
					IUNOXWrapper* wrapper = NULL;
					((IUnknown*)*ppvObject)->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
					if(wrapper)
					{
						wrapper->put_XInterface((long)pUNOInterface);
						wrapper->Release();
					}
					return S_OK;
				}
			}
			return E_FAIL;
		}
		pMap++;
	}
	return E_FAIL;

	LEAVE_PROTECTED_BLOCK
}

BOOL CMAccessible::get_IAccessibleFromXAccessible(long pXAcc, IAccessible **ppIA)
{

	ENTER_PROTECTED_BLOCK

		// #CHECK#
		if(ppIA == NULL)
		{
			return E_INVALIDARG;
		}
		BOOL isGet = FALSE;
		if(g_pAgent)
			isGet = g_pAgent->GetIAccessibleFromXAccessible((XAccessible*)pXAcc,ppIA);

		if(isGet)
			return TRUE;
		else
			return FALSE;

		LEAVE_PROTECTED_BLOCK
}

void CMAccessible::get_OLECHARFromAny(Any& pAny, OLECHAR* pChar)
{
	// #CHECK#
	if(pChar == NULL)
		return;

	switch(pAny.getValueTypeClass())
	{
	case TypeClass_CHAR:
		{
			sal_Int8 val;
			pAny >>= val;
			swprintf( pChar, L"%d", val);
			break;
		}
	case TypeClass_BOOLEAN:
		{
			sal_Bool val;
			pAny >>= val;
			swprintf( pChar, L"%d", val);
			break;
		}
	case TypeClass_BYTE:
		{
			sal_Int8 val;
			pAny >>= val;
			swprintf( pChar, L"%d", val);
			break;
		}
	case TypeClass_SHORT:
		{
			SHORT val;
			pAny >>= val;
			swprintf( pChar, L"%d", val);
			break;
		}
	case TypeClass_UNSIGNED_SHORT:
		{
			USHORT val;
			pAny >>= val;
			swprintf( pChar, L"%d", val);
			break;
		}
	case TypeClass_LONG:
		{
			LONG val;
			pAny >>= val;
			swprintf( pChar, L"%ld", val);
			break;
		}
	case TypeClass_UNSIGNED_LONG:
		{
			ULONG val;
			pAny >>= val;
			swprintf( pChar, L"%ld", val);
			break;
		}
	case TypeClass_FLOAT:
		{
			FLOAT val;
			pAny >>= val;
			swprintf( pChar, L"%.3f", val);
			break;
		}
	case TypeClass_DOUBLE:
		{
			DOUBLE val;
			pAny >>= val;
			swprintf( pChar, L"%.6lf", val);
			break;
		}
	case TypeClass_STRING:
		{
			::rtl::OUString val;
			pAny >>= val;
			wcscpy(pChar, val.getStr());
			break;
		}
	case TypeClass_SEQUENCE:
		{
			if(pAny.getValueType() == getCppuType( (Sequence< ::rtl::OUString > *)0 ) )
			{
				Sequence < ::rtl::OUString > val;
				pAny >>= val;

				::rtl::OUString pString;

				int count = val.getLength();

				for( int iIndex = 0;iIndex < count;iIndex++ )
				{
					pString += val[iIndex];
				}
				wcscpy(pChar, pString.getStr());
			}
			else if (pAny.getValueType() == getCppuType( (Sequence< ::com::sun::star::style::TabStop >* )0 ) )
			{
				Sequence < ::com::sun::star::style::TabStop > val;
				pAny >>= val;
				int count = val.getLength();

				for( int iIndex = 0;iIndex < count;iIndex++ )
				{
					OLECHAR pAttrs[512] = {NULL};

					OLECHAR pAttrsPosition[512] = {NULL};
					OLECHAR pAttrsDescimalChar[512] = {NULL};
					OLECHAR pAttrsFillChar[512] = {NULL};

					::com::sun::star::style::TabStop sigleVal = val[iIndex];

					swprintf( pAttrsPosition, L"Position=%ld,TabAlign=%ld",
						sigleVal.Position, sigleVal.Alignment);

					if(sigleVal.DecimalChar==';' || sigleVal.DecimalChar == ':' || sigleVal.DecimalChar == ',' ||
						sigleVal.DecimalChar == '=' || sigleVal.DecimalChar == '\\')
						swprintf( pAttrsDescimalChar, L"DecimalChar=\\%c",sigleVal.DecimalChar);
					else
						swprintf( pAttrsDescimalChar, L"DecimalChar=%c",sigleVal.DecimalChar);

					if(sigleVal.FillChar==';' || sigleVal.FillChar == ':' || sigleVal.FillChar == ',' ||
						sigleVal.FillChar == '=' || sigleVal.FillChar == '\\')
						swprintf( pAttrsFillChar, L"FillChar=\\%c",sigleVal.FillChar);
					else
						swprintf( pAttrsFillChar, L"FillChar=%c",sigleVal.FillChar);

					swprintf( pAttrs, L"%s,%s,%s,",pAttrsPosition,pAttrsDescimalChar,pAttrsFillChar);

					wcscat(pChar,pAttrs);
				}
			}
			break;
		}
	case TypeClass_ENUM:
		{
			if (pAny.getValueType() == getCppuType( (::com::sun::star::awt::FontSlant* )0 ) )
			{
				com::sun::star::awt::FontSlant val;
				pAny >>= val;
				swprintf( pChar, L"%d", val);
			}
		}
	case TypeClass_STRUCT:
		{
			if (pAny.getValueType() == getCppuType( (::com::sun::star::style::LineSpacing* )0 ) )
			{
				com::sun::star::style::LineSpacing val;
				pAny >>= val;
				swprintf( pChar, L"Mode=%ld,Height=%ld,", val.Mode, val.Height);
			}
			else if (pAny.getValueType() == getCppuType( (com::sun::star::accessibility::TextSegment *)0 ) )
			{
				com::sun::star::accessibility::TextSegment val;
				pAny >>= val;
				::rtl::OUString realVal(val.SegmentText);
				wcscpy(pChar, realVal.getStr());
			}
			break;
		}
	case TypeClass_VOID:
	case TypeClass_HYPER:
	case TypeClass_UNSIGNED_HYPER:
	case TypeClass_TYPE:
	case TypeClass_ANY:
	case TypeClass_TYPEDEF:
	case TypeClass_UNION:
	case TypeClass_EXCEPTION:
	case TypeClass_ARRAY:
	case TypeClass_INTERFACE:
	case TypeClass_SERVICE:
	case TypeClass_MODULE:
	case TypeClass_INTERFACE_METHOD:
	case TypeClass_INTERFACE_ATTRIBUTE:
	case TypeClass_UNKNOWN:
	case TypeClass_PROPERTY:
	case TypeClass_CONSTANT:
	case TypeClass_CONSTANTS:
	case TypeClass_SINGLETON:
	case TypeClass_MAKE_FIXED_SIZE:
		break;
	default:
		break;
	}
}

void CMAccessible::get_OLECHAR4Numbering(const Any& pAny, short numberingLevel,const OUString& numberingPrefix,OLECHAR* pChar)
{
	if(pChar == NULL)
		return;
	Reference< ::com::sun::star::container::XIndexReplace > pXIndex;
	if((pAny>>=pXIndex) && (numberingLevel !=-1))//numbering level is -1,means invalid value
	{
		Any aAny = pXIndex->getByIndex(numberingLevel);
		Sequence< ::com::sun::star::beans::PropertyValue > aProps;
		aAny >>= aProps;
		const ::com::sun::star::beans::PropertyValue* pPropArray = aProps.getConstArray();
		sal_Int32 nCount = aProps.getLength();
		swprintf(pChar,L"Numbering:NumberingLevel=%d,",numberingLevel);
		for( sal_Int32 i=0; i<nCount; i++ )
		{
			::com::sun::star::beans::PropertyValue rProp = pPropArray[i];
			if(	(rProp.Name.compareTo(OUString::createFromAscii("BulletChar"))==0)||
				(rProp.Name.compareTo(OUString::createFromAscii("GraphicURL"))==0)||
				(rProp.Name.compareTo(OUString::createFromAscii("NumberingType"))==0))
			{
				OLECHAR propStr[512] = {NULL};
				swprintf(propStr,L"%s=",rProp.Name.getStr());
				OLECHAR pTemp[256] = {NULL};
				CMAccessible::get_OLECHARFromAny(rProp.Value,pTemp);
				if(rProp.Name.compareTo(OUString::createFromAscii("GraphicURL"))==0)
				{
					OLECHAR* pOccur = wcschr(pTemp,':');
					if(pOccur)
						*pOccur = '.';
				}
				wcscat(propStr,pTemp);
				wcscat(pChar,propStr);
				wcscat(pChar,L",");

				if(rProp.Name.compareTo(OUString::createFromAscii("NumberingType"))==0)
				{
					if(numberingPrefix.getLength()!=0)
					{
						swprintf(pTemp,L"NumberingPrefix=%s,",numberingPrefix.getStr());
						wcscat(pChar,pTemp);
					}
				}
			}
		}
	}

	//Because now have three types numbering level:
	//1.real numbering list,numbering level>=0 and numbering Rule !=NULL;
	//2.common paragraph, numbering level >=0, and numbering Rule == NULL;
	//3.TOC paragraph, numbering level >0, and numbering Rule ==NULL;
	// IAText:numberinglevel base on 0, but TOC's level base on 1,
	// so NumberingLevel value will be decreased 1 in bridge code.
	else if(numberingLevel >0)
	{
		swprintf(pChar,L"Numbering:NumberingLevel=%d,NumberingType=4,NumberingPrefix=,",numberingLevel-1);
	}
	else
	{
		swprintf(pChar,L"Numbering:");
	}
}

void CMAccessible::ConvertAnyToVariant(const ::com::sun::star::uno::Any &rAnyVal, VARIANT *pvData)
{
	if(rAnyVal.hasValue())
	{
		// Clear VARIANT variable.
		VariantClear(pvData);

		// Set value according to value type.
		switch(rAnyVal.getValueTypeClass())
		{
		case TypeClass_CHAR:
			pvData->vt = VT_UI1;
			memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Char));
			break;

		case TypeClass_BOOLEAN:
			pvData->vt = VT_BOOL;
			memcpy(&pvData->boolVal, rAnyVal.getValue(), sizeof(sal_Bool));
			break;

		case TypeClass_BYTE:
			pvData->vt = VT_UI1;
			memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Int8));
			break;

		case TypeClass_SHORT:
			pvData->vt = VT_I2;
			memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_Int16));
			break;

		case TypeClass_UNSIGNED_SHORT:
			pvData->vt = VT_I2;
			memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_uInt16));
			break;

		case TypeClass_LONG:
			pvData->vt = VT_I4;
			memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_Int32));
			break;

		case TypeClass_UNSIGNED_LONG:
			pvData->vt = VT_I4;
			memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_uInt32));
			break;

		case TypeClass_FLOAT:
			pvData->vt = VT_R4;
			memcpy(&pvData->fltVal, rAnyVal.getValue(), sizeof(float));
			break;

		case TypeClass_DOUBLE:
			pvData->vt = VT_R8;
			memcpy(&pvData->dblVal, rAnyVal.getValue(), sizeof(double));
			break;

		case TypeClass_STRING:
			{
				pvData->vt = VT_BSTR;
				::rtl::OUString val;
				rAnyVal >>= val;
				pvData->bstrVal = SysAllocString((OLECHAR *)val.getStr());
				break;
			}

		case TypeClass_VOID:
		case TypeClass_HYPER:
		case TypeClass_UNSIGNED_HYPER:
		case TypeClass_TYPE:
		case TypeClass_ANY:
		case TypeClass_ENUM:
		case TypeClass_TYPEDEF:
		case TypeClass_STRUCT:
		case TypeClass_UNION:
		case TypeClass_EXCEPTION:
		case TypeClass_SEQUENCE:
		case TypeClass_ARRAY:
		case TypeClass_INTERFACE:
			{
				Reference< XAccessible > pXAcc;
				if(rAnyVal >>= pXAcc)
				{
					if(pXAcc.is())
					{
						IAccessible* pIAcc = NULL;
						get_IAccessibleFromXAccessible((long)pXAcc.get(), &pIAcc);
						if(pIAcc == NULL)
						{
							Reference< XAccessibleContext > pXAccContext = pXAcc->getAccessibleContext();
							g_pAgent->InsertAccObj(pXAcc.get(),pXAccContext->getAccessibleParent().get());
							get_IAccessibleFromXAccessible((long)pXAcc.get(), &pIAcc);
						}
						if(pIAcc)
						{
							pIAcc->AddRef();

							pvData->vt = VT_UNKNOWN;
							pvData->pdispVal = (IAccessible2*)pIAcc;
							break;
						}
					}
				}
			}
		case TypeClass_SERVICE:
		case TypeClass_MODULE:
		case TypeClass_INTERFACE_METHOD:
		case TypeClass_INTERFACE_ATTRIBUTE:
		case TypeClass_UNKNOWN:
		case TypeClass_PROPERTY:
		case TypeClass_CONSTANT:
		case TypeClass_CONSTANTS:
		case TypeClass_SINGLETON:
		case TypeClass_MAKE_FIXED_SIZE:
			// Output the type string, if there is other uno value type.
			pvData->vt = VT_BSTR;
			pvData->bstrVal = SysAllocString(rAnyVal.getValueTypeName().getStr());
			break;

		default:
			break;
		}
	}
	else
	{
		VariantClear(pvData);
	}
}

STDMETHODIMP CMAccessible::Get_XAccChildID(long* childID)
{
	// #CHECK#
	if(childID == NULL)
	{
		return E_FAIL;
	}
	*childID = m_dChildID;
	return S_OK;
}
STDMETHODIMP CMAccessible:: get_states(AccessibleStates __RPC_FAR *states )
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK XInterface#
		if( !pRContext.is() )
			return E_FAIL;

	Reference<XAccessibleStateSet> pRStateSet = pRContext.get()->getAccessibleStateSet();
	if(!pRStateSet.is())
	{
		return S_OK;
	}
	Sequence<short> pStates = pRStateSet->getStates();


	long count = pStates.getLength() ;
	*states = 0x0;
	for( int i = 0; i < count; i++  )
	{
		for( int j = 0; j < sizeof(UNO_STATES) / sizeof(UNO_STATES[0]); j++ )
		{
			if( pStates[i] == UNO_STATES[j] )
			{
				*states |= IA2_STATES[j];
				break;
			}
		}
	}
	return S_OK;


	LEAVE_PROTECTED_BLOCK
}

// return the UNO roles
STDMETHODIMP CMAccessible:: get_extendedRole( BSTR __RPC_FAR *  )
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()

		return E_NOTIMPL;

	LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible:: get_localizedExtendedRole( BSTR __RPC_FAR *  )
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		return E_NOTIMPL;

	LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_nExtendedStates( long __RPC_FAR * )
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()

		return E_NOTIMPL;

	LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_localizedExtendedStates( long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		return E_NOTIMPL;

	LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_indexInParent( long __RPC_FAR *accParentIndex)
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		// #CHECK#
		if(accParentIndex == NULL)
			return E_INVALIDARG;

	// #CHECK XInterface#
	if( !pRContext.is() )
		return E_FAIL;

	*accParentIndex = pRContext.get()->getAccessibleIndexInParent();
	return S_OK;


	LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_locale( IA2Locale __RPC_FAR *locale  )
{

	CHECK_ENABLE_INF
		ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(locale == NULL)
			return E_INVALIDARG;
	// #CHECK XInterface#

	if( !pRContext.is() )
		return E_FAIL;

	::com::sun::star::lang::Locale unoLoc = pRContext.get()->getLocale();
	locale->language = SysAllocString((OLECHAR*)unoLoc.Language.getStr());
	locale->country = SysAllocString((OLECHAR*)unoLoc.Country.getStr());
	locale->variant = SysAllocString((OLECHAR*)unoLoc.Variant.getStr());

	return S_OK;

	LEAVE_PROTECTED_BLOCK
}

DWORD GetMSAAStateFromUNO(short xState)
{
	DWORD IState = STATE_SYSTEM_UNAVAILABLE;
	switch( xState )
	{
	case /*AccessibleStateType::*/AccessibleStateType::BUSY:
		IState = STATE_SYSTEM_BUSY;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::CHECKED:
		IState = STATE_SYSTEM_CHECKED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::DEFUNC:
		IState = STATE_SYSTEM_UNAVAILABLE;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::EXPANDED:
		IState = STATE_SYSTEM_EXPANDED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::FOCUSABLE:
		IState = STATE_SYSTEM_FOCUSABLE;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::FOCUSED:
		IState = STATE_SYSTEM_FOCUSED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::INDETERMINATE:
		IState = STATE_SYSTEM_MIXED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::MULTI_SELECTABLE:
		IState = STATE_SYSTEM_MULTISELECTABLE;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::PRESSED:
		IState = STATE_SYSTEM_PRESSED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::RESIZABLE:
		IState = STATE_SYSTEM_SIZEABLE;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::SELECTABLE:
		IState = STATE_SYSTEM_SELECTABLE;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::SELECTED:
		IState = STATE_SYSTEM_SELECTED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::ARMED:
		IState = STATE_SYSTEM_FOCUSED;
		break;
	case /*AccessibleStateType::*/AccessibleStateType::EXPANDABLE:
		IState = STATE_SYSTEM_COLLAPSED;
		break;
	default:
		break;
	}
	return IState;
}

STDMETHODIMP CMAccessible:: get_appName( BSTR __RPC_FAR *name)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(name == NULL)
			return E_INVALIDARG;

	*name = SysAllocString(OLESTR("Hannover"));
	return S_OK;
	LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_appVersion(BSTR __RPC_FAR *version)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(version == NULL)
			return E_INVALIDARG;
	*version=SysAllocString(OLESTR("3.0"));
	return S_OK;
	LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_toolkitName(BSTR __RPC_FAR *name)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(name == NULL)
			return E_INVALIDARG;
	*name = SysAllocString(OLESTR(" "));
	return S_OK;
	LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_toolkitVersion(BSTR __RPC_FAR *version)
{

	ENTER_PROTECTED_BLOCK
		ISDESTROY()
		if(version == NULL)
			return E_INVALIDARG;
	*version = SysAllocString(OLESTR(" "));
	return S_OK;
	LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible::get_attributes(/*[out]*/ BSTR *pAttr)
{
	CHECK_ENABLE_INF
		Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
	if( !pRContext.is() )
	{
		return E_FAIL;
	}
	Reference<XAccessibleExtendedAttributes> pRXI(pRContext,UNO_QUERY);
	if( !pRXI.is() )
		return E_FAIL;
	else
	{
		com::sun::star::uno::Reference<com::sun::star::accessibility::XAccessibleExtendedAttributes> pRXAttr;
		pRXAttr = pRXI.get();
		::com::sun::star::uno::Any	anyVal = pRXAttr->getExtendedAttributes();

		::rtl::OUString val;
		anyVal >>= val;

		if(*pAttr)
			SAFE_SYSFREESTRING(*pAttr);
		*pAttr = SysAllocString((OLECHAR *)val.getStr());

		return S_OK;
	}
}