/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * 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.
 *
 ************************************************************************/

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

/**************************************************************************
                                TODO
 **************************************************************************

 *************************************************************************/

#ifndef __VECTOR__
#include <vector>
#endif
#include <com/sun/star/beans/Property.hpp>
#include <com/sun/star/beans/XPropertyAccess.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/script/XTypeConverter.hpp>

#include "osl/diagnose.h"
#include "osl/mutex.hxx"
#include <ucbhelper/propertyvalueset.hxx>

using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::io;
using namespace com::sun::star::lang;
using namespace com::sun::star::script;
using namespace com::sun::star::sdbc;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
using ::rtl::OUString;

namespace ucbhelper_impl
{

//=========================================================================
//
// PropertyValue.
//
//=========================================================================

const sal_uInt32 NO_VALUE_SET 				= 0x00000000;
const sal_uInt32 STRING_VALUE_SET 		 	= 0x00000001;
const sal_uInt32 BOOLEAN_VALUE_SET 		 	= 0x00000002;
const sal_uInt32 BYTE_VALUE_SET 			= 0x00000004;
const sal_uInt32 SHORT_VALUE_SET 			= 0x00000008;
const sal_uInt32 INT_VALUE_SET 			 	= 0x00000010;
const sal_uInt32 LONG_VALUE_SET 			= 0x00000020;
const sal_uInt32 FLOAT_VALUE_SET 			= 0x00000040;
const sal_uInt32 DOUBLE_VALUE_SET 		 	= 0x00000080;
const sal_uInt32 BYTES_VALUE_SET 			= 0x00000100;
const sal_uInt32 DATE_VALUE_SET 			= 0x00000200;
const sal_uInt32 TIME_VALUE_SET 			= 0x00000400;
const sal_uInt32 TIMESTAMP_VALUE_SET 		= 0x00000800;
const sal_uInt32 BINARYSTREAM_VALUE_SET 	= 0x00001000;
const sal_uInt32 CHARACTERSTREAM_VALUE_SET 	= 0x00002000;
const sal_uInt32 REF_VALUE_SET 			 	= 0x00004000;
const sal_uInt32 BLOB_VALUE_SET 			= 0x00008000;
const sal_uInt32 CLOB_VALUE_SET 			= 0x00010000;
const sal_uInt32 ARRAY_VALUE_SET 			= 0x00020000;
const sal_uInt32 OBJECT_VALUE_SET 		 	= 0x00040000;

struct PropertyValue
{
    ::rtl::OUString
                sPropertyName;

    sal_uInt32	nPropsSet;
    sal_uInt32  nOrigValue;

    OUString	aString;	// getString
    sal_Bool 	bBoolean;	// getBoolean
    sal_Int8	nByte;		// getByte
    sal_Int16	nShort;		// getShort
    sal_Int32 	nInt;		// getInt
    sal_Int64 	nLong;		// getLong
    float		nFloat;		// getFloat
    double		nDouble;	// getDouble

    Sequence< sal_Int8 > 		aBytes; 			// getBytes
    Date                		aDate;				// getDate
    Time                		aTime;				// getTime
    DateTime            		aTimestamp;			// getTimestamp
    Reference< XInputStream >	xBinaryStream;		// getBinaryStream
    Reference< XInputStream >	xCharacterStream;	// getCharacterStream
    Reference< XRef >			xRef;				// getRef
    Reference< XBlob >			xBlob;				// getBlob
    Reference< XClob >			xClob;				// getClob
    Reference< XArray >			xArray;				// getArray
    Any							aObject;			// getObject

    inline PropertyValue()
        : nPropsSet( NO_VALUE_SET ), nOrigValue( NO_VALUE_SET ),
          bBoolean(false),
          nByte(0),
          nShort(0),
          nInt(0),
          nLong(0),
          nFloat(0.0),
          nDouble(0.0)
        {}
};
} // namespace ucbhelper_impl

using namespace ucbhelper_impl;

namespace ucbhelper
{

//=========================================================================
//
// class PropertyValues.
//
//=========================================================================

typedef std::vector< ucbhelper_impl::PropertyValue > PropertyValuesVector;

class PropertyValues : public PropertyValuesVector {};

} // namespace ucbhelper

//=========================================================================
//
// Welcome to the macro hell...
//
//=========================================================================

#define GETVALUE_IMPL_TYPE( _type_, _type_name_, _member_name_, _cppu_type_ ) \
                                                                              \
    osl::MutexGuard aGuard( m_aMutex );                                       \
                                                                              \
    _type_ aValue = _type_();	/* default ctor	*/							  \
                                                                              \
    m_bWasNull = sal_True;                                					  \
                                                                              \
    if ( ( columnIndex < 1 )												  \
         || ( columnIndex > sal_Int32( m_pValues->size() ) ) )         		  \
    {                                                                         \
        OSL_FAIL( "PropertyValueSet - index out of range!" );    \
    }                                                                         \
    else                                                                      \
    {                                                                         \
        ucbhelper_impl::PropertyValue& rValue                                 \
            = (*m_pValues)[ columnIndex - 1 ];                                \
                                                                              \
        if ( rValue.nOrigValue != NO_VALUE_SET )							  \
        {                                                                     \
            if ( rValue.nPropsSet & _type_name_ )							  \
            {                                                                 \
                /* Values is present natively... */							  \
                aValue = rValue._member_name_;                                \
                m_bWasNull = sal_False;                   					  \
            }                                                                 \
            else                                                              \
            {                                                                 \
                if ( !(rValue.nPropsSet & OBJECT_VALUE_SET) )                 \
                {                                                             \
                    /* Value is not (yet) available as Any. Create it. */     \
                    getObject( columnIndex, Reference< XNameAccess >() );     \
                }                                                             \
                                                                              \
                if ( rValue.nPropsSet & OBJECT_VALUE_SET )                    \
                {															  \
                    /* Value is available as Any. */                          \
                                                                              \
                    if ( rValue.aObject.hasValue() )						  \
                    {                                                         \
                        /* Try to convert into native value. */               \
                        if ( rValue.aObject >>= aValue )                      \
                        {                                                     \
                            rValue._member_name_ = aValue;					  \
                            rValue.nPropsSet |= _type_name_;				  \
                            m_bWasNull = sal_False;           				  \
                        }                                                     \
                        else                                                  \
                        {                                                     \
                            /* Last chance. Try type converter service... */  \
                                                                              \
                            Reference< XTypeConverter > xConverter            \
                                                    = getTypeConverter(); 	  \
                            if ( xConverter.is() )                            \
                            {                                                 \
                                try                                           \
                                {                                             \
                                    Any aConvAny = xConverter->convertTo(     \
                                                             rValue.aObject,	  \
                                                            _cppu_type_ );	  \
                                                                              \
                                    if ( aConvAny >>= aValue )                \
                                    {                           			  \
                                        rValue._member_name_ = aValue;		  \
                                        rValue.nPropsSet |= _type_name_;      \
                                        m_bWasNull = sal_False;   			  \
                                    }                                         \
                                }                                             \
                                catch ( IllegalArgumentException )            \
                                {                                             \
                                }                                             \
                                catch ( CannotConvertException )              \
                                {                                             \
                                }                                             \
                            }                                                 \
                        }                                                     \
                    }                                                         \
                }                                                             \
            }                                                                 \
        }																	  \
    }                                                                         \
    return aValue;

#define GETVALUE_IMPL( _type_, _type_name_, _member_name_ )					  \
    GETVALUE_IMPL_TYPE( _type_,												  \
                        _type_name_,										  \
                        _member_name_,                                        \
                        getCppuType( static_cast< const _type_ * >( 0 ) ) )

#define SETVALUE_IMPL( _prop_name_, _type_name_, _member_name_, _value_ ) 	  \
                                                                              \
    osl::MutexGuard aGuard( m_aMutex );				                          \
                                                                              \
    ucbhelper_impl::PropertyValue aNewValue;                                  \
    aNewValue.sPropertyName = _prop_name_;                                    \
    aNewValue.nPropsSet  	= _type_name_;                                    \
    aNewValue.nOrigValue 	= _type_name_;                                    \
    aNewValue._member_name_ = _value_;                                        \
                                                                              \
    m_pValues->push_back( aNewValue );

namespace ucbhelper {

//=========================================================================
//=========================================================================
//
// PropertyValueSet Implementation.
//
//=========================================================================
//=========================================================================

#define PROPERTYVALUESET_INIT() 			\
  m_xSMgr( rxSMgr ),						\
  m_pValues( new PropertyValues ),			\
  m_bWasNull( sal_False ),      			\
  m_bTriedToGetTypeConverter( sal_False )

//=========================================================================
PropertyValueSet::PropertyValueSet(
                    const Reference< XMultiServiceFactory >& rxSMgr )
: PROPERTYVALUESET_INIT()
{
}

//=========================================================================
PropertyValueSet::PropertyValueSet(
            const Reference< XMultiServiceFactory >& rxSMgr,
            const Sequence< com::sun::star::beans::PropertyValue >& rValues )
: PROPERTYVALUESET_INIT()
{
    sal_Int32 nCount = rValues.getLength();
    if ( nCount )
    {
        const com::sun::star::beans::PropertyValue* pValues
            = rValues.getConstArray();

        for ( sal_Int32 n = 0; n < nCount; ++n )
        {
            const com::sun::star::beans::PropertyValue& rValue = pValues[ n ];
            appendObject( Property( rValue.Name,
                                      rValue.Handle,
                                      rValue.Value.getValueType(),
                                      0 ),
                          rValue.Value );
        }
    }
}

//=========================================================================
// virtual
PropertyValueSet::~PropertyValueSet()
{
    delete m_pValues;
}

//=========================================================================
//
// XInterface methods.
//
//=========================================================================

XINTERFACE_IMPL_3( PropertyValueSet,
                   XTypeProvider,
                   XRow,
                   XColumnLocate );

//=========================================================================
//
// XTypeProvider methods.
//
//=========================================================================

XTYPEPROVIDER_IMPL_3( PropertyValueSet,
                      XTypeProvider,
                         XRow,
                      XColumnLocate );

//=========================================================================
//
// XRow methods.
//
//=========================================================================

// virtual
sal_Bool SAL_CALL PropertyValueSet::wasNull()
    throw( SQLException, RuntimeException )
{
    // This method can not be implemented correctly!!! Imagine different
    // threads doing a getXYZ - wasNull calling sequence on the same
    // implementation object...
    return m_bWasNull;
}

//=========================================================================
// virtual
OUString SAL_CALL PropertyValueSet::getString( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( OUString, STRING_VALUE_SET, aString );
}

//=========================================================================
// virtual
sal_Bool SAL_CALL PropertyValueSet::getBoolean( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL_TYPE(
            sal_Bool, BOOLEAN_VALUE_SET, bBoolean, getCppuBooleanType() );
}

//=========================================================================
// virtual
sal_Int8 SAL_CALL PropertyValueSet::getByte( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( sal_Int8, BYTE_VALUE_SET, nByte );
}

//=========================================================================
// virtual
sal_Int16 SAL_CALL PropertyValueSet::getShort( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( sal_Int16, SHORT_VALUE_SET, nShort );
}

//=========================================================================
// virtual
sal_Int32 SAL_CALL PropertyValueSet::getInt( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( sal_Int32, INT_VALUE_SET, nInt );
}

//=========================================================================
// virtual
sal_Int64 SAL_CALL PropertyValueSet::getLong( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( sal_Int64, LONG_VALUE_SET, nLong );
}

//=========================================================================
// virtual
float SAL_CALL PropertyValueSet::getFloat( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( float, FLOAT_VALUE_SET, nFloat );
}

//=========================================================================
// virtual
double SAL_CALL PropertyValueSet::getDouble( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( double, DOUBLE_VALUE_SET, nDouble );
}

//=========================================================================
// virtual
Sequence< sal_Int8 > SAL_CALL
PropertyValueSet::getBytes( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Sequence< sal_Int8 >, BYTES_VALUE_SET, aBytes );
}

//=========================================================================
// virtual
Date SAL_CALL PropertyValueSet::getDate( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Date, DATE_VALUE_SET, aDate );
}

//=========================================================================
// virtual
Time SAL_CALL PropertyValueSet::getTime( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Time, TIME_VALUE_SET, aTime );
}

//=========================================================================
// virtual
DateTime SAL_CALL PropertyValueSet::getTimestamp( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( DateTime, TIMESTAMP_VALUE_SET, aTimestamp );
}

//=========================================================================
// virtual
Reference< XInputStream > SAL_CALL
PropertyValueSet::getBinaryStream( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL(
        Reference< XInputStream >, BINARYSTREAM_VALUE_SET, xBinaryStream );
}

//=========================================================================
// virtual
Reference< XInputStream > SAL_CALL
PropertyValueSet::getCharacterStream( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL(
        Reference< XInputStream >, CHARACTERSTREAM_VALUE_SET, xCharacterStream );
}

//=========================================================================
// virtual
Any SAL_CALL PropertyValueSet::getObject(
                                    sal_Int32 columnIndex,
                                         const Reference< XNameAccess >& )
    throw( SQLException, RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    Any aValue;

    m_bWasNull = sal_True;

    if ( ( columnIndex < 1 )
         || ( columnIndex > sal_Int32( m_pValues->size() ) ) )
    {
        OSL_FAIL( "PropertyValueSet - index out of range!" );
    }
    else
    {
        ucbhelper_impl::PropertyValue& rValue 
            = (*m_pValues)[ columnIndex - 1 ];

        if ( rValue.nPropsSet & OBJECT_VALUE_SET )
        {
            // Values is present natively...
            aValue = rValue.aObject;
            m_bWasNull = sal_False;
        }
        else
        {
            // Make Any from original value.

            switch ( rValue.nOrigValue )
            {
                case NO_VALUE_SET:
                    break;

                case STRING_VALUE_SET:
                    aValue <<= rValue.aString;
                    break;

                case BOOLEAN_VALUE_SET:
                    aValue <<= rValue.bBoolean;
                    break;

                case BYTE_VALUE_SET:
                    aValue <<= rValue.nByte;
                    break;

                case SHORT_VALUE_SET:
                    aValue <<= rValue.nShort;
                    break;

                case INT_VALUE_SET:
                    aValue <<= rValue.nInt;
                    break;

                case LONG_VALUE_SET:
                    aValue <<= rValue.nLong;
                    break;

                case FLOAT_VALUE_SET:
                    aValue <<= rValue.nFloat;
                    break;

                case DOUBLE_VALUE_SET:
                    aValue <<= rValue.nDouble;
                    break;

                case BYTES_VALUE_SET:
                    aValue <<= rValue.aBytes;
                    break;

                case DATE_VALUE_SET:
                    aValue <<= rValue.aDate;
                    break;

                case TIME_VALUE_SET:
                    aValue <<= rValue.aTime;
                    break;

                case TIMESTAMP_VALUE_SET:
                    aValue <<= rValue.aTimestamp;
                    break;

                case BINARYSTREAM_VALUE_SET:
                    aValue <<= rValue.xBinaryStream;
                    break;

                case CHARACTERSTREAM_VALUE_SET:
                    aValue <<= rValue.xCharacterStream;
                    break;

                case REF_VALUE_SET:
                    aValue <<= rValue.xRef;
                    break;

                case BLOB_VALUE_SET:
                    aValue <<= rValue.xBlob;
                    break;

                case CLOB_VALUE_SET:
                    aValue <<= rValue.xClob;
                    break;

                case ARRAY_VALUE_SET:
                    aValue <<= rValue.xArray;
                    break;

                case OBJECT_VALUE_SET:
                    // Fall-through is intended!
                default:
                    OSL_FAIL( "PropertyValueSet::getObject - "
                                "Wrong original type" );
                    break;
            }

            if ( aValue.hasValue() )
            {
                rValue.aObject = aValue;
                rValue.nPropsSet |= OBJECT_VALUE_SET;
                m_bWasNull = sal_False;
            }
        }
     }

    return aValue;
}

//=========================================================================
// virtual
Reference< XRef > SAL_CALL PropertyValueSet::getRef( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Reference< XRef >, REF_VALUE_SET, xRef );
}

//=========================================================================
// virtual
Reference< XBlob > SAL_CALL PropertyValueSet::getBlob( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Reference< XBlob >, BLOB_VALUE_SET, xBlob );
}

//=========================================================================
// virtual
Reference< XClob > SAL_CALL PropertyValueSet::getClob( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Reference< XClob >, CLOB_VALUE_SET, xClob );
}

//=========================================================================
// virtual
Reference< XArray > SAL_CALL PropertyValueSet::getArray( sal_Int32 columnIndex )
    throw( SQLException, RuntimeException )
{
    GETVALUE_IMPL( Reference< XArray >, ARRAY_VALUE_SET, xArray );
}

//=========================================================================
//
// XColumnLocate methods.
//
//=========================================================================

// virtual
sal_Int32 SAL_CALL PropertyValueSet::findColumn( const OUString& columnName )
    throw( SQLException, RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( columnName.getLength() )
    {
        sal_Int32 nCount = m_pValues->size();
        for ( sal_Int32 n = 0; n < nCount; ++n )
        {
            if ( (*m_pValues)[ n ].sPropertyName.equals( columnName ) )
                return sal_Int32( n + 1 ); // Index is 1-based.
        }
    }
    return 0;
}

//=========================================================================
//
// Non-interface methods.
//
//=========================================================================

const Reference< XTypeConverter >& PropertyValueSet::getTypeConverter()
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() )
    {
        m_bTriedToGetTypeConverter = sal_True;
        m_xTypeConverter = Reference< XTypeConverter >(
                                m_xSMgr->createInstance(
                                    OUString(RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.script.Converter" )) ),
                                UNO_QUERY );

        OSL_ENSURE( m_xTypeConverter.is(),
                    "PropertyValueSet::getTypeConverter() - "
                    "Service 'com.sun.star.script.Converter' n/a!" );
    }
    return m_xTypeConverter;
}

//=========================================================================
sal_Int32 PropertyValueSet::getLength() const
{
    return m_pValues->size();
}

//=========================================================================
void PropertyValueSet::appendString( const ::rtl::OUString& rPropName,
                                     const OUString& rValue )
{
    SETVALUE_IMPL( rPropName, STRING_VALUE_SET, aString, rValue );
}

//=========================================================================
void PropertyValueSet::appendBoolean( const ::rtl::OUString& rPropName,
                                      sal_Bool bValue )
{
    SETVALUE_IMPL( rPropName, BOOLEAN_VALUE_SET, bBoolean, bValue );
}

//=========================================================================
void PropertyValueSet::appendByte( const ::rtl::OUString& rPropName,
                                   sal_Int8 nValue )
{
    SETVALUE_IMPL( rPropName, BYTE_VALUE_SET, nByte, nValue );
}

//=========================================================================
void PropertyValueSet::appendShort( const ::rtl::OUString& rPropName,
                                    sal_Int16 nValue )
{
    SETVALUE_IMPL( rPropName, SHORT_VALUE_SET, nShort, nValue );
}

//=========================================================================
void PropertyValueSet::appendInt( const ::rtl::OUString& rPropName,
                                  sal_Int32 nValue )
{
    SETVALUE_IMPL( rPropName, INT_VALUE_SET, nInt, nValue );
}

//=========================================================================
void PropertyValueSet::appendLong( const ::rtl::OUString& rPropName,
                                   sal_Int64 nValue )
{
    SETVALUE_IMPL( rPropName, LONG_VALUE_SET, nLong, nValue );
}

//=========================================================================
void PropertyValueSet::appendFloat( const ::rtl::OUString& rPropName,
                                    float nValue )
{
    SETVALUE_IMPL( rPropName, FLOAT_VALUE_SET, nFloat, nValue );
}

//=========================================================================
void PropertyValueSet::appendDouble( const ::rtl::OUString& rPropName,
                                     double nValue )
{
    SETVALUE_IMPL( rPropName, DOUBLE_VALUE_SET, nDouble, nValue );
}

//=========================================================================
void PropertyValueSet::appendBytes( const ::rtl::OUString& rPropName,
                                    const Sequence< sal_Int8 >& rValue )
{
    SETVALUE_IMPL( rPropName, BYTES_VALUE_SET, aBytes, rValue );
}

//=========================================================================
void PropertyValueSet::appendDate( const ::rtl::OUString& rPropName,
                                   const Date& rValue )
{
    SETVALUE_IMPL( rPropName, DATE_VALUE_SET, aDate, rValue );
}

//=========================================================================
void PropertyValueSet::appendTime( const ::rtl::OUString& rPropName,
                                   const Time& rValue )
{
    SETVALUE_IMPL( rPropName, TIME_VALUE_SET, aTime, rValue );
}

//=========================================================================
void PropertyValueSet::appendTimestamp( const ::rtl::OUString& rPropName,
                                        const DateTime& rValue )
{
    SETVALUE_IMPL( rPropName, TIMESTAMP_VALUE_SET, aTimestamp, rValue );
}

//=========================================================================
void PropertyValueSet::appendBinaryStream(
                                const ::rtl::OUString& rPropName,
                                const Reference< XInputStream >& rValue )
{
    SETVALUE_IMPL( rPropName, BINARYSTREAM_VALUE_SET, xBinaryStream, rValue );
}

//=========================================================================
void PropertyValueSet::appendCharacterStream(
                                const ::rtl::OUString& rPropName,
                                const Reference< XInputStream >& rValue )
{
    SETVALUE_IMPL( rPropName, CHARACTERSTREAM_VALUE_SET, xCharacterStream, rValue );
}

//=========================================================================
void PropertyValueSet::appendObject( const ::rtl::OUString& rPropName,
                                     const Any& rValue )
{
    SETVALUE_IMPL( rPropName, OBJECT_VALUE_SET, aObject, rValue );
}

//=========================================================================
void PropertyValueSet::appendRef( const ::rtl::OUString& rPropName,
                                  const Reference< XRef >& rValue )
{
    SETVALUE_IMPL( rPropName, REF_VALUE_SET, xRef, rValue );
}

//=========================================================================
void PropertyValueSet::appendBlob( const ::rtl::OUString& rPropName,
                                   const Reference< XBlob >& rValue )
{
    SETVALUE_IMPL( rPropName, BLOB_VALUE_SET, xBlob, rValue );
}

//=========================================================================
void PropertyValueSet::appendClob( const ::rtl::OUString& rPropName,
                                   const Reference< XClob >& rValue )
{
    SETVALUE_IMPL( rPropName, CLOB_VALUE_SET, xClob, rValue );
}

//=========================================================================
void PropertyValueSet::appendArray( const ::rtl::OUString& rPropName,
                                    const Reference< XArray >& rValue )
{
    SETVALUE_IMPL( rPropName, ARRAY_VALUE_SET, xArray, rValue );
}

//=========================================================================
void PropertyValueSet::appendVoid( const ::rtl::OUString& rPropName )
{
    SETVALUE_IMPL( rPropName, NO_VALUE_SET, aObject, Any() );
}

//=========================================================================
void PropertyValueSet::appendPropertySet(
                                const Reference< XPropertySet >& rxSet )
{
    if ( rxSet.is() )
    {
        Reference< XPropertySetInfo > xInfo = rxSet->getPropertySetInfo();
        if ( xInfo.is() )
        {
            Sequence< Property > aProps 	 = xInfo->getProperties();
            const Property* 	 pProps 	 = aProps.getConstArray();
            sal_Int32 			 nPropsCount = aProps.getLength();

            Reference< XPropertyAccess > xPropertyAccess( rxSet, UNO_QUERY );
            if ( xPropertyAccess.is() )
            {
                // Efficient: Get all prop values with one ( remote) call.

                Sequence< ::com::sun::star::beans::PropertyValue > aPropValues
                    = xPropertyAccess->getPropertyValues();

                const ::com::sun::star::beans::PropertyValue* pPropValues
                      = aPropValues.getConstArray();

                sal_Int32 nValuesCount = aPropValues.getLength();
                for ( sal_Int32 n = 0; n < nValuesCount; ++n )
                {
                    const ::com::sun::star::beans::PropertyValue& rPropValue
                        = pPropValues[ n ];

                    // Find info for current property value.
                    for ( sal_Int32 m = 0; m < nPropsCount; ++m )
                    {
                        const Property& rProp = pProps[ m ];
                        if ( rProp.Name == rPropValue.Name )
                        {
                            // Found!
                            appendObject( rProp, rPropValue.Value );
                            break;
                        }
                    }
                }
            }
            else
            {
                // Get every single prop value with one ( remote) call.

                for ( sal_Int32 n = 0; n < nPropsCount; ++n )
                {
                    const Property& rProp = pProps[ n ];

                    try
                    {
                        Any aValue = rxSet->getPropertyValue( rProp.Name );

                        if ( aValue.hasValue() )
                            appendObject( rProp, aValue );
                    }
                    catch ( UnknownPropertyException )
                    {
                    }
                       catch ( WrappedTargetException )
                    {
                    }
                }
            }
        }
    }
}

//=========================================================================
sal_Bool PropertyValueSet::appendPropertySetValue(
                                const Reference< XPropertySet >& rxSet,
                                const Property& rProperty )
{
    if ( rxSet.is() )
    {
        try
        {
            Any aValue = rxSet->getPropertyValue( rProperty.Name );
            if ( aValue.hasValue() )
            {
                appendObject( rProperty, aValue );
                return sal_True;
            }
        }
        catch ( UnknownPropertyException )
        {
        }
        catch ( WrappedTargetException )
        {
        }
    }

    // Error.
    return sal_False;
}

} // namespace ucbhelper

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
