/*************************************************************************
 *
 * 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_xmloff.hxx"
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/xml/AttributeData.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XTolerantMultiPropertySet.hpp>
#include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
#include <rtl/ustrbuf.hxx>
#include <list>
#include <hash_map>

#include <xmloff/xmlexppr.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/attrlist.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmloff/xmlnmspe.hxx"
#include <xmloff/xmlexp.hxx>
#include <xmloff/xmlprmap.hxx>
#include <xmloff/PropertySetInfoHash.hxx>
#include <comphelper/stl_types.hxx>

#ifndef _SVSTDARR_USHORTS
#define _SVSTDARR_USHORTS
#include <svl/svstdarr.hxx>
#endif

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

using namespace ::std;
using namespace ::com::sun::star;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::xmloff::token;

#define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT)

struct XMLPropTokens_Impl
{
	sal_uInt16 nType;
	XMLTokenEnum eToken;
};

#define ENTRY(t) { GET_PROP_TYPE(XML_TYPE_PROP_##t), XML_##t##_PROPERTIES }
const sal_uInt16 MAX_PROP_TYPES =
	(XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) -
	(XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT);

static  XMLPropTokens_Impl aPropTokens[MAX_PROP_TYPES] =
{
	ENTRY(CHART),
	ENTRY(GRAPHIC),
	ENTRY(TABLE),
	ENTRY(TABLE_COLUMN),
	ENTRY(TABLE_ROW),
	ENTRY(TABLE_CELL),
	ENTRY(LIST_LEVEL),
	ENTRY(PARAGRAPH),
	ENTRY(TEXT),
	ENTRY(DRAWING_PAGE),
	ENTRY(PAGE_LAYOUT),
	ENTRY(HEADER_FOOTER),
	ENTRY(RUBY),
	ENTRY(SECTION)
};

///////////////////////////////////////////////////////////////////////////////
//
// public methods
//

///////////////////////////////////////////////////////////////////////////
//
// Take all properties of the XPropertySet which are also found in the
// XMLPropertyMapEntry-array and which are not set to their default-value,
// if a state is available.
//
// After that I call the method 'ContextFilter'.
//

typedef std::list<XMLPropertyState> XMLPropertyStateList_Impl;

class XMLPropertyStates_Impl
{
	XMLPropertyStateList_Impl			aPropStates;
	XMLPropertyStateList_Impl::iterator	aLastItr;
	sal_uInt32							nCount;
public:
	XMLPropertyStates_Impl();
	void AddPropertyState(const XMLPropertyState& rPropState);
	void FillPropertyStateVector(std::vector<XMLPropertyState>& rVector);
};

XMLPropertyStates_Impl::XMLPropertyStates_Impl() :
	aPropStates(),
	nCount(0)
{
	aLastItr = aPropStates.begin();
}

void XMLPropertyStates_Impl::AddPropertyState(
		const XMLPropertyState& rPropState)
{
	XMLPropertyStateList_Impl::iterator aItr = aPropStates.begin();
	sal_Bool bInserted(sal_False);
	if (nCount)
	{
		if (aLastItr->mnIndex < rPropState.mnIndex)
			aItr = ++aLastItr;
	}
	do
	{
		// TODO: one path required only
		if (aItr == aPropStates.end())
		{
			aLastItr = aPropStates.insert(aPropStates.end(), rPropState);
			bInserted = sal_True;
			nCount++;
		}
		else if (aItr->mnIndex > rPropState.mnIndex)
		{
			aLastItr = aPropStates.insert(aItr, rPropState);
			bInserted = sal_True;
			nCount++;
		}
	}
	while(!bInserted && (aItr++ != aPropStates.end()));
}

void XMLPropertyStates_Impl::FillPropertyStateVector(
		std::vector<XMLPropertyState>& rVector)
{
	if (nCount)
	{
		rVector.resize(nCount, XMLPropertyState(-1));
        ::std::copy( aPropStates.begin(), aPropStates.end(), rVector.begin() );
	}
}

class FilterPropertyInfo_Impl
{
	const rtl::OUString		sApiName;
	std::list<sal_uInt32>	aIndexes;
	sal_uInt32				nCount;

public:

	FilterPropertyInfo_Impl( const rtl::OUString& rApiName,
							 const sal_uInt32 nIndex);

	const OUString& GetApiName() const { return sApiName; }
	std::list<sal_uInt32>& GetIndexes() { return aIndexes; }

	void AddIndex( sal_uInt32 nIndex )
	{
		aIndexes.push_back(nIndex);
		nCount++;
	}

    // for sort
    sal_Bool operator< ( const FilterPropertyInfo_Impl& rArg ) const
    {
        return (GetApiName() < rArg.GetApiName());
    }
};

FilterPropertyInfo_Impl::FilterPropertyInfo_Impl(
		const rtl::OUString& rApiName,
		const sal_uInt32 nIndex ) :
	sApiName( rApiName ),
	aIndexes(),
	nCount(1)
{
	aIndexes.push_back(nIndex);
}

typedef std::list<FilterPropertyInfo_Impl> FilterPropertyInfoList_Impl;

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

class FilterPropertiesInfo_Impl
{
	sal_uInt32								nCount;
	FilterPropertyInfoList_Impl				aPropInfos;
	FilterPropertyInfoList_Impl::iterator	aLastItr;

	Sequence <OUString> 					*pApiNames;

public:
	FilterPropertiesInfo_Impl();
	~FilterPropertiesInfo_Impl();

	void AddProperty(const rtl::OUString& rApiName, const sal_uInt32 nIndex);
	const uno::Sequence<OUString>& GetApiNames();
	void FillPropertyStateArray(
			vector< XMLPropertyState >& rPropStates,
			const Reference< XPropertySet >& xPropSet,
			const UniReference< XMLPropertySetMapper >& maPropMapper,
			const sal_Bool bDefault = sal_False);
	sal_uInt32 GetPropertyCount() const { return nCount; }
};

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

typedef std::hash_map
<
	PropertySetInfoKey,
	FilterPropertiesInfo_Impl *,
	PropertySetInfoHash,
	PropertySetInfoHash
>
FilterOropertiesHashMap_Impl;

class FilterPropertiesInfos_Impl : public FilterOropertiesHashMap_Impl
{
public:
	~FilterPropertiesInfos_Impl ();
};

FilterPropertiesInfos_Impl::~FilterPropertiesInfos_Impl ()
{
	FilterOropertiesHashMap_Impl::iterator aIter = begin();
	FilterOropertiesHashMap_Impl::iterator aEnd = end();
	while( aIter != aEnd )
	{
		delete (*aIter).second;
		(*aIter).second = 0;
		++aIter;
	}
}

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

FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl() :
	nCount(0),
	aPropInfos(),
	pApiNames( 0 )
{
	aLastItr = aPropInfos.begin();
}

FilterPropertiesInfo_Impl::~FilterPropertiesInfo_Impl()
{
	delete pApiNames;
}

void FilterPropertiesInfo_Impl::AddProperty(
		const rtl::OUString& rApiName, const sal_uInt32 nIndex)
{
    aPropInfos.push_back(FilterPropertyInfo_Impl(rApiName, nIndex));
    nCount++;

	OSL_ENSURE( !pApiNames, "perfomance warning: API names already retrieved" );
	if( pApiNames )
	{
		delete pApiNames;
		pApiNames = NULL;
	}
}
const uno::Sequence<OUString>& FilterPropertiesInfo_Impl::GetApiNames()
{
	OSL_ENSURE(nCount == aPropInfos.size(), "wrong property count");
	if( !pApiNames )
	{
        // we have to do three things:
        // 1) sort API names,
        // 2) merge duplicates,
        // 3) construct sequence

        // sort names
        aPropInfos.sort();

        // merge duplicates
        if ( nCount > 1 )
        {
            FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin();
            FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end();
            FilterPropertyInfoList_Impl::iterator aCurrent = aOld;
            aCurrent++;

            while ( aCurrent != aEnd )
            {
                // equal to next element?
                if ( aOld->GetApiName().equals( aCurrent->GetApiName() ) )
                {
                    // if equal: merge index lists
                    aOld->GetIndexes().merge( aCurrent->GetIndexes() );
                    // erase element, and continue with next
                    aCurrent = aPropInfos.erase( aCurrent );
					nCount--;
                }
                else
                {
                    // remember old element and continue with next
                    aOld = aCurrent;
                    aCurrent++;
                }
            }
        }

        // construct sequence
		pApiNames = new Sequence < OUString >( nCount );
		OUString *pNames = pApiNames->getArray();
		FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
		FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end();
		for ( ; aItr != aEnd; aItr++, pNames++)
			*pNames = aItr->GetApiName();
	}

	return *pApiNames;
}

void FilterPropertiesInfo_Impl::FillPropertyStateArray(
		vector< XMLPropertyState >& rPropStates,
		const Reference< XPropertySet >& rPropSet,
		const UniReference< XMLPropertySetMapper >& rPropMapper,
		const sal_Bool bDefault )
{
	XMLPropertyStates_Impl aPropStates;

	const uno::Sequence<OUString>& rApiNames = GetApiNames();

    Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY );
    if (xTolPropSet.is())
    {
        if (!bDefault)
        {
            Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames));
            sal_Int32 nResultCount(aResults.getLength());
            if (nResultCount > 0)
            {
		        const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray();
		        FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
		        XMLPropertyState aNewProperty( -1 );
                sal_uInt32 i = 0;
                while (nResultCount > 0 && i < nCount)
		        {
                    if (pResults->Name == aPropIter->GetApiName())
                    {
			            aNewProperty.mnIndex = -1;
			            aNewProperty.maValue = pResults->Value;

			            for( std::list<sal_uInt32>::iterator aIndexItr(aPropIter->GetIndexes().begin());
				            aIndexItr != aPropIter->GetIndexes().end();
				            ++aIndexItr )
			            {
				            aNewProperty.mnIndex = *aIndexItr;
				            aPropStates.AddPropertyState( aNewProperty );
			            }
    			        ++pResults;
                        --nResultCount;
                    }
		            ++aPropIter;
                    ++i;
                }
		    }
        }
        else
        {
            Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames));
            OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" );
		    const beans::GetPropertyTolerantResult *pResults = aResults.getConstArray();
		    FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
		    XMLPropertyState aNewProperty( -1 );
            sal_uInt32 nResultCount(aResults.getLength());
            OSL_ENSURE( nCount == nResultCount, "wrong implemented XTolerantMultiPropertySet??" );
		    for( sal_uInt32 i = 0; i < nResultCount; ++i )
		    {
                if ((pResults->Result == beans::TolerantPropertySetResultType::SUCCESS) &&
                    ((pResults->State == PropertyState_DIRECT_VALUE) || (pResults->State == PropertyState_DEFAULT_VALUE)))
                {
			        aNewProperty.mnIndex = -1;
			        aNewProperty.maValue = pResults->Value;

			        for( std::list<sal_uInt32>::iterator aIndexItr(aPropIter->GetIndexes().begin());
				        aIndexItr != aPropIter->GetIndexes().end();
				        ++aIndexItr )
			        {
				        aNewProperty.mnIndex = *aIndexItr;
				        aPropStates.AddPropertyState( aNewProperty );
			        }
                }
    			++pResults;
    		    ++aPropIter;
		    }
        }
    }
    else
    {
	    Sequence < PropertyState > aStates;
	    const PropertyState *pStates = 0;
	    Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY );
   	    if( xPropState.is() )
	    {
		    aStates = xPropState->getPropertyStates( rApiNames );
		    pStates = aStates.getConstArray();
	    }

	    Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY );
	    if( xMultiPropSet.is() && !bDefault )
	    {
		    Sequence < Any > aValues;
		    if( pStates )
		    {
			    // step 1: get value count
			    sal_uInt32 nValueCount = 0;
			    sal_uInt32 i;

			    for( i = 0; i < nCount; ++i, ++pStates )
			    {
				    if( (*pStates == PropertyState_DIRECT_VALUE)/* || (bDefault && (*pStates == PropertyState_DEFAULT_VALUE))*/ )
					    nValueCount++;
			    }

			    if( nValueCount )
			    {
				    // step 2: collect property names
				    Sequence < OUString > aAPINames( nValueCount );
				    OUString *pAPINames = aAPINames.getArray();

                    ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters;
                    aPropIters.reserve( nValueCount );

				    FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
    				OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!");

				    pStates = aStates.getConstArray();
				    i = 0;
				    while( i < nValueCount )
				    {
					    if( (*pStates == PropertyState_DIRECT_VALUE)/* || (bDefault && (*pStates == PropertyState_DEFAULT_VALUE))*/ )
					    {
						    *pAPINames++ = aItr->GetApiName();
                            aPropIters.push_back( aItr );
						    ++i;
					    }
                        ++aItr;
					    ++pStates;
				    }

				    aValues = xMultiPropSet->getPropertyValues( aAPINames );
				    const Any *pValues = aValues.getConstArray();

                    ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator
                        pPropIter = aPropIters.begin();

				    XMLPropertyState aNewProperty( -1 );
				    for( i = 0; i < nValueCount; i++ )
				    {
					    aNewProperty.mnIndex = -1;
					    aNewProperty.maValue = *pValues;

                        const ::std::list< sal_uInt32 >& rIndexes( (*pPropIter)->GetIndexes() );
					    for (   std::list<sal_uInt32>::const_iterator aIndexItr = rIndexes.begin();
						        aIndexItr != rIndexes.end();
						        ++aIndexItr
                            )
					    {
						    aNewProperty.mnIndex = *aIndexItr;
						    aPropStates.AddPropertyState( aNewProperty );
					    }

					    ++pPropIter;
					    ++pValues;
				    }
			    }
		    }
		    else
		    {
			    aValues = xMultiPropSet->getPropertyValues( rApiNames );
			    const Any *pValues = aValues.getConstArray();

			    FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
			    for(sal_uInt32 i = 0; i < nCount; i++ )
			    {
				    // The value is stored in the PropertySet itself, add to list.
				    XMLPropertyState aNewProperty( -1 );
				    aNewProperty.maValue = *pValues;
				    ++pValues;
				    for( std::list<sal_uInt32>::iterator aIndexItr =
						    aItr->GetIndexes().begin();
					    aIndexItr != aItr->GetIndexes().end();
					    aIndexItr++ )
				    {
					    aNewProperty.mnIndex = *aIndexItr;
					    aPropStates.AddPropertyState( aNewProperty );
				    }
				    aItr++;
			    }
		    }
	    }
	    else
	    {
		    FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
		    for(sal_uInt32 i = 0; i < nCount; i++ )
		    {
			    sal_Bool bDirectValue =
				    !pStates || *pStates == PropertyState_DIRECT_VALUE;
			    if( bDirectValue || bDefault )
			    {
				    // The value is stored in the PropertySet itself, add to list.
				    sal_Bool bGotValue = sal_False;
				    XMLPropertyState aNewProperty( -1 );
				    for( std::list<sal_uInt32>::const_iterator aIndexItr =
						    aItr->GetIndexes().begin();
					    aIndexItr != aItr->GetIndexes().end();
					    aIndexItr++ )
				    {
					    if( bDirectValue ||
						    (rPropMapper->GetEntryFlags( *aIndexItr ) &
										    MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 )
					    {
						    try
						    {
							    if( !bGotValue )
							    {
								    aNewProperty.maValue =
									    rPropSet->getPropertyValue( aItr->GetApiName() );
								    bGotValue = sal_True;
							    }
							    aNewProperty.mnIndex = *aIndexItr;
							    aPropStates.AddPropertyState( aNewProperty );
						    }
						    catch( UnknownPropertyException& )
						    {
							    // might be a problem of getImplemenetationId
							    OSL_ENSURE( !this, "unknown property in getPropertyValue" );
						    }

					    }
				    }
			    }

			    aItr++;
			    if( pStates )
				    pStates++;
		    }
	    }
    }
	aPropStates.FillPropertyStateVector(rPropStates);
}

///////////////////////////////////////////////////////////////////////////////
//
// ctor/dtor , class SvXMLExportPropertyMapper
//

SvXMLExportPropertyMapper::SvXMLExportPropertyMapper(
		const UniReference< XMLPropertySetMapper >& rMapper ) :
	pCache( 0 ),
	maPropMapper( rMapper )
{
}

SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper()
{
	delete pCache;
	mxNextMapper = 0;
}

void SvXMLExportPropertyMapper::ChainExportMapper(
		const UniReference< SvXMLExportPropertyMapper>& rMapper )
{
	// add map entries from rMapper to current map
	maPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() );
	// rMapper uses the same map as 'this'
	rMapper->maPropMapper = maPropMapper;

	// set rMapper as last mapper in current chain
	UniReference< SvXMLExportPropertyMapper > xNext = mxNextMapper;
	if( xNext.is())
	{
		while( xNext->mxNextMapper.is())
			xNext = xNext->mxNextMapper;
		xNext->mxNextMapper = rMapper;
	}
	else
		mxNextMapper = rMapper;

	// if rMapper was already chained, correct
	// map pointer of successors
	xNext = rMapper;

	while( xNext->mxNextMapper.is())
	{
		xNext = xNext->mxNextMapper;
		xNext->maPropMapper = maPropMapper;
	}
}


vector< XMLPropertyState > SvXMLExportPropertyMapper::_Filter(
		const Reference< XPropertySet > xPropSet,
		const sal_Bool bDefault ) const
{
	vector< XMLPropertyState > aPropStateArray;

	// Retrieve XPropertySetInfo and XPropertyState
	Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() );
	if( !xInfo.is() )
		return aPropStateArray;

	sal_Int32 nProps = maPropMapper->GetEntryCount();

	FilterPropertiesInfo_Impl *pFilterInfo = 0;

	Reference < XTypeProvider > xTypeProv( xPropSet, UNO_QUERY );
	Sequence< sal_Int8 > aImplId;
	if( xTypeProv.is() )
	{
		aImplId = xTypeProv->getImplementationId();
		if( aImplId.getLength() == 16 )
		{
			if( pCache )
			{
				// The key must not be created outside this block, because it
				// keeps a reference to the property set info.
				PropertySetInfoKey aKey( xInfo, aImplId );
				FilterPropertiesInfos_Impl::iterator aIter =
					pCache->find( aKey );
				if( aIter != pCache->end() )
					pFilterInfo = (*aIter).second;
			}
		}
	}

	sal_Bool bDelInfo = sal_False;
	if( !pFilterInfo )
	{
		pFilterInfo = new FilterPropertiesInfo_Impl;
		for( sal_Int32 i=0; i < nProps; i++ )
		{
			// Are we allowed to ask for the property? (MID_FLAG_NO_PROP..)
			// Does the PropertySet contain name of mpEntries-array ?
			const OUString& rAPIName = maPropMapper->GetEntryAPIName( i );
			const sal_Int32 nFlags = maPropMapper->GetEntryFlags( i );
			if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) &&
				( (0 != (nFlags & MID_FLAG_MUST_EXIST)) ||
				  xInfo->hasPropertyByName( rAPIName ) ) )
            {
                const SvtSaveOptions::ODFDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFDefaultVersion() );
                const SvtSaveOptions::ODFDefaultVersion nEarliestODFVersionForExport(
                        maPropMapper->GetEarliestODFVersionForExport( i ) );
                if( nCurrentVersion >= nEarliestODFVersionForExport
                        || nCurrentVersion == SvtSaveOptions::ODFVER_UNKNOWN
                        || nEarliestODFVersionForExport == SvtSaveOptions::ODFVER_UNKNOWN )
                    pFilterInfo->AddProperty(rAPIName, i);
            }
		}

		if( xTypeProv.is() && aImplId.getLength() == 16 )
		{
			// Check whether the property set info is destroyed if it is
			// assigned to a weak reference only. If it is destroyed, then
			// every instance of getPropertySetInfo returns a new object.
			// Such property set infos must not be cached.
			WeakReference < XPropertySetInfo > xWeakInfo( xInfo );
			xInfo = 0;
			xInfo = xWeakInfo;
			if( xInfo.is() )
			{
				if( !pCache )
					((SvXMLExportPropertyMapper *)this)->pCache =
						new FilterPropertiesInfos_Impl;
				PropertySetInfoKey aKey( xInfo, aImplId );
				(*pCache)[aKey] = pFilterInfo;
			}
			else
				bDelInfo = sal_True;
		}
		else
		{
			OSL_ENSURE(sal_False, "here is no TypeProvider or the ImplId is wrong");
			bDelInfo = sal_True;
		}
	}

	if( pFilterInfo->GetPropertyCount() )
	{
		try
		{
			pFilterInfo->FillPropertyStateArray(aPropStateArray,
												xPropSet, maPropMapper,
												bDefault);
		}
		catch( UnknownPropertyException& )
		{
			// might be a problem of getImplemenetationId
			OSL_ENSURE( !this, "unknown property in getPropertyStates" );
		}
	}

	// Call centext-filter
	if( !aPropStateArray.empty() )
		ContextFilter( aPropStateArray, xPropSet );

	// Have to do if we change from a vector to a list or something like that
	/*vector< XMLPropertyState >::iterator aItr = aPropStateArray.begin();
	while (aItr != aPropStateArray.end())
	{
		if (aItr->mnIndex == -1)
			aItr = aPropStateArray.erase(aItr);
		else
			aItr++;
	}*/

	if( bDelInfo )
		delete pFilterInfo;

	return aPropStateArray;
}

void SvXMLExportPropertyMapper::ContextFilter(
		vector< XMLPropertyState >& rProperties,
		Reference< XPropertySet > rPropSet ) const
{
	// Derived class could implement this.
	if( mxNextMapper.is() )
		mxNextMapper->ContextFilter( rProperties, rPropSet );
}

///////////////////////////////////////////////////////////////////////////
//
// Compares two Sequences of XMLPropertyState:
//	1.Number of elements equal ?
//	2.Index of each element equal ? (So I know whether the propertynames are the same)
//	3.Value of each element equal ?
//
sal_Bool SvXMLExportPropertyMapper::Equals(
		const vector< XMLPropertyState >& aProperties1,
	    const vector< XMLPropertyState >& aProperties2 ) const
{
	sal_Bool bRet = sal_True;
	sal_uInt32 nCount = aProperties1.size();

	if( nCount == aProperties2.size() )
	{
		sal_uInt32 nIndex = 0;
		while( bRet && nIndex < nCount )
		{
			const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
			const XMLPropertyState& rProp2 = aProperties2[ nIndex ];

			// Compare index. If equal, compare value
			if( rProp1.mnIndex == rProp2.mnIndex )
			{
				if( rProp1.mnIndex != -1 )
				{
					// Now compare values
					if( ( maPropMapper->GetEntryType( rProp1.mnIndex ) &
						  XML_TYPE_BUILDIN_CMP ) != 0 )
						// simple type ( binary compare )
						bRet = ( rProp1.maValue == rProp2.maValue );
					else
						// complex type ( ask for compare-function )
						bRet = maPropMapper->GetPropertyHandler(
									rProp1.mnIndex )->equals( rProp1.maValue,
															  rProp2.maValue );
				}
			}
			else
				bRet = sal_False;

			nIndex++;
		}
	}
	else
		bRet = sal_False;

	return bRet;
}


/** fills the given attribute list with the items in the given set
void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
		const ::std::vector< XMLPropertyState >& rProperties,
		const SvXMLUnitConverter& rUnitConverter,
		const SvXMLNamespaceMap& rNamespaceMap,
		sal_uInt16 nFlags ) const
{
	_exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
				nFlags, 0, -1, -1 );
}


void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
		const ::std::vector< XMLPropertyState >& rProperties,
		const SvXMLUnitConverter& rUnitConverter,
		const SvXMLNamespaceMap& rNamespaceMap,
		sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
		sal_uInt16 nFlags ) const
{
	_exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
				nFlags, 0, nPropMapStartIdx, nPropMapEndIdx );
}
*/


void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
		const XMLPropertyState& rProperty,
		const SvXMLUnitConverter& rUnitConverter,
		const SvXMLNamespaceMap& rNamespaceMap,
		sal_uInt16 nFlags ) const
{
	if( ( maPropMapper->GetEntryFlags( rProperty.mnIndex ) &
				MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0 )
		_exportXML( rAttrList, rProperty, rUnitConverter, rNamespaceMap,
					nFlags );
}

void SvXMLExportPropertyMapper::exportXML(
        SvXMLExport& rExport,
		const ::std::vector< XMLPropertyState >& rProperties,
		sal_uInt16 nFlags ) const
{
	exportXML( rExport, rProperties, -1, -1,  nFlags );
}

void SvXMLExportPropertyMapper::exportXML(
        SvXMLExport& rExport,
		const ::std::vector< XMLPropertyState >& rProperties,
		sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
		sal_uInt16 nFlags ) const
{
	sal_uInt16 nPropTypeFlags = 0;
	for( sal_uInt16 i=0; i<MAX_PROP_TYPES; ++i )
	{
		sal_uInt16 nPropType = aPropTokens[i].nType;
		if( 0==i || (nPropTypeFlags & (1 << nPropType)) != 0 )
		{
			SvUShorts aIndexArray;

			_exportXML( nPropType, nPropTypeFlags,
						rExport.GetAttrList(), rProperties,
						rExport.GetMM100UnitConverter(),
						rExport.GetNamespaceMap(),
						nFlags, &aIndexArray,
						nPropMapStartIdx, nPropMapEndIdx );

			if( rExport.GetAttrList().getLength() > 0L ||
				(nFlags & XML_EXPORT_FLAG_EMPTY) != 0 ||
				aIndexArray.Count() != 0 )
			{
				SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE,
								  aPropTokens[i].eToken,
								  (nFlags & XML_EXPORT_FLAG_IGN_WS) != 0,
								  sal_False );

				exportElementItems( rExport, rProperties, nFlags, aIndexArray );
			}
		}
	}
}

/** this method is called for every item that has the
    MID_FLAG_SPECIAL_ITEM_EXPORT flag set */
void SvXMLExportPropertyMapper::handleSpecialItem(
		SvXMLAttributeList& rAttrList,
		const XMLPropertyState& rProperty,
		const SvXMLUnitConverter& rUnitConverter,
		const SvXMLNamespaceMap& rNamespaceMap,
		const ::std::vector< XMLPropertyState > *pProperties,
		sal_uInt32 nIdx ) const
{
	OSL_ENSURE( mxNextMapper.is(), "special item not handled in xml export" );
	if( mxNextMapper.is() )
		mxNextMapper->handleSpecialItem( rAttrList, rProperty, rUnitConverter,
										rNamespaceMap, pProperties, nIdx );
}

/** this method is called for every item that has the
    MID_FLAG_ELEMENT_EXPORT flag set */
void SvXMLExportPropertyMapper::handleElementItem(
        SvXMLExport& rExport,
		const XMLPropertyState& rProperty,
		sal_uInt16 nFlags,
		const ::std::vector< XMLPropertyState > *pProperties,
		sal_uInt32 nIdx ) const
{
	OSL_ENSURE( mxNextMapper.is(), "element item not handled in xml export" );
	if( mxNextMapper.is() )
		mxNextMapper->handleElementItem( rExport, rProperty, nFlags,
                                         pProperties, nIdx );
}

///////////////////////////////////////////////////////////////////////////////
//
// protected methods
//

/** fills the given attribute list with the items in the given set */
void SvXMLExportPropertyMapper::_exportXML(
		sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags,
		SvXMLAttributeList& rAttrList,
		const ::std::vector< XMLPropertyState >& rProperties,
		const SvXMLUnitConverter& rUnitConverter,
		const SvXMLNamespaceMap& rNamespaceMap,
		sal_uInt16 nFlags,
		SvUShorts* pIndexArray,
		sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const
{
	const sal_uInt32 nCount = rProperties.size();
	sal_uInt32 nIndex = 0;

	if( -1 == nPropMapStartIdx )
		nPropMapStartIdx = 0;
	if( -1 == nPropMapEndIdx )
		nPropMapEndIdx = maPropMapper->GetEntryCount();

	while( nIndex < nCount )
	{
		sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex;
		if( nPropMapIdx >= nPropMapStartIdx &&
			nPropMapIdx < nPropMapEndIdx  )// valid entry?
		{
			sal_uInt32 nEFlags = maPropMapper->GetEntryFlags( nPropMapIdx );
			sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags);
			OSL_ENSURE( nEPType >= (XML_TYPE_PROP_START>>XML_TYPE_PROP_SHIFT),
						"no prop type sepcified" );
			rPropTypeFlags |= (1 << nEPType);
			if( nEPType == nPropType )
			{
				// we have a valid map entry here, so lets use it...
				if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 )
				{
					// element items do not add any properties,
					// we export it later
					if( pIndexArray )
						pIndexArray->Insert( (sal_uInt16)nIndex, pIndexArray->Count() );
				}
				else
				{
					_exportXML( rAttrList, rProperties[nIndex], rUnitConverter,
								rNamespaceMap, nFlags, &rProperties, nIndex );
				}
			}
		}

		nIndex++;
	}
}

void SvXMLExportPropertyMapper::_exportXML(
		SvXMLAttributeList& rAttrList,
		const XMLPropertyState& rProperty,
		const SvXMLUnitConverter& rUnitConverter,
		const SvXMLNamespaceMap& rNamespaceMap,
		sal_uInt16 /*nFlags*/,
		const ::std::vector< XMLPropertyState > *pProperties,
		sal_uInt32 nIdx ) const
{
	OUString sCDATA( GetXMLToken(XML_CDATA) );

	if ( ( maPropMapper->GetEntryFlags( rProperty.mnIndex ) &
				MID_FLAG_SPECIAL_ITEM_EXPORT ) != 0 )
	{
		uno::Reference< container::XNameContainer > xAttrContainer;
		if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() )
		{
			SvXMLNamespaceMap *pNewNamespaceMap = 0;
			const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap;

			uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() );
			const OUString* pAttribName = aAttribNames.getConstArray();

			const sal_Int32 nCount = aAttribNames.getLength();

			OUStringBuffer sNameBuffer;
			xml::AttributeData aData;
			for( sal_Int32 i=0; i < nCount; i++, pAttribName++ )
			{
				xAttrContainer->getByName( *pAttribName ) >>= aData;
				OUString sAttribName( *pAttribName );

				// extract namespace prefix from attribute name if it exists
				OUString sPrefix;
				const sal_Int32 nColonPos = 
					pAttribName->indexOf( sal_Unicode(':') );
				if( nColonPos != -1 )
					sPrefix = pAttribName->copy( 0, nColonPos );

				if( sPrefix.getLength() )
				{
					OUString sNamespace( aData.Namespace );

					// if the prefix isn't defined yet or has another meaning,
					// we have to redefine it now.
					sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
					if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace )
					{
						sal_Bool bAddNamespace = sal_False;
						if( USHRT_MAX == nKey )
						{
							// The prefix is unused, so it is sufficient
							// to add it to the namespace map.
							bAddNamespace = sal_True;
						}
						else 
						{
							// check if there is a prefix registered for the
							// namepsace URI
							nKey = pNamespaceMap->GetKeyByName( sNamespace );
							if( XML_NAMESPACE_UNKNOWN == nKey )
							{
								// There is no prefix for the namespace, so
								// we have to generate one and have to add it.
								sal_Int32 n=0;
								OUString sOrigPrefix( sPrefix );
								do
								{
									sNameBuffer.append( sOrigPrefix );
									sNameBuffer.append( ++n );
									sPrefix = sNameBuffer.makeStringAndClear();
									nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
								}
								while( nKey != USHRT_MAX );

								bAddNamespace = sal_True;
							}
							else
							{
								// If there is a prefix for the namespace,
								// we reuse that.
								sPrefix = pNamespaceMap->GetPrefixByKey( nKey );
							}
							// In any case, the attribute name has to be adapted.
							sNameBuffer.append( sPrefix );
							sNameBuffer.append( sal_Unicode(':') );
							sNameBuffer.append( pAttribName->copy( nColonPos+1 ) );
							sAttribName = sNameBuffer.makeStringAndClear();
						}

						if( bAddNamespace )
						{
							if( !pNewNamespaceMap )
							{
								pNewNamespaceMap = new SvXMLNamespaceMap( rNamespaceMap );
								pNamespaceMap = pNewNamespaceMap;
							}
							pNewNamespaceMap->Add( sPrefix, sNamespace );
							sNameBuffer.append( GetXMLToken(XML_XMLNS) );
							sNameBuffer.append( sal_Unicode(':') );
							sNameBuffer.append( sPrefix );
							rAttrList.AddAttribute( sNameBuffer.makeStringAndClear(),
													sNamespace );
						}
					}
				}
				OUString sOldValue( rAttrList.getValueByName( sAttribName ) );
				OSL_ENSURE( sOldValue.getLength() == 0, "alien attribute exists already" );
                OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out");
				if( !sOldValue.getLength() )
					rAttrList.AddAttribute( sAttribName, aData.Value );
			}

			delete pNewNamespaceMap;
		}
		else
		{
			handleSpecialItem( rAttrList, rProperty, rUnitConverter,
							   rNamespaceMap, pProperties, nIdx );
		}
	}
	else if ( ( maPropMapper->GetEntryFlags( rProperty.mnIndex ) &
					MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0 )
	{
		OUString aValue;
		const OUString sName( rNamespaceMap.GetQNameByKey(
					maPropMapper->GetEntryNameSpace( rProperty.mnIndex ),
				    maPropMapper->GetEntryXMLName( rProperty.mnIndex ) ) );

		sal_Bool bRemove = sal_False;
		if( ( maPropMapper->GetEntryFlags( rProperty.mnIndex ) &
					MID_FLAG_MERGE_ATTRIBUTE ) != 0 )
		{
			aValue = rAttrList.getValueByName( sName );
			bRemove = sal_True; //aValue.getLength() != 0;
		}

		if( maPropMapper->exportXML( aValue, rProperty, rUnitConverter ) )
		{
			if( bRemove )
				rAttrList.RemoveAttribute( sName );
			rAttrList.AddAttribute( sName, aValue );
		}
	}
}

void SvXMLExportPropertyMapper::exportElementItems(
        SvXMLExport& rExport,
		const ::std::vector< XMLPropertyState >& rProperties,
		sal_uInt16 nFlags,
		const SvUShorts& rIndexArray ) const
{
	const sal_uInt16 nCount = rIndexArray.Count();

	sal_Bool bItemsExported = sal_False;
	OUString sWS( GetXMLToken(XML_WS) );
	for( sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++ )
	{
		const sal_uInt16 nElement = rIndexArray.GetObject( nIndex );

		OSL_ENSURE( 0 != ( maPropMapper->GetEntryFlags(
				rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT),
				"wrong mid flag!" );

		rExport.IgnorableWhitespace();
		handleElementItem( rExport, rProperties[nElement],
                           nFlags, &rProperties, nElement );
		bItemsExported = sal_True;
	}

	if( bItemsExported )
		rExport.IgnorableWhitespace();
}