/**************************************************************
 * 
 * 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_xmloff.hxx"

#include <stdio.h>
#include "propertyexport.hxx"
#include <xmloff/xmlexp.hxx>
#include "strings.hxx"
#include "xmloff/xmlnmspe.hxx"
#include <xmloff/xmluconv.hxx>
#include <xmloff/families.hxx>
#include <osl/diagnose.h>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/Time.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <osl/diagnose.h>
#include <comphelper/extract.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/types.hxx>
#include "callbacks.hxx"
#include <unotools/datetime.hxx>
#include <tools/date.hxx>
#include <tools/time.hxx>
#include <tools/datetime.hxx>

//.........................................................................
namespace xmloff
{
//.........................................................................

	using namespace ::com::sun::star::uno;
	using namespace ::com::sun::star::lang;
	using namespace ::com::sun::star::beans;

	// NO using namespace ...util !!!
	// need a tools Date/Time/DateTime below, which would conflict with the uno types then

	using namespace ::comphelper;

	//=====================================================================
	//= OPropertyExport
	//=====================================================================
	//---------------------------------------------------------------------
	OPropertyExport::OPropertyExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxProps)
		:m_rContext(_rContext)
		,m_xProps(_rxProps)
        ,m_xPropertyInfo( m_xProps->getPropertySetInfo() )
        ,m_xPropertyState( _rxProps, UNO_QUERY )
	{
		// caching
		::rtl::OUStringBuffer aBuffer;
		m_rContext.getGlobalContext().GetMM100UnitConverter().convertBool(aBuffer, sal_True);
		m_sValueTrue = aBuffer.makeStringAndClear();
		m_rContext.getGlobalContext().GetMM100UnitConverter().convertBool(aBuffer, sal_False);
		m_sValueFalse = aBuffer.makeStringAndClear();

		OSL_ENSURE(m_xPropertyInfo.is(), "OPropertyExport::OPropertyExport: need an XPropertySetInfo!");

		// collect the properties which need to be exported
		examinePersistence();
	}

	//---------------------------------------------------------------------
    bool OPropertyExport::shouldExportProperty( const ::rtl::OUString& i_propertyName ) const
    {
		// if the property state is DEFAULT, it does not need to be written - at least
        // if it's a built-in property, and not a dynamically-added one.
        bool bIsDefaultValue =    m_xPropertyState.is()
                            &&  ( PropertyState_DEFAULT_VALUE == m_xPropertyState->getPropertyState( i_propertyName ) );
        bool bIsDynamicProperty =  m_xPropertyInfo.is()
                                && ( ( m_xPropertyInfo->getPropertyByName( i_propertyName ).Attributes & PropertyAttribute::REMOVEABLE ) != 0 );
		return ( !bIsDefaultValue || bIsDynamicProperty );
    }

	//---------------------------------------------------------------------
	void OPropertyExport::exportRemainingProperties()
	{
		// the properties tag (will be created if we have at least one no-default property)
		SvXMLElementExport* pPropertiesTag = NULL;

		try
		{
			Any aValue;
			::rtl::OUString sValue;

			// loop through all the properties which are yet to be exported
			for	(	ConstStringSetIterator	aProperty = m_aRemainingProps.begin();
					aProperty != m_aRemainingProps.end();
					++aProperty
				)
			{
				DBG_CHECK_PROPERTY_NO_TYPE(*aProperty);

	#if OSL_DEBUG_LEVEL > 0
				const ::rtl::OUString sPropertyName = *aProperty; (void)sPropertyName;
	#endif
                if ( !shouldExportProperty( *aProperty ) )
                    continue;

				// now that we have the first sub-tag we need the form:properties element
				if (!pPropertiesTag)
					pPropertiesTag = new SvXMLElementExport(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, token::XML_PROPERTIES, sal_True, sal_True);

				// add the name attribute
				AddAttribute(XML_NAMESPACE_FORM, token::XML_PROPERTY_NAME, *aProperty);

				// get the value
				aValue = m_xProps->getPropertyValue(*aProperty);

                // the type to export
                Type aExportType;

                // is it a sequence
				sal_Bool bIsSequence = TypeClass_SEQUENCE == aValue.getValueTypeClass();
				// the type of the property, maybe reduced to the element type of a sequence
				if (bIsSequence)
					aExportType = getSequenceElementType( aValue.getValueType() );
				else
					aExportType = aValue.getValueType();

				// the type attribute
				// modified by BerryJia for Bug102407
                bool bIsEmptyValue = TypeClass_VOID == aValue.getValueType().getTypeClass();
                if ( bIsEmptyValue )
                {
                    com::sun::star::beans::Property aPropDesc;
				    aPropDesc = m_xPropertyInfo->getPropertyByName( *aProperty );
                    aExportType = aPropDesc.Type;
                }
				token::XMLTokenEnum eValueType = implGetPropertyXMLType( aExportType );

				if ( bIsEmptyValue )
					AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, token::XML_VOID );
				else
					AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, eValueType );

                token::XMLTokenEnum eValueAttName( token::XML_VALUE );
                switch ( eValueType )
                {
                case token::XML_BOOLEAN:    eValueAttName = token::XML_BOOLEAN_VALUE; break;
                case token::XML_STRING:     eValueAttName = token::XML_STRING_VALUE;  break;
                default:    break;
                }

				if( !bIsSequence && !bIsEmptyValue )
				{	// the simple case
					//add by BerryJia for Bug102407
					sValue = implConvertAny(aValue);
					AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue );
				}


				// start the property tag
				SvXMLElementExport aValueTag1(m_rContext.getGlobalContext(), 
						XML_NAMESPACE_FORM, 
						bIsSequence ? token::XML_LIST_PROPERTY
									: token::XML_PROPERTY, sal_True, sal_True);

				if (!bIsSequence)
					continue;

				// the not-that-simple case, we need to iterate through the sequence elements
				IIterator* pSequenceIterator = NULL;

				switch ( aExportType.getTypeClass() )
				{
					case TypeClass_STRING:
						pSequenceIterator = new OSequenceIterator< ::rtl::OUString >(aValue);
						break;
					case TypeClass_DOUBLE:
						pSequenceIterator = new OSequenceIterator< double >(aValue);
						break;
					case TypeClass_BOOLEAN:
						pSequenceIterator = new OSequenceIterator< sal_Bool >(aValue);
						break;
					case TypeClass_BYTE:
						pSequenceIterator = new OSequenceIterator< sal_Int8 >(aValue);
						break;
					case TypeClass_SHORT:
						pSequenceIterator = new OSequenceIterator< sal_Int16 >(aValue);
						break;
					case TypeClass_LONG:
						pSequenceIterator = new OSequenceIterator< sal_Int32 >(aValue);
						break;
					case TypeClass_HYPER:
						pSequenceIterator = new OSequenceIterator< sal_Int64 >(aValue);
						break;
					default:
						OSL_ENSURE(sal_False, "OPropertyExport::exportRemainingProperties: unsupported sequence tyoe !");
						break;
				}
				if (pSequenceIterator)
				{
					while (pSequenceIterator->hasMoreElements())
					{
						sValue = 
							implConvertAny(pSequenceIterator->nextElement());
						AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue );
						SvXMLElementExport aValueTag(
								m_rContext.getGlobalContext(), 
								XML_NAMESPACE_FORM, token::XML_LIST_VALUE, 
								sal_True, sal_False);
					}
				}
				delete pSequenceIterator;
			}
		}
		catch(...)
		{
			delete pPropertiesTag;
			throw;
		}
		delete pPropertiesTag;
	}

	//---------------------------------------------------------------------
	void OPropertyExport::examinePersistence()
	{
		m_aRemainingProps.clear();
		Sequence< Property > aProperties = m_xPropertyInfo->getProperties();
		const Property* pProperties = aProperties.getConstArray();
		for (sal_Int32 i=0; i<aProperties.getLength(); ++i, ++pProperties)
		{
			// no transient props
            if ( pProperties->Attributes & PropertyAttribute::TRANSIENT )
                continue;
            // no read-only props
            if ( ( pProperties->Attributes & PropertyAttribute::READONLY ) != 0 )
                // except they're dynamically added
                if ( ( pProperties->Attributes & PropertyAttribute::REMOVEABLE ) == 0 )
				    continue;
			m_aRemainingProps.insert(pProperties->Name);
		}
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportStringPropertyAttribute( const sal_uInt16 _nNamespaceKey, const sal_Char* _pAttributeName,
			const ::rtl::OUString& _rPropertyName )
	{
		DBG_CHECK_PROPERTY( _rPropertyName, ::rtl::OUString );

		// no try-catch here, this would be to expensive. The outer scope has to handle exceptions (which should not
		// happen if we're used correctly :)

		// this is way simple, as we don't need to convert anything (the property already is a string)

		// get the string
		::rtl::OUString sPropValue;
		m_xProps->getPropertyValue( _rPropertyName ) >>= sPropValue;

		// add the attribute
		if ( sPropValue.getLength() )
			AddAttribute( _nNamespaceKey, _pAttributeName, sPropValue );

		// the property does not need to be handled anymore
		exportedProperty( _rPropertyName );
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportBooleanPropertyAttribute(const sal_uInt16 _nNamespaceKey, const sal_Char* _pAttributeName,
			const ::rtl::OUString& _rPropertyName, const sal_Int8 _nBooleanAttributeFlags)
	{
		DBG_CHECK_PROPERTY_NO_TYPE( _rPropertyName );
		// no check of the property value type: this method is allowed to be called with any integer properties
		// (e.g. sal_Int32, sal_uInt16 etc)

		sal_Bool bDefault = (BOOLATTR_DEFAULT_TRUE == (BOOLATTR_DEFAULT_MASK & _nBooleanAttributeFlags));
		sal_Bool bDefaultVoid = (BOOLATTR_DEFAULT_VOID == (BOOLATTR_DEFAULT_MASK & _nBooleanAttributeFlags));

		// get the value
		sal_Bool bCurrentValue = bDefault;
		Any aCurrentValue = m_xProps->getPropertyValue( _rPropertyName );
		if (aCurrentValue.hasValue())
		{
			bCurrentValue = ::cppu::any2bool(aCurrentValue);
			// this will extract a boolean value even if the Any contains a int or short or something like that ...

			if (_nBooleanAttributeFlags & BOOLATTR_INVERSE_SEMANTICS)
				bCurrentValue = !bCurrentValue;

			// we have a non-void current value
			if (bDefaultVoid || (bDefault != bCurrentValue))
				// and (the default is void, or the non-void default does not equal the current value)
				// -> write the attribute
				AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse);
		}
		else
			// we have a void current value
			if (!bDefaultVoid)
				// and we have a non-void default
				// -> write the attribute
				AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse);

		// the property does not need to be handled anymore
		exportedProperty( _rPropertyName );
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportInt16PropertyAttribute(const sal_uInt16 _nNamespaceKey, const sal_Char* _pAttributeName,
		const ::rtl::OUString& _rPropertyName, const sal_Int16 _nDefault)
	{
		DBG_CHECK_PROPERTY( _rPropertyName, sal_Int16 );

		// get the value
		sal_Int16 nCurrentValue(_nDefault);
		m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue;

		// add the attribute
		if (_nDefault != nCurrentValue)
		{
			// let the formatter of the export context build a string
			::rtl::OUStringBuffer sBuffer;
			m_rContext.getGlobalContext().GetMM100UnitConverter().convertNumber(sBuffer, (sal_Int32)nCurrentValue);

			AddAttribute(_nNamespaceKey, _pAttributeName, sBuffer.makeStringAndClear());
		}

		// the property does not need to be handled anymore
		exportedProperty( _rPropertyName );
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportInt32PropertyAttribute( const sal_uInt16 _nNamespaceKey, const sal_Char* _pAttributeName,
		const ::rtl::OUString& _rPropertyName, const sal_Int32 _nDefault )
	{
		DBG_CHECK_PROPERTY( _rPropertyName, sal_Int32 );

		// get the value
		sal_Int32 nCurrentValue( _nDefault );
		m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue;

		// add the attribute
		if ( _nDefault != nCurrentValue )
		{
			// let the formatter of the export context build a string
			::rtl::OUStringBuffer sBuffer;
			m_rContext.getGlobalContext().GetMM100UnitConverter().convertNumber( sBuffer, nCurrentValue );

			AddAttribute( _nNamespaceKey, _pAttributeName, sBuffer.makeStringAndClear() );
		}

		// the property does not need to be handled anymore
		exportedProperty( _rPropertyName );
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportEnumPropertyAttribute(
			const sal_uInt16 _nNamespaceKey, const sal_Char* _pAttributeName,
			const sal_Char* _pPropertyName, const SvXMLEnumMapEntry* _pValueMap,
			const sal_Int32 _nDefault, const sal_Bool _bVoidDefault)
	{
		// get the value
		sal_Int32 nCurrentValue(_nDefault);
		::rtl::OUString sPropertyName(::rtl::OUString::createFromAscii(_pPropertyName));
		Any aValue = m_xProps->getPropertyValue(sPropertyName);

		if (aValue.hasValue())
		{	// we have a non-void current value
			::cppu::enum2int(nCurrentValue, aValue);

			// add the attribute
			if ((_nDefault != nCurrentValue) || _bVoidDefault)
			{	// the default does not equal the value, or the default is void and the value isn't

				// let the formatter of the export context build a string
				::rtl::OUStringBuffer sBuffer;
				m_rContext.getGlobalContext().GetMM100UnitConverter().convertEnum(sBuffer, (sal_uInt16)nCurrentValue, _pValueMap);

				AddAttribute(_nNamespaceKey, _pAttributeName, sBuffer.makeStringAndClear());
			}
		}
		else
		{
			if (!_bVoidDefault)
				AddAttributeASCII(_nNamespaceKey, _pAttributeName, "");
		}

		// the property does not need to be handled anymore
		exportedProperty(sPropertyName);
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportTargetFrameAttribute()
	{
		DBG_CHECK_PROPERTY( PROPERTY_TARGETFRAME, ::rtl::OUString );

		::rtl::OUString sTargetFrame = comphelper::getString(m_xProps->getPropertyValue(PROPERTY_TARGETFRAME));
		if (0 != sTargetFrame.compareToAscii("_blank"))
		{	// an empty string and "_blank" have the same meaning and don't have to be written
			AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(CCA_TARGET_FRAME)
						,OAttributeMetaData::getCommonControlAttributeName(CCA_TARGET_FRAME)
						,sTargetFrame);
		}
			
		exportedProperty(PROPERTY_TARGETFRAME);
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportRelativeTargetLocation(const ConstAsciiString& _sPropertyName,sal_Int32 _nProperty,bool _bAddType)
	{
		DBG_CHECK_PROPERTY( _sPropertyName, ::rtl::OUString );
			
		::rtl::OUString sTargetLocation = comphelper::getString(m_xProps->getPropertyValue(_sPropertyName));
        if ( sTargetLocation.getLength() )
                    // If this isn't a GraphicObject then GetRelativeReference
                    // will be called anyway ( in AddEmbeddedGraphic )
		    sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedGraphicObject(sTargetLocation);
		AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(_nProperty)
					,OAttributeMetaData::getCommonControlAttributeName(_nProperty)
					, sTargetLocation);

        // #i110911# add xlink:type="simple" if required
        if (_bAddType)
            AddAttribute(XML_NAMESPACE_XLINK, token::XML_TYPE, token::XML_SIMPLE);

		exportedProperty(_sPropertyName);
	}
	//---------------------------------------------------------------------
	void OPropertyExport::flagStyleProperties()
	{
		// flag all the properties which are part of the style as "handled"
		UniReference< XMLPropertySetMapper > xStylePropertiesSupplier = m_rContext.getStylePropertyMapper()->getPropertySetMapper();
		for (sal_Int32 i=0; i<xStylePropertiesSupplier->GetEntryCount(); ++i)
			exportedProperty(xStylePropertiesSupplier->GetEntryAPIName(i));

		// the font properties are exported as single properties, but there is a FontDescriptor property which
		// collects them all-in-one, this has been exported implicitly
		exportedProperty(PROPERTY_FONT);

		// for the DateFormat and TimeFormat, there exist wrapper properties which has been exported as
		// style, too
		exportedProperty(PROPERTY_DATEFORMAT);
		exportedProperty(PROPERTY_TIMEFORMAT);

        // the following properties should have been exported at the shape already:
        exportedProperty( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VerticalAlign" ) ) );
        exportedProperty( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "WritingMode" ) ) );
        exportedProperty( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ScaleMode" ) ) );
        // ditto the TextWritingMode
		exportedProperty( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "WritingMode" ) ) );
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportGenericPropertyAttribute(
			const sal_uInt16 _nAttributeNamespaceKey, const sal_Char* _pAttributeName, const sal_Char* _pPropertyName)
	{
		DBG_CHECK_PROPERTY_ASCII_NO_TYPE( _pPropertyName );

		::rtl::OUString sPropertyName = ::rtl::OUString::createFromAscii(_pPropertyName);
		exportedProperty(sPropertyName);

		Any aCurrentValue = m_xProps->getPropertyValue(sPropertyName);
		if (!aCurrentValue.hasValue())
			// nothing to do without a concrete value
			return;

		::rtl::OUString sValue = implConvertAny(aCurrentValue);
		if (!sValue.getLength() && (TypeClass_STRING == aCurrentValue.getValueTypeClass()))
		{
			// check whether or not the property is allowed to be VOID
			Property aProperty = m_xPropertyInfo->getPropertyByName(sPropertyName);
			if ((aProperty.Attributes & PropertyAttribute::MAYBEVOID) == 0)
				// the string is empty, and the property is not allowed to be void
				// -> don't need to write the attibute, 'cause missing it is unambiguous
				return;
		}

		// finally add the attribute to the context
		AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sValue);
	}

	//---------------------------------------------------------------------
	void OPropertyExport::exportStringSequenceAttribute(const sal_uInt16 _nAttributeNamespaceKey, const sal_Char* _pAttributeName,
		const ::rtl::OUString& _rPropertyName,
		const sal_Unicode _aQuoteCharacter, const sal_Unicode _aListSeparator)
	{
		DBG_CHECK_PROPERTY( _rPropertyName, Sequence< ::rtl::OUString > );
		OSL_ENSURE(_aListSeparator != 0, "OPropertyExport::exportStringSequenceAttribute: invalid separator character!");

		Sequence< ::rtl::OUString > aItems;
		m_xProps->getPropertyValue( _rPropertyName ) >>= aItems;

		::rtl::OUString sFinalList;

		// unfortunately the OUString can't append single sal_Unicode characters ...
		const ::rtl::OUString sQuote(&_aQuoteCharacter, 1);
		const ::rtl::OUString sSeparator(&_aListSeparator, 1);
		const sal_Bool bQuote = 0 != sQuote.getLength();

		// concatenate the string items
		const ::rtl::OUString* pItems = aItems.getConstArray();
		const ::rtl::OUString* pEnd = pItems + aItems.getLength();
		const ::rtl::OUString* pLastElement = pEnd - 1;
		for	(	;
				pItems != pEnd;
				++pItems
			)
		{
			OSL_ENSURE(!_aQuoteCharacter || (-1 == pItems->indexOf(_aQuoteCharacter)),
				"OPropertyExport::exportStringSequenceAttribute: there is an item which contains the quote character!");
			OSL_ENSURE(_aQuoteCharacter || (-1 == pItems->indexOf(_aListSeparator)),
				"OPropertyExport::exportStringSequenceAttribute: no quote character, but there is an item containing the separator character!");

			if (bQuote)
				sFinalList += sQuote;
			sFinalList += *pItems;
			if (bQuote)
				sFinalList += sQuote;

			if (pItems != pLastElement)
				sFinalList += sSeparator;
		}

		if (sFinalList.getLength())
			AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sFinalList);

		exportedProperty( _rPropertyName );
	}

	//---------------------------------------------------------------------
	::rtl::OUString OPropertyExport::implConvertAny(const Any& _rValue)
	{
		::rtl::OUStringBuffer aBuffer;
		switch (_rValue.getValueTypeClass())
		{
			case TypeClass_STRING:
			{	// extract the string
				::rtl::OUString sCurrentValue;
				_rValue >>= sCurrentValue;
				aBuffer.append(sCurrentValue);
			}
			break;
			case TypeClass_DOUBLE:
				// let the unit converter format is as string
				m_rContext.getGlobalContext().GetMM100UnitConverter().convertDouble(aBuffer, getDouble(_rValue));
				break;
			case TypeClass_BOOLEAN:
				aBuffer = getBOOL(_rValue) ? m_sValueTrue : m_sValueFalse;
				break;
			case TypeClass_BYTE:
			case TypeClass_SHORT:
			case TypeClass_LONG:
				// let the unit converter format is as string
				m_rContext.getGlobalContext().GetMM100UnitConverter().convertNumber(aBuffer, getINT32(_rValue));
				break;
			case TypeClass_HYPER:
				// TODO
				OSL_ENSURE(sal_False, "OPropertyExport::implConvertAny: missing implementation for sal_Int64!");
				break;
			case TypeClass_ENUM:
			{
				// convert it into an int32
				sal_Int32 nValue = 0;
				::cppu::enum2int(nValue, _rValue);
				m_rContext.getGlobalContext().GetMM100UnitConverter().convertNumber(aBuffer, nValue);
			}
			break;
			default:
			{	// hmmm .... what else do we know?
				double fValue = 0;
				::com::sun::star::util::Date aDate;
				::com::sun::star::util::Time aTime;
				::com::sun::star::util::DateTime aDateTime;
				if (_rValue >>= aDate)
				{
					Date aToolsDate;
					::utl::typeConvert(aDate, aToolsDate);
					fValue = aToolsDate.GetDate();
				}
				else if (_rValue >>= aTime)
				{
					fValue = ((aTime.Hours * 60 + aTime.Minutes) * 60 + aTime.Seconds) * 100 + aTime.HundredthSeconds;
					fValue = fValue / 8640000.0;
				}
				else if (_rValue >>= aDateTime)
				{
					DateTime aToolsDateTime;
					::utl::typeConvert(aDateTime, aToolsDateTime);
					// the time part (the digits behind the comma)
					fValue = ((aDateTime.Hours * 60 + aDateTime.Minutes) * 60 + aDateTime.Seconds) * 100 + aDateTime.HundredthSeconds;
					fValue = fValue / 8640000.0;
					// plus the data part (the digits in front of the comma)
					fValue += aToolsDateTime.GetDate();
				}
				else
				{
					// if any other types are added here, please remember to adjust implGetPropertyXMLType accordingly

					// no more options ...
					OSL_ENSURE(sal_False, "OPropertyExport::implConvertAny: unsupported value type!");
					break;
				}
				// let the unit converter format is as string
				m_rContext.getGlobalContext().GetMM100UnitConverter().convertDouble(aBuffer, fValue);
			}
			break;
		}

		return aBuffer.makeStringAndClear();
	}


	//---------------------------------------------------------------------
	token::XMLTokenEnum OPropertyExport::implGetPropertyXMLType(const ::com::sun::star::uno::Type& _rType)
	{
		// handle the type description
		switch (_rType.getTypeClass())
		{
			case TypeClass_STRING:
				return token::XML_STRING;
			case TypeClass_DOUBLE:
			case TypeClass_BYTE:
			case TypeClass_SHORT:
			case TypeClass_LONG:
			case TypeClass_HYPER:
			case TypeClass_ENUM:
				return token::XML_FLOAT;
			case TypeClass_BOOLEAN:
				return token::XML_BOOLEAN;

			default:
				return token::XML_FLOAT;
		}
	}

#ifdef DBG_UTIL
	//---------------------------------------------------------------------
	void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, const sal_Char* _pName, const ::rtl::OUString& _rValue)
	{
		OSL_ENSURE(0 == m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::rtl::OUString::createFromAscii(_pName)).getLength(),
			"OPropertyExport::AddAttribute: already have such an attribute");

		m_rContext.getGlobalContext().AddAttribute(_nPrefix, _pName, _rValue);
	}

    //---------------------------------------------------------------------
    void OPropertyExport::AddAttribute( sal_uInt16 _nPrefix, const ::rtl::OUString& _rName, const ::rtl::OUString& _rValue )
    {
        OSL_ENSURE(0 == m_rContext.getGlobalContext().GetXAttrList()->getValueByName( _rName ).getLength(),
            "OPropertyExport::AddAttribute: already have such an attribute");

        m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue );
    }

	//---------------------------------------------------------------------
	void OPropertyExport::AddAttributeASCII(sal_uInt16 _nPrefix, const sal_Char* _pName, const sal_Char *pValue)
	{
		OSL_ENSURE(0 == m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::rtl::OUString::createFromAscii(_pName)).getLength(),
			"OPropertyExport::AddAttributeASCII: already have such an attribute");

		m_rContext.getGlobalContext().AddAttributeASCII(_nPrefix, _pName, pValue);
	}

	//---------------------------------------------------------------------
	void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const ::rtl::OUString& _rValue)
	{
		OSL_ENSURE(0 == m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).getLength(),
			"OPropertyExport::AddAttribute: already have such an attribute");

		m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue);
	}

	//---------------------------------------------------------------------
	void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue )
	{
		OSL_ENSURE(0 == m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).getLength(),
			"OPropertyExport::AddAttribute: already have such an attribute");

		m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _eValue);
	}

	//---------------------------------------------------------------------
	void OPropertyExport::dbg_implCheckProperty(const ::rtl::OUString& _rPropertyName, const Type* _pType)
	{
		try
		{
			// the property must exist
			if (!m_xPropertyInfo->hasPropertyByName(_rPropertyName))
			{
				OSL_ENSURE(sal_False,
					::rtl::OString("OPropertyExport::dbg_implCheckProperty: no property with the name ") +=
					::rtl::OString(_rPropertyName.getStr(), _rPropertyName.getLength(), RTL_TEXTENCODING_ASCII_US) +=
					::rtl::OString("!"));
				return;
			}

			if (_pType)
			{
				// and it must have the correct type
				Property aPropertyDescription = m_xPropertyInfo->getPropertyByName(_rPropertyName);
				OSL_ENSURE(aPropertyDescription.Type.equals(*_pType), "OPropertyExport::dbg_implCheckProperty: invalid property type!");
			}
		}
		catch(Exception&)
		{
			OSL_ENSURE(sal_False, "OPropertyExport::dbg_implCheckProperty: caught an exception, could not check the property!");
		}
	}
#endif // DBG_UTIL - dbg_implCheckProperty

//.........................................................................
}	// namespace xmloff
//.........................................................................