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



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

#include "dbexchange.hxx"
#include <sot/formats.hxx>
#include <sot/storage.hxx>
#include <osl/diagnose.h>
#include <com/sun/star/sdb/CommandType.hpp>
#include <com/sun/star/sdb/XResultSetAccess.hpp>
#include "TokenWriter.hxx"
#include "dbustrings.hrc"
#include <comphelper/uno3.hxx>
#include <svx/dataaccessdescriptor.hxx>
#include "UITools.hxx"


namespace dbaui
{
	using namespace ::com::sun::star::uno;
	using namespace ::com::sun::star::beans;
	using namespace ::com::sun::star::sdb;
	using namespace ::com::sun::star::beans;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::util;
	using namespace ::com::sun::star::sdbc;
	using namespace ::com::sun::star::datatransfer;
	using namespace ::svx;

	namespace 
	{
		template<class T > void lcl_setListener(const Reference<T>& _xComponent, const Reference< XEventListener >& i_rListener, const bool i_bAdd )
		{
			if ( !_xComponent.is() )
                return;

            Reference< XComponent> xCom( _xComponent, UNO_QUERY );
            OSL_ENSURE( xCom.is(), "lcl_setListener: no component!" );
			if ( !xCom.is() )
                return;

            i_bAdd ? xCom->addEventListener( i_rListener ) : xCom->removeEventListener( i_rListener );
		}
	}
		
	// -----------------------------------------------------------------------------
	ODataClipboard::ODataClipboard(
					const ::rtl::OUString&	_rDatasource,
					const sal_Int32			_nCommandType,
					const ::rtl::OUString&	_rCommand,
					const Reference< XConnection >& _rxConnection,
					const Reference< XNumberFormatter >& _rxFormatter,
					const Reference< XMultiServiceFactory >& _rxORB)
					:ODataAccessObjectTransferable( _rDatasource,::rtl::OUString(), _nCommandType, _rCommand, _rxConnection )
		,m_pHtml(NULL)
		,m_pRtf(NULL)
	{
		osl_incrementInterlockedCount( &m_refCount );
		lcl_setListener( _rxConnection, this, true );

		m_pHtml.set( new OHTMLImportExport( getDescriptor(), _rxORB, _rxFormatter ) );
		m_pRtf.set( new ORTFImportExport( getDescriptor(), _rxORB, _rxFormatter ) );

        osl_decrementInterlockedCount( &m_refCount );
	}

	// -----------------------------------------------------------------------------
	ODataClipboard::ODataClipboard(
					const ::rtl::OUString&	_rDatasource,
					const sal_Int32			_nCommandType,
					const ::rtl::OUString&	_rCommand,
					const Reference< XNumberFormatter >& _rxFormatter,
					const Reference< XMultiServiceFactory >& _rxORB)
		:ODataAccessObjectTransferable( _rDatasource, ::rtl::OUString(),_nCommandType, _rCommand)
		,m_pHtml(NULL)
		,m_pRtf(NULL)
	{
		m_pHtml.set( new OHTMLImportExport( getDescriptor(),_rxORB, _rxFormatter ) );
		m_pRtf.set( new ORTFImportExport( getDescriptor(),_rxORB, _rxFormatter ) );
	}

	// -----------------------------------------------------------------------------
    ODataClipboard::ODataClipboard(	const Reference< XPropertySet >& i_rAliveForm,
                                    const Sequence< Any >& i_rSelectedRows,
                                    const sal_Bool i_bBookmarkSelection,
                                    const Reference< XMultiServiceFactory >& i_rORB )
        :ODataAccessObjectTransferable( i_rAliveForm )
        ,m_pHtml(NULL)
        ,m_pRtf(NULL)
    {
        OSL_PRECOND( i_rORB.is(), "ODataClipboard::ODataClipboard: having no factory is not good ..." );

        osl_incrementInterlockedCount( &m_refCount );
        
        Reference<XConnection> xConnection;
        getDescriptor()[ daConnection ] >>= xConnection;
        lcl_setListener( xConnection, this, true );

        // do not pass the form itself as source result set, since the client might operate on the form, which
        // might lead to undesired effects. Instead, use a clone.
        Reference< XResultSet > xResultSetClone;
		Reference< XResultSetAccess > xResultSetAccess( i_rAliveForm, UNO_QUERY );
		if ( xResultSetAccess.is() )
			xResultSetClone = xResultSetAccess->createResultSet();
        OSL_ENSURE( xResultSetClone.is(), "ODataClipboard::ODataClipboard: could not clone the form's result set" );
        lcl_setListener( xResultSetClone, this, true );

        getDescriptor()[daCursor]			<<= xResultSetClone;
        getDescriptor()[daSelection]		<<= i_rSelectedRows;
        getDescriptor()[daBookmarkSelection]<<= i_bBookmarkSelection;
        addCompatibleSelectionDescription( i_rSelectedRows );

        if ( xConnection.is() && i_rORB.is() )
        {
            Reference< XNumberFormatter > xFormatter( getNumberFormatter( xConnection, i_rORB ) );
            if ( xFormatter.is() )
            {
                m_pHtml.set( new OHTMLImportExport( getDescriptor(), i_rORB, xFormatter ) );
                m_pRtf.set( new ORTFImportExport( getDescriptor(), i_rORB, xFormatter ) );
            }
        }

        osl_decrementInterlockedCount( &m_refCount );
    }

	// -----------------------------------------------------------------------------
	sal_Bool ODataClipboard::WriteObject( SotStorageStreamRef& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const ::com::sun::star::datatransfer::DataFlavor& /*rFlavor*/ )
	{
		if (nUserObjectId == SOT_FORMAT_RTF || nUserObjectId == SOT_FORMATSTR_ID_HTML )
		{
			ODatabaseImportExport* pExport = reinterpret_cast<ODatabaseImportExport*>(pUserObject);
			if ( pExport && rxOStm.Is() )
			{
				pExport->setStream(&rxOStm);
				return pExport->Write();
			}
		}
		return sal_False;
	}

	// -----------------------------------------------------------------------------
	void ODataClipboard::AddSupportedFormats()
	{
		if ( m_pRtf.is() )
			AddFormat( SOT_FORMAT_RTF );

		if ( m_pHtml.is() )
			AddFormat( SOT_FORMATSTR_ID_HTML );

		ODataAccessObjectTransferable::AddSupportedFormats();
	}

	// -----------------------------------------------------------------------------
	sal_Bool ODataClipboard::GetData( const DataFlavor& rFlavor )
	{
		const sal_uLong nFormat = SotExchange::GetFormat(rFlavor);
		switch (nFormat)
		{
			case SOT_FORMAT_RTF:
                if ( m_pRtf.is() )
				    m_pRtf->initialize(getDescriptor());
			    return m_pRtf.is() && SetObject( m_pRtf.get(), SOT_FORMAT_RTF, rFlavor );

            case SOT_FORMATSTR_ID_HTML:
                if ( m_pHtml.is() )
				    m_pHtml->initialize(getDescriptor());
			    return m_pHtml.is() && SetObject( m_pHtml.get(), SOT_FORMATSTR_ID_HTML, rFlavor );
		}

		return ODataAccessObjectTransferable::GetData( rFlavor );
	}

	// -----------------------------------------------------------------------------
	void ODataClipboard::ObjectReleased()
	{
        if ( m_pHtml.is() )
        {
            m_pHtml->dispose();
		    m_pHtml.clear();
        }

        if ( m_pRtf.is() )
        {
            m_pRtf->dispose();
		    m_pRtf.clear();
        }

        if ( getDescriptor().has( daConnection ) )
        {
            Reference<XConnection> xConnection( getDescriptor()[daConnection], UNO_QUERY );
			lcl_setListener( xConnection, this, false );
        }

		if ( getDescriptor().has( daCursor ) )
        {
            Reference< XResultSet > xResultSet( getDescriptor()[ daCursor ], UNO_QUERY );
			lcl_setListener( xResultSet, this, false );
        }

		ODataAccessObjectTransferable::ObjectReleased( );
	}

	// -----------------------------------------------------------------------------
	void SAL_CALL ODataClipboard::disposing( const ::com::sun::star::lang::EventObject& i_rSource ) throw (::com::sun::star::uno::RuntimeException)
	{
        ODataAccessDescriptor& rDescriptor( getDescriptor() );

		if ( rDescriptor.has( daConnection ) )
        {
            Reference< XConnection > xConnection( rDescriptor[daConnection], UNO_QUERY );
            if ( xConnection == i_rSource.Source )
            {
                rDescriptor.erase( daConnection );
            }
        }

		if ( rDescriptor.has( daCursor ) )
        {
            Reference< XResultSet > xResultSet( rDescriptor[ daCursor ], UNO_QUERY );
            if ( xResultSet == i_rSource.Source )
            {
                rDescriptor.erase( daCursor );
                // Selection and BookmarkSelection are meaningless without a result set
                if ( rDescriptor.has( daSelection ) )
                    rDescriptor.erase( daSelection );
                if ( rDescriptor.has( daBookmarkSelection ) )
                    rDescriptor.erase( daBookmarkSelection );
            }
        }

        // no matter whether it was the source connection or the source result set which died,
        // we cannot provide the data anymore.
        ClearFormats();
	}
}