/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright IBM Corporation 2010.
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

//add by duan mei hua, 2006/09/04, for issue 174
#ifndef _SVTRULERACCESSIBLE_HXX
#include <svtools/accessibleruler.hxx>
#endif
//end add by duan mei hua, 2006/09/04, for issue 174
#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEEVENTID_HPP_
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#endif
#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX_
#include <unotools/accessiblestatesethelper.hxx>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#endif

#ifndef	_COM_SUN_STAR_BEANS_PROPERTYCHANGEEVENT_HPP_
#include <com/sun/star/beans/PropertyChangeEvent.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif

#ifndef _CPPUHELPER_TYPEPROVIDER_HXX_
#include <cppuhelper/typeprovider.hxx>
#endif

#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/helper/vclunohelper.hxx>
#endif
#ifndef _TOOLKIT_HELPER_CONVERT_HXX_
#include <toolkit/helper/convert.hxx>
#endif

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
#ifndef _RTL_UUID_H_
#include <rtl/uuid.h>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif

#include "ruler.hxx"

#ifndef COMPHELPER_ACCESSIBLE_EVENT_NOTIFIER
#include <comphelper/accessibleeventnotifier.hxx>
#endif

using namespace ::cppu;
using namespace ::osl;
using namespace	::rtl;
using namespace	::com::sun::star;
using namespace	::com::sun::star::uno;
using namespace	::com::sun::star::accessibility;

DBG_NAME( SvtRulerAccessible )


//=====  internal  ============================================================

SvtRulerAccessible::SvtRulerAccessible(
	const uno::Reference< XAccessible >& rxParent, Ruler& rRepr, const OUString& rName ) :

	SvtRulerAccessible_Base( m_aMutex ),
	msName( rName ),
	mxParent( rxParent ),
	mpRepr( &rRepr ),
    mnClientId( 0 )
{
	DBG_CTOR( SvtRulerAccessible, NULL );
}

SvtRulerAccessible::~SvtRulerAccessible()
{
	DBG_DTOR( SvtRulerAccessible, NULL );

	if( IsAlive() )
	{
		osl_incrementInterlockedCount( &m_refCount );
		dispose();		// set mpRepr = NULL & release all childs
	}
}

//=====  XAccessible  =========================================================

uno::Reference< XAccessibleContext > SAL_CALL SvtRulerAccessible::getAccessibleContext( void ) throw( RuntimeException )
{
	return this;
}

//=====  XAccessibleComponent  ================================================

sal_Bool SAL_CALL SvtRulerAccessible::containsPoint( const awt::Point& rPoint ) throw( RuntimeException )
{
	// no guard -> done in getBounds()
//	return GetBoundingBox().IsInside( VCLPoint( rPoint ) );
	return Rectangle( Point( 0, 0 ), GetBoundingBox().GetSize() ).IsInside( VCLPoint( rPoint ) );
}

uno::Reference< XAccessible > SAL_CALL SvtRulerAccessible::getAccessibleAtPoint( const awt::Point& ) throw( RuntimeException )
{
	::osl::MutexGuard			aGuard( m_aMutex );

	ThrowExceptionIfNotAlive();

	uno::Reference< XAccessible >	xRet;


	return xRet;
}

awt::Rectangle SAL_CALL SvtRulerAccessible::getBounds() throw( RuntimeException )
{
	// no guard -> done in GetBoundingBox()
	return AWTRectangle( GetBoundingBox() );
}

awt::Point SAL_CALL SvtRulerAccessible::getLocation() throw( RuntimeException )
{
	// no guard -> done in GetBoundingBox()
	return AWTPoint( GetBoundingBox().TopLeft() );
}

awt::Point SAL_CALL SvtRulerAccessible::getLocationOnScreen() throw( RuntimeException )
{
	// no guard -> done in GetBoundingBoxOnScreen()
	return AWTPoint( GetBoundingBoxOnScreen().TopLeft() );
}

awt::Size SAL_CALL SvtRulerAccessible::getSize() throw( RuntimeException )
{
	// no guard -> done in GetBoundingBox()
	return AWTSize( GetBoundingBox().GetSize() );
}

sal_Bool SAL_CALL SvtRulerAccessible::isShowing() throw( RuntimeException )
{
	return sal_True;
}

sal_Bool SAL_CALL SvtRulerAccessible::isVisible() throw( RuntimeException )
{
	::osl::MutexGuard			aGuard( m_aMutex );

	ThrowExceptionIfNotAlive();

	return mpRepr->IsVisible();
}

sal_Bool SAL_CALL SvtRulerAccessible::isFocusTraversable() throw( RuntimeException )
{
	return sal_True;
}

//=====  XAccessibleContext  ==================================================

sal_Int32 SAL_CALL SvtRulerAccessible::getAccessibleChildCount( void ) throw( RuntimeException )
{
	::osl::MutexGuard	aGuard( m_aMutex );

	ThrowExceptionIfNotAlive();

	return 0;
}

uno::Reference< XAccessible > SAL_CALL SvtRulerAccessible::getAccessibleChild( sal_Int32 )
	throw( RuntimeException, lang::IndexOutOfBoundsException )
{
	uno::Reference< XAccessible >	xChild ;

	return xChild;
}

uno::Reference< XAccessible > SAL_CALL SvtRulerAccessible::getAccessibleParent( void ) throw( RuntimeException )
{
	return mxParent;
}

sal_Int32 SAL_CALL SvtRulerAccessible::getAccessibleIndexInParent( void ) throw( RuntimeException )
{
	::osl::MutexGuard	aGuard( m_aMutex );
	//	Use a simple but slow solution for now.  Optimize later.

    //	Iterate over all the parent's children and search for this object.
    if( mxParent.is() )
    {
    	uno::Reference< XAccessibleContext >		xParentContext( mxParent->getAccessibleContext() );
        if( xParentContext.is() )
        {
        	sal_Int32						nChildCount = xParentContext->getAccessibleChildCount();
            for( sal_Int32 i = 0 ; i < nChildCount ; ++i )
            {
            	uno::Reference< XAccessible >	xChild( xParentContext->getAccessibleChild( i ) );
				if( xChild.get() == ( XAccessible* ) this )
                    return i;
            }
        }
   }

   //	Return -1 to indicate that this object's parent does not know about the
   //	object.
   return -1;
}

sal_Int16 SAL_CALL SvtRulerAccessible::getAccessibleRole( void ) throw( RuntimeException )
{
	return AccessibleRole::RULER;
}

OUString SAL_CALL SvtRulerAccessible::getAccessibleDescription( void ) throw( RuntimeException )
{
	::osl::MutexGuard	aGuard( m_aMutex );
	return msDescription;
}

OUString SAL_CALL SvtRulerAccessible::getAccessibleName( void ) throw( RuntimeException )
{
	::osl::MutexGuard	aGuard( m_aMutex );
	return msName;
}

/**	Return empty uno::Reference to indicate that the relation set is not
	supported.
*/
uno::Reference< XAccessibleRelationSet > SAL_CALL SvtRulerAccessible::getAccessibleRelationSet( void ) throw( RuntimeException )
{
	return uno::Reference< XAccessibleRelationSet >();
}


uno::Reference< XAccessibleStateSet > SAL_CALL SvtRulerAccessible::getAccessibleStateSet( void ) throw( RuntimeException )
{
	::osl::MutexGuard						aGuard( m_aMutex );
	utl::AccessibleStateSetHelper*			pStateSetHelper = new utl::AccessibleStateSetHelper;

	if( IsAlive() )
	{
		pStateSetHelper->AddState( AccessibleStateType::ENABLED );
				
		if( isShowing() )
			pStateSetHelper->AddState( AccessibleStateType::SHOWING );

		if( isVisible() )
			pStateSetHelper->AddState( AccessibleStateType::VISIBLE );

		
		if ( mpRepr )
		{
			if ( mpRepr->GetStyle() & WB_HORZ )
				pStateSetHelper->AddState( AccessibleStateType::HORIZONTAL );
			else 
				pStateSetHelper->AddState( AccessibleStateType::VERTICAL );
		}
		if(pStateSetHelper->contains(AccessibleStateType::FOCUSABLE))
		{
			pStateSetHelper->RemoveState( AccessibleStateType::FOCUSABLE );
		}

	}
	

	return pStateSetHelper;
}

lang::Locale SAL_CALL SvtRulerAccessible::getLocale( void ) throw( IllegalAccessibleComponentStateException, RuntimeException )
{
	::osl::MutexGuard							aGuard( m_aMutex );
	if( mxParent.is() )
    {
    	uno::Reference< XAccessibleContext >	xParentContext( mxParent->getAccessibleContext() );
        if( xParentContext.is() )
	    	return xParentContext->getLocale();
    }

    //	No parent.  Therefore throw exception to indicate this cluelessness.
    throw IllegalAccessibleComponentStateException();
}

void SAL_CALL SvtRulerAccessible::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
    throw( RuntimeException )
{
	if (xListener.is())
    {
		::osl::MutexGuard	aGuard( m_aMutex );
		if (!mnClientId)
            mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
		comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
    }
}

void SAL_CALL SvtRulerAccessible::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener )
    throw( RuntimeException )
{
	if (xListener.is())
	{
    	::osl::MutexGuard	aGuard( m_aMutex );

        sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
		if ( !nListenerCount )
		{
			// no listeners anymore
			// -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
			// and at least to us not firing any events anymore, in case somebody calls
			// NotifyAccessibleEvent, again
			comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
			mnClientId = 0;
		}
	}
}

void SAL_CALL SvtRulerAccessible::addFocusListener( const uno::Reference< awt::XFocusListener >& xListener )
	throw( RuntimeException )
{
	if( xListener.is() )
    {
		::osl::MutexGuard	aGuard( m_aMutex );

		ThrowExceptionIfNotAlive();

		uno::Reference< awt::XWindow >	xWindow = VCLUnoHelper::GetInterface( mpRepr );
		if( xWindow.is() )
			xWindow->addFocusListener( xListener );
    }
}

void SAL_CALL SvtRulerAccessible::removeFocusListener( const uno::Reference< awt::XFocusListener >& xListener )
	throw (RuntimeException)
{
	if( xListener.is() )
    {
		::osl::MutexGuard	aGuard( m_aMutex );

		ThrowExceptionIfNotAlive();

		uno::Reference< awt::XWindow >	xWindow = VCLUnoHelper::GetInterface( mpRepr );
		if( xWindow.is() )
			xWindow->removeFocusListener( xListener );
    }
}

void SAL_CALL SvtRulerAccessible::grabFocus() throw( RuntimeException )
{
	::vos::OGuard		aSolarGuard( Application::GetSolarMutex() );
	::osl::MutexGuard	aGuard( m_aMutex );

	ThrowExceptionIfNotAlive();

	mpRepr->GrabFocus();
}

Any SAL_CALL SvtRulerAccessible::getAccessibleKeyBinding() throw( RuntimeException )
{
	// here is no implementation, because here are no KeyBindings for every object
	return Any();
}

sal_Int32 SvtRulerAccessible::getForeground(  ) 
        throw (::com::sun::star::uno::RuntimeException)
{
    ::vos::OGuard       aSolarGuard( Application::GetSolarMutex() );
    ::osl::MutexGuard   aGuard( m_aMutex );
    ThrowExceptionIfNotAlive();
    
    return mpRepr->GetControlForeground().GetColor();
}
sal_Int32 SvtRulerAccessible::getBackground(  ) 
        throw (::com::sun::star::uno::RuntimeException)
{
    ::vos::OGuard       aSolarGuard( Application::GetSolarMutex() );
    ::osl::MutexGuard   aGuard( m_aMutex );
    ThrowExceptionIfNotAlive();

    return mpRepr->GetControlBackground().GetColor();
}

//=====  XServiceInfo  ========================================================

OUString SAL_CALL SvtRulerAccessible::getImplementationName( void ) throw( RuntimeException )
{
	return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.ui.SvtRulerAccessible" ) );
}

sal_Bool SAL_CALL SvtRulerAccessible::supportsService( const OUString& sServiceName ) throw( RuntimeException )
{
	::osl::MutexGuard	aGuard( m_aMutex );
    //  Iterate over all supported service names and return true if on of them
    //  matches the given name.
    Sequence< OUString >	aSupportedServices( getSupportedServiceNames() );
	int						nLength = aSupportedServices.getLength();
	const OUString*			pStr = aSupportedServices.getConstArray();

    for( int i = nLength ; i ; --i, ++pStr )
	{
        if( sServiceName == *pStr )
            return sal_True;
	}

    return sal_False;
}

Sequence< OUString > SAL_CALL SvtRulerAccessible::getSupportedServiceNames( void ) throw( RuntimeException )
{
	const OUString sServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.accessibility.AccessibleContext" ) );
	return Sequence< OUString >( &sServiceName, 1 );
}

//=====  XTypeProvider  =======================================================

Sequence< sal_Int8 > SAL_CALL SvtRulerAccessible::getImplementationId( void ) throw( RuntimeException )
{
	return getUniqueId();
}


//=====  internals ========================================================

void SvtRulerAccessible::setName( const OUString& rName )
{
		msName = rName;

}

void SvtRulerAccessible::setDescription( const OUString& rDescr )
{

		msDescription = rDescr;

}



void SAL_CALL SvtRulerAccessible::disposing()
{
	if( !rBHelper.bDisposed )
	{
		{
			::osl::MutexGuard	aGuard( m_aMutex );
			mpRepr = NULL;		// object dies with representation

		}

		{
			::osl::MutexGuard	aGuard( m_aMutex );

            // Send a disposing to all listeners.
	        if ( mnClientId )
	        {
                comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
		        mnClientId =  0;
	        }
			mxParent = uno::Reference< XAccessible >();
		}
	}
}

Rectangle SvtRulerAccessible::GetBoundingBoxOnScreen( void ) throw( RuntimeException )
{
	::vos::OGuard		aSolarGuard( Application::GetSolarMutex() );
	::osl::MutexGuard	aGuard( m_aMutex );

	ThrowExceptionIfNotAlive();
//IAccessibility2 Implementation 2009-----
	//Modified by Li Xing, 2007/03/26, SODC_7333, the absolute on screen pixel is wrong
	//return Rectangle( mpRepr->GetParent()->OutputToScreenPixel( mpRepr->GetPosPixel() ), mpRepr->GetSizePixel() );
	return Rectangle( mpRepr->GetParent()->OutputToAbsoluteScreenPixel( mpRepr->GetPosPixel() ), mpRepr->GetSizePixel() );
	//Ended by Li Xing, 2007/03/26, SODC_7333.
//-----IAccessibility2 Implementation 2009
}

Rectangle SvtRulerAccessible::GetBoundingBox( void ) throw( RuntimeException )
{
	::vos::OGuard		aSolarGuard( Application::GetSolarMutex() );
	::osl::MutexGuard	aGuard( m_aMutex );

	ThrowExceptionIfNotAlive();

	return Rectangle( mpRepr->GetPosPixel(), mpRepr->GetSizePixel() );
}

Sequence< sal_Int8 > SvtRulerAccessible::getUniqueId( void )
{
	static OImplementationId*	pId = 0;
	if( !pId )
	{
		MutexGuard						aGuard( Mutex::getGlobalMutex() );
		if( !pId)
		{
			static OImplementationId	aId;
			pId = &aId;
		}
	}
	return pId->getImplementationId();
}

void SvtRulerAccessible::ThrowExceptionIfNotAlive( void ) throw( lang::DisposedException )
{
	if( IsNotAlive() )
		throw lang::DisposedException();
}

void SvtRulerAccessible::addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener )throw( com::sun::star::uno::RuntimeException )
{
	cppu::WeakAggComponentImplHelperBase::addEventListener( xListener );
}

void SvtRulerAccessible::removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw( com::sun::star::uno::RuntimeException )
{
	cppu::WeakAggComponentImplHelperBase::removeEventListener( xListener );
}


// -------------------------------------------------------------------------------------------------