/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * 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.
 *
 ************************************************************************/

//  #define TRACE(x) OSL_TRACE(x)
#define TRACE(x)

#include <osl/diagnose.h>
#include <osl/mutex.hxx>
#include <cppuhelper/factory.hxx>
#include <cppuhelper/implbase2.hxx>
#include <cppuhelper/implementationentry.hxx>
#include "cppuhelper/unourl.hxx"
#include "rtl/malformeduriexception.hxx"

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/connection/XConnector.hpp>
#include <com/sun/star/bridge/XBridgeFactory.hpp>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>

using namespace cppu;
using namespace rtl;
using namespace osl;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::connection;
using namespace com::sun::star::bridge;
using namespace com::sun::star::registry;

#define SERVICENAME		"com.sun.star.bridge.UnoUrlResolver"
#define IMPLNAME		"com.sun.star.comp.bridge.UnoUrlResolver"

namespace unourl_resolver
{
	rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;
//--------------------------------------------------------------------------------------------------
Sequence< OUString > resolver_getSupportedServiceNames()
{
	static Sequence < OUString > *pNames = 0;
	if( ! pNames )
	{
		MutexGuard guard( Mutex::getGlobalMutex() );
		if( !pNames )
		{
			static Sequence< OUString > seqNames(1);
			seqNames.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM(SERVICENAME));
			pNames = &seqNames;
		}
	}
	return *pNames;
}

OUString resolver_getImplementationName()
{
	static OUString *pImplName = 0;
	if( ! pImplName )
	{
		MutexGuard guard( Mutex::getGlobalMutex() );
		if( ! pImplName )
		{
			static OUString implName(
				RTL_CONSTASCII_USTRINGPARAM( IMPLNAME ) );
			pImplName = &implName;
		}
	}
	return *pImplName;
}
	
//==================================================================================================
class ResolverImpl : public WeakImplHelper2< XServiceInfo, XUnoUrlResolver >
{
	Reference< XMultiComponentFactory > _xSMgr;
	Reference< XComponentContext > _xCtx;
	
public:
	ResolverImpl( const Reference< XComponentContext > & xSMgr );
	virtual ~ResolverImpl();
	
	// XServiceInfo
	virtual OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
	virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) throw(::com::sun::star::uno::RuntimeException);
	virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

	// XUnoUrlResolver
    virtual Reference< XInterface > SAL_CALL resolve( const OUString & rUnoUrl )
		throw (NoConnectException, ConnectionSetupException, RuntimeException);
};

//##################################################################################################

//__________________________________________________________________________________________________
ResolverImpl::ResolverImpl( const Reference< XComponentContext > & xCtx )
	: _xSMgr( xCtx->getServiceManager() )
	, _xCtx( xCtx )
{
	g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}
//__________________________________________________________________________________________________
ResolverImpl::~ResolverImpl()
{
	g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XServiceInfo
//__________________________________________________________________________________________________
OUString ResolverImpl::getImplementationName()
	throw(::com::sun::star::uno::RuntimeException)
{
	return resolver_getImplementationName();
}
//__________________________________________________________________________________________________
sal_Bool ResolverImpl::supportsService( const OUString & rServiceName )
	throw(::com::sun::star::uno::RuntimeException)
{
	const Sequence< OUString > & rSNL = getSupportedServiceNames();
	const OUString * pArray = rSNL.getConstArray();
	for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
	{
		if (pArray[nPos] == rServiceName)
			return sal_True;
	}
	return sal_False;
}
//__________________________________________________________________________________________________
Sequence< OUString > ResolverImpl::getSupportedServiceNames()
	throw(::com::sun::star::uno::RuntimeException)
{
	return resolver_getSupportedServiceNames();
}

// XUnoUrlResolver
//__________________________________________________________________________________________________
Reference< XInterface > ResolverImpl::resolve( const OUString & rUnoUrl )
	throw (NoConnectException, ConnectionSetupException, RuntimeException)
{
    OUString aProtocolDescr;
    OUString aConnectDescr;
    OUString aInstanceName;
    try
    {
        cppu::UnoUrl aUrl(rUnoUrl);
        aProtocolDescr = aUrl.getProtocol().getDescriptor();
        aConnectDescr = aUrl.getConnection().getDescriptor();
        aInstanceName = aUrl.getObjectName();
    }
    catch (rtl::MalformedUriException & rEx)
    {
        throw ConnectionSetupException(rEx.getMessage(), 0);
    }

	Reference< XConnector > xConnector(
		_xSMgr->createInstanceWithContext(
			OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.connection.Connector") ),
			_xCtx ),
		UNO_QUERY );
	
	if (! xConnector.is())
		throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM("no connector!" ) ), Reference< XInterface >() );
	
	Reference< XConnection > xConnection( xConnector->connect( aConnectDescr ) );

	// As soon as singletons are ready, switch to singleton !
	Reference< XBridgeFactory > xBridgeFactory(
		_xSMgr->createInstanceWithContext(
			OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.bridge.BridgeFactory") ),
			_xCtx ),
		UNO_QUERY );
	
	if (! xBridgeFactory.is())
		throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM("no bridge factory!" ) ), Reference< XInterface >() );
	
	// bridge
	Reference< XBridge > xBridge( xBridgeFactory->createBridge(
		OUString(), aProtocolDescr,
		xConnection, Reference< XInstanceProvider >() ) );
	
	Reference< XInterface > xRet( xBridge->getInstance( aInstanceName ) );
	
	return xRet;
}

//==================================================================================================
static Reference< XInterface > SAL_CALL ResolverImpl_create( const Reference< XComponentContext > & xCtx )
{
	return Reference< XInterface >( *new ResolverImpl( xCtx ) );
}


}

using namespace unourl_resolver;

static struct ImplementationEntry g_entries[] =
{
	{
		ResolverImpl_create, resolver_getImplementationName,
		resolver_getSupportedServiceNames, createSingleComponentFactory,
		&g_moduleCount.modCnt , 0
	},
	{ 0, 0, 0, 0, 0, 0 }
};

extern "C"
{
sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
{
	return g_moduleCount.canUnload( &g_moduleCount , pTime );
}

//==================================================================================================
void SAL_CALL component_getImplementationEnvironment(
	const sal_Char ** ppEnvTypeName, uno_Environment ** )
{
	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}
//==================================================================================================
void * SAL_CALL component_getFactory(
	const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
	return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
}
}