/*************************************************************************
 *
 *  $RCSfile: xmlnum.cxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: hr $ $Date: 2000/09/18 17:15:00 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PRECOMPILED
#include "filt_pch.hxx"
#endif

#pragma hdrstop

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

#ifndef _SVARRAY_HXX
#include <svtools/svarray.hxx>
#endif

#ifndef _XMLOFF_NMSPMAP_HXX
#include <xmloff/nmspmap.hxx>
#endif
#ifndef _XMLOFF_XMLNMSPE_HXX
#include <xmloff/xmlnmspe.hxx>
#endif
#ifndef _XMLOFF_XMLKYWD_HXX
#include <xmloff/xmlkywd.hxx>
#endif
#ifndef _XMLOFF_I18NMAP_HXX
#include <xmloff/i18nmap.hxx>
#endif
#ifndef _XMLOFF_XMLTKMAP_HXX
#include <xmloff/xmltkmap.hxx>
#endif
#ifndef _SVX_XMLNUME_HXX
#include <xmloff/xmlnume.hxx>
#endif

#ifndef _SVX_NUMITEM_HXX
#include <svx/numitem.hxx>
#endif

#ifndef _POOLFMT_HXX
#include <poolfmt.hxx>
#endif
#ifndef _UNOSETT_HXX
#include <unosett.hxx>
#endif
#ifndef _UNOSTYLE_HXX
#include "unostyle.hxx"
#endif
#ifndef _PAM_HXX
#include <pam.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _NUMRULE_HXX
#include <numrule.hxx>
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif

#ifndef _XMLEXP_HXX
#include "xmlexp.hxx"
#endif
#ifndef _XMLIMP_HXX
#include "xmlimp.hxx"
#endif
#ifndef _XMLNUM_HXX
#include "xmlnum.hxx"
#endif
#ifndef _XMLNUME_HXX
#include "xmlnume.hxx"
#endif
#ifndef _XMLTEXTI_HXX
#include "xmltexti.hxx"
#endif

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;

#ifdef XML_CORE_API
typedef OUString *OUStringPtr;
SV_DECL_PTRARR_DEL( OUStrings_Impl, OUStringPtr, 20, 10 )
SV_IMPL_PTRARR( OUStrings_Impl, OUStringPtr )

SV_DECL_PTRARR_SORT_DEL( OUStringsSort_Impl, OUStringPtr, 20, 10 )
SV_IMPL_OP_PTRARR_SORT( OUStringsSort_Impl, OUStringPtr )

typedef const SwNumRule *ConstSwNumRulePtr;
SV_DECL_PTRARR_SORT( SwNumRulesSort_Impl, ConstSwNumRulePtr, 20, 10 )
SV_IMPL_PTRARR_SORT( SwNumRulesSort_Impl, ConstSwNumRulePtr )
#endif

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

#ifdef XML_CORE_API
void SwXMLListStyleContext::SetAttribute( sal_uInt16 nPrefixKey,
									const OUString& rLocalName,
									const OUString& rValue )
{
	// TODO: use a map here
	if( XML_NAMESPACE_STYLE == nPrefixKey &&
		rLocalName.compareToAscii( sXML_pool_id ) == 0 )
	{
		sal_Int32 nTmp = rValue.toInt32();
		nPoolId = (nTmp < 0L) ? 0U : ( (nTmp > USHRT_MAX) ? USHRT_MAX
									                      : (sal_uInt16)nTmp );
		bHasPoolId = sal_True;
	}
	else
	{
		SvxXMLListStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
	}
}

TYPEINIT1( SwXMLListStyleContext, SvxXMLListStyleContext );

SwXMLListStyleContext::SwXMLListStyleContext( SwXMLImport& rImport,
		sal_uInt16 nPrfx,
		const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList,
		sal_Bool bOutline ) :
	SvxXMLListStyleContext( rImport, nPrfx, rLName, xAttrList, bOutline ),
	nPoolId( USHRT_MAX ),
	bHasPoolId( sal_False )
{
	SetFamily( SFX_STYLE_FAMILY_PSEUDO );
}

SwXMLListStyleContext::~SwXMLListStyleContext()
{
}

extern void lcl_sw3io__copyNumRule( const SwNumRule& rSrc, SwNumRule& rDst );
void SwXMLListStyleContext::InsertNumRule( sal_Bool bAuto )
{
	const OUString& rName = GetName();
	if( IsOutline() )
	{
		SwXMLImport& rSwImport = GetSwImport();
		SwDoc& rDoc = rSwImport.GetDoc();

		ASSERT( rDoc.GetDocShell(),
				"SwXMLListStyleContext::InsertNumRule(): doc shell missing" );
		if( rDoc.GetDocShell() && !(rSwImport.IsStylesOnlyMode() ||
									rSwImport.IsInsertMode()) )
		{
			SwXNumberingRules *pXNumRules =
				new SwXNumberingRules( *rDoc.GetDocShell() );

			Reference< container::XIndexReplace >  xNumRule = pXNumRules;
			FillUnoNumRule( xNumRule, &rSwImport.GetI18NMap() );
		}
	}
	else if( rName.getLength() )
	{
		SwXMLImport& rSwImport = GetSwImport();
		SwDoc& rDoc = rSwImport.GetDoc();

//		String sName( rName );

		// Test Pool-Id and get internationalized name
		String sName( SwXStyleFamilies::GetUIName( rName,
					  SFX_STYLE_FAMILY_PSEUDO ) );
		sal_uInt32 nPoolId = rDoc.GetPoolId( sName, GET_POOLID_NUMRULE );
#if 0
		sal_uInt16 nPoolId = GetPoolId();
		if( bHasPoolId )
		{
			if( nPoolId >= RES_POOLNUMRULE_BEGIN &&
				nPoolId < RES_POOLNUMRULE_END )
			{
				sName = rDoc.GetPoolNm( nPoolId, sName );
			}
			else
			{
				nPoolId = USHRT_MAX;
			}
		}
#endif

		// Create a StarOffice API representation of a SwNumRule
		SwXNumberingRules *pXNumRules = new SwXNumberingRules( rDoc, sName );

		Reference< container::XIndexReplace >  xNumRule = pXNumRules;

		// Get the num rule that is owned (and modified) by the
		// StarOffice API representation.
		SwNumRule *pNumRule = (SwNumRule *)pXNumRules->GetNumRule();

		// Set members that cannot be set by the StarOffice API
		pNumRule->SetAutoRule( bAuto );
		if( USHRT_MAX != nPoolId )
		{
			pNumRule->SetPoolFmtId( nPoolId );
//			if( GetHelpFile().getLength() )
//				pNumRule->SetPoolHlpFileId
//						( (sal_Int8) rDoc.SetDocPattern( GetHelpFile() ) );
//			pNumRule->SetPoolHelpId( (sal_uInt16)GetHelpId() );
		}
		pNumRule->SetContinusNum( IsConsecutive() );

		// Set members that can be set by the StarOffice API
		FillUnoNumRule( xNumRule, &rSwImport.GetI18NMap() );

		sal_Bool bStylesOnlyMode = rSwImport.IsStylesOnlyMode();
		sal_Bool bInsertMode = rSwImport.IsInsertMode();
		sal_uInt16 nStyleFamilyMask = rSwImport.GetStyleFamilyMask();

		sal_Bool bInsertNumRule = sal_False;
		if( pNumRule->IsAutoRule() )
		{
			// Automatic rules will be inserted if the full document
			// or pages styles are loaded only.
			if( !bStylesOnlyMode ||
				(SFX_STYLE_FAMILY_PAGE & nStyleFamilyMask ) != 0 )
			{
				bInsertNumRule = sal_True;

				// If the document is inserted into another or page styles
				// are loaded, the num rule name must be made unique.
				if( bStylesOnlyMode || bInsertMode )
				{
					pNumRule->SetName(
						rDoc.GetUniqueNumRuleName( &sName ) );
					sName = pNumRule->GetName();
				}
			}
		}
		else
		{
			// Number styles will be inserted if the full document or
			// number styles are loaded only
			if( !bStylesOnlyMode ||
				(SFX_STYLE_FAMILY_PSEUDO & nStyleFamilyMask ) != 0 )
			{
				if( bInsertMode )
				{
					SwNumRule *pDocRule = rDoc.FindNumRulePtr( sName );
					if( pDocRule )
						pDocRule->SetInvalidRule( sal_True );
					else
						bInsertNumRule = sal_True;
				}
				else if( bStylesOnlyMode )
				{
					SwNumRule *pDocRule = rDoc.FindNumRulePtr( sName );
					if( pDocRule )
					{
						rDoc.ChgNumRuleFmts( *pNumRule );
						// copy pool/help ids and continous flag
						lcl_sw3io__copyNumRule( *pNumRule, *pDocRule );
					}
					else
					{
						bInsertNumRule = sal_True;
					}
				}
				else
				{
					bInsertNumRule = sal_True;
				}
			}
		}

		if( bInsertNumRule )
		{
			ASSERT( !rDoc.FindNumRulePtr( sName ),
					"NumRule is existing already" );
			sal_uInt16 nPos = rDoc.MakeNumRule( sName, pNumRule );
			if( bAuto )
				rSwImport.AddUnused( *rDoc.GetNumRuleTbl()[nPos] );
		}
		if( sName != String(rName) )
			rSwImport.GetI18NMap().Add( SFX_STYLE_FAMILY_PSEUDO, rName,
										sName );
	}
}
#endif

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

#ifdef XML_CORE_API
SwXMLListItemContext::SwXMLListItemContext(
		SwXMLImport& rImport, sal_uInt16 nPrfx,
		const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList,
		sal_Bool bIsHeader ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	nStartValue( USHRT_MAX )
{
	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );
		const OUString& rValue = xAttrList->getValueByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		if( !bIsHeader && XML_NAMESPACE_TEXT == nPrefix &&
			aLocalName.compareToAscii( sXML_start_value ) == 0 )
		{
			sal_Int32 nTmp = rValue.toInt32();
			if( nTmp >= 0 && nTmp <= USHRT_MAX )
				nStartValue = (sal_uInt16)nTmp;
		}
	}

	ASSERT( !GetSwImport().GetListItem(),
		"SwXMLListItemContext::SwXMLListItemContext: list item is existing" );

	// If this is a <text:list-item> element, then remember it as a sign
	// that a bullet has to be generated.
	if( !bIsHeader )
		GetSwImport().SetListItem( this );
}

SwXMLListItemContext::~SwXMLListItemContext()
{
}

void SwXMLListItemContext::EndElement()
{
	// finish current list item
	GetSwImport().SetListItem( 0 );
}

SvXMLImportContext *SwXMLListItemContext::CreateChildContext(
		sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

	const SvXMLTokenMap& rTokenMap = GetSwImport().GetBodyElemTokenMap();
	sal_Bool bOrdered = sal_False;
	sal_Bool bHeading = sal_False;
	switch( rTokenMap.Get( nPrefix, rLocalName ) )
	{
	case XML_TOK_SW_H:
		bHeading = sal_True;
	case XML_TOK_SW_P:
		pContext = new SwXMLParaContext( GetSwImport(),nPrefix, rLocalName,
										 xAttrList, bHeading );
		break;
	case XML_TOK_SW_ORDERED_LIST:
		bOrdered = sal_True;
	case XML_TOK_SW_UNORDERED_LIST:
		pContext = new SwXMLListBlockContext( GetSwImport(),nPrefix, rLocalName,
											  xAttrList, bOrdered );
		break;
	}

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

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

enum SwXMLTextListBlockAttrTokens
{
	XML_TOK_SW_LIST_BLOCK_STYLE_NAME,
	XML_TOK_SW_LIST_BLOCK_CONTINUE_NUMBERING,
	XML_TOK_SW_LIST_BLOCK_END=XML_TOK_UNKNOWN
};

static __FAR_DATA SvXMLTokenMapEntry aTextListBlockAttrTokenMap[] =
{
	{ XML_NAMESPACE_TEXT, sXML_style_name,
			XML_TOK_SW_LIST_BLOCK_STYLE_NAME },
	{ XML_NAMESPACE_TEXT, sXML_continue_numbering,
			XML_TOK_SW_LIST_BLOCK_CONTINUE_NUMBERING },
	XML_TOKEN_MAP_END
};

enum SwXMLTextListBlockElemTokens
{
	XML_TOK_SW_LIST_HEADER,
	XML_TOK_SW_LIST_ITEM,
	XML_TOK_SW_LIST_BLOCK_ELEM_END=XML_TOK_UNKNOWN
};

static __FAR_DATA SvXMLTokenMapEntry aTextListBlockElemTokenMap[] =
{
	{ XML_NAMESPACE_TEXT, sXML_list_header, XML_TOK_SW_LIST_HEADER },
	{ XML_NAMESPACE_TEXT, sXML_list_item, 	XML_TOK_SW_LIST_ITEM	 },
	XML_TOKEN_MAP_END
};

SwXMLListBlockContext::SwXMLListBlockContext(
		SwXMLImport& rImport, sal_uInt16 nPrfx,
		const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList,
		sal_Bool bOrd ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	xParentListBlock( rImport.GetListBlock() ),
	nLevel( 0U ),
	bOrdered( bOrd ),
	bRestartNumbering( sal_True ),
	bCreateFmt( sal_False )
{
	// Inherit style name from parent list, as well as the flags whether
	// numbering must be restarted and formats have to be created.
	if( xParentListBlock.Is() )
	{
		SwXMLListBlockContext *pParent =
			(SwXMLListBlockContext *)&xParentListBlock;
		sStyleName = pParent->GetStyleName();
		nLevel = pParent->GetLevel() + 1;
		bRestartNumbering = pParent->IsRestartNumbering();
		bCreateFmt = pParent->bCreateFmt;
	}

	const SvXMLTokenMap& rTokenMap =
		GetSwImport().GetTextListBlockAttrTokenMap();

	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );
		const OUString& rValue = xAttrList->getValueByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		switch( rTokenMap.Get( nPrefix, aLocalName ) )
		{
		case XML_TOK_SW_LIST_BLOCK_CONTINUE_NUMBERING:
			bRestartNumbering = rValue.compareToAscii( sXML_true ) != 0;
			break;
		case XML_TOK_SW_LIST_BLOCK_STYLE_NAME:
			sStyleName = rValue;
			break;
		}
	}

	SwDoc& rDoc = GetSwImport().GetDoc();
	String sName;
	SwNumRule *pNumRule = 0;
	if( sStyleName.getLength() )
	{
		sName = GetSwImport().GetI18NMap().Get( SFX_STYLE_FAMILY_PSEUDO,
													 sStyleName );
		pNumRule = rDoc.FindNumRulePtr( sName );

		// If the style has not been used, the restart numbering has
		// to be set never.
		if( pNumRule && bRestartNumbering && !rDoc.IsUsed( *pNumRule ) )
			bRestartNumbering = sal_False;
	}

	if( !pNumRule )
	{
		// If no style name has been specified for this style and for any
		// parent or if no num rule this the specified name is existing,
		// create a new one.
		if( !sStyleName.getLength() )
		{
			sName = rDoc.GetUniqueNumRuleName();
			sStyleName = sName;
		}
		sal_uInt16 nPos = rDoc.MakeNumRule( sName );
		pNumRule = rDoc.GetNumRuleTbl()[nPos];
		GetSwImport().AddUnused( *pNumRule );

		// Because there is no list style sheet for this style, a default
		// format must be set for any level of this num rule.
		bCreateFmt = sal_True;

		// Because its a new num rule, numbering mist be restarted never.
		bRestartNumbering = sal_False;
	}

	if( bCreateFmt )
	{
		// Create a default format for this level.
		SwNumFmt aNumFmt( pNumRule->Get(nLevel) );

		if( bOrdered )
		{
			aNumFmt.eType = SVX_NUM_ARABIC;
		}
		else
		{
			aNumFmt.SetBulletFont( &SwNumRule::GetDefBulletFont() );
			aNumFmt.eType = SVX_NUM_CHAR_SPECIAL;
			aNumFmt.SetBulletChar( cBulletChar );
			aNumFmt.SetCharFmt(
					rDoc.GetCharFmtFromPool(RES_POOLCHR_BUL_LEVEL) );
		}
		pNumRule->Set( nLevel, aNumFmt );

		rDoc.ChgNumRuleFmts( *pNumRule );
	}

	// Remember this list block.
	GetSwImport().SetListBlock( this );

	// There is no list item by now.
	GetSwImport().SetListItem( 0 );
}

SwXMLListBlockContext::~SwXMLListBlockContext()
{
}

void SwXMLListBlockContext::EndElement()
{
	// Numbering has not to be restarted if it has been restarted within
	// a child list.
	SwXMLListBlockContext *pParent = (SwXMLListBlockContext *)&xParentListBlock;
	if( pParent )
	{
		pParent->bRestartNumbering = bRestartNumbering;
	}

	// Restore current list block.
	GetSwImport().SetListBlock( pParent );

	// Any paragraph following the list within the same list item mist not
	// be numbered.
	GetSwImport().SetListItem( 0 );
}

SvXMLImportContext *SwXMLListBlockContext::CreateChildContext(
		sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

	const SvXMLTokenMap& rTokenMap =
								GetSwImport().GetTextListBlockElemTokenMap();
	sal_Bool bHeader = sal_False;
	switch( rTokenMap.Get( nPrefix, rLocalName ) )
	{
	case XML_TOK_SW_LIST_HEADER:
		bHeader = sal_True;
	case XML_TOK_SW_LIST_ITEM:
		pContext = new SwXMLListItemContext( GetSwImport(), nPrefix, rLocalName,
							 				 xAttrList, bHeader );
		break;
	}

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

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

SwXMLListItemContext *SwXMLImport::GetListItem()
{
	return (SwXMLListItemContext *)&xListItem;
}

void SwXMLImport::SetListItem( SwXMLListItemContext *pListItem )
{
	xListItem = pListItem;
}

SwXMLListBlockContext *SwXMLImport::GetListBlock()
{
	return (SwXMLListBlockContext *)&xListBlock;
}

void SwXMLImport::SetListBlock( SwXMLListBlockContext *pListBlock )
{
	xListBlock = pListBlock;
}


const SvXMLTokenMap& SwXMLImport::GetTextListBlockAttrTokenMap()
{
	if( !pTextListBlockAttrTokenMap )
		pTextListBlockAttrTokenMap =
			new SvXMLTokenMap( aTextListBlockAttrTokenMap );

	return *pTextListBlockAttrTokenMap;
}

const SvXMLTokenMap& SwXMLImport::GetTextListBlockElemTokenMap()
{
	if( !pTextListBlockElemTokenMap )
		pTextListBlockElemTokenMap =
			new SvXMLTokenMap( aTextListBlockElemTokenMap );

	return *pTextListBlockElemTokenMap;
}

void SwXMLImport::RemoveUnusedNumRules()
{
	if( pUnusedNumRules )
	{
		sal_uInt16 nCount = pUnusedNumRules->Count();
		for( sal_uInt16 i=0; i<nCount; i++ )
		{
			const SwNumRule *pNumRule = (*pUnusedNumRules)[i];
			ASSERT( !pDoc->IsUsed( *pNumRule ),
					"SwXMLImport::RemoveUnusedNumRules()" );
			pDoc->DelNumRule( pNumRule->GetName() );
		}
		delete pUnusedNumRules;
	}
}

void SwXMLImport::AddUnused( const SwNumRule& rNumRule )
{
	if( !pUnusedNumRules )
		pUnusedNumRules = new SwNumRulesSort_Impl;

	pUnusedNumRules->Insert( &rNumRule );
}

void SwXMLImport::SetUsed( const SwNumRule& rNumRule )
{
	if( pUnusedNumRules && pUnusedNumRules->Seek_Entry( &rNumRule ) )
		pUnusedNumRules->Remove( &rNumRule );
}
#endif

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

#ifdef XML_CORE_API
class SwXMLNumRuleExport_Impl : public SvxXMLNumRuleExport
{
	const SwNumRule *pNumRule;
	SwDoc& rDoc;

protected:

	virtual Reference< container::XIndexReplace >  GetUNONumRule() const;

	virtual void AddListStyleAttributes();

public:

	SwXMLNumRuleExport_Impl(
			SwXMLExport& rExport);
	virtual ~SwXMLNumRuleExport_Impl();

	void ExportSwNumRule( const SwNumRule& rNumRule,
						  const SvXMLNamespaceMap& rNamespMap );
};

Reference< container::XIndexReplace > SwXMLNumRuleExport_Impl::GetUNONumRule() const
{
	Reference< container::XIndexReplace > xNumRule;

	if( pNumRule )
	{
		// list
		xNumRule = new SwXNumberingRules( *pNumRule );
	}
	else
	{
		// outline
		ASSERT( rDoc.GetDocShell(),
				"SwXMLNumRuleExport_Impl::GetUNONumRule(): doc shell missing" );
		if( rDoc.GetDocShell() )
			xNumRule = new SwXNumberingRules( *rDoc.GetDocShell() );
	}

	return xNumRule;
}

void SwXMLNumRuleExport_Impl::AddListStyleAttributes()
{
	ASSERT( pNumRule, "no sw num rule" );
	if( !pNumRule )
		return;

#if 0
	// style:pool-id="..."
	if( !pNumRule->IsAutoRule() )
	{
		OUStringBuffer sTmp( 5L );
		sTmp.append( (sal_Int32)pNumRule->GetPoolFmtId() );
		GetExport().AddAttribute( XML_NAMESPACE_STYLE, sXML_pool_id,
					  sTmp.makeStringAndClear() );
	}

	// style:help-file-name="..." and style:help-id="..."
	if( UCHAR_MAX != pNumRule->GetPoolHlpFileId() )
	{
		GetExport().AddAttribute( XML_NAMESPACE_STYLE, sXML_help_file_name,
				  	  *rDoc.GetDocPattern( pNumRule->GetPoolHlpFileId() ) );
		OUStringBuffer sTmp( 5L );
		sTmp.append( (sal_Int32)pNumRule->GetPoolHelpId() );
		GetExport().AddAttribute( XML_NAMESPACE_STYLE, sXML_help_id,
					  sTmp.makeStringAndClear() );
	}
#endif
}

SwXMLNumRuleExport_Impl::SwXMLNumRuleExport_Impl(
		SwXMLExport& rExport ) :
	SvxXMLNumRuleExport( rExport ),
	rDoc( rExport.GetDoc() ),
	pNumRule( 0 )
{
}

SwXMLNumRuleExport_Impl::~SwXMLNumRuleExport_Impl()
{
}

void SwXMLNumRuleExport_Impl::ExportSwNumRule( const SwNumRule& rNumRule,
								 const SvXMLNamespaceMap& rNamespMap )
{
	pNumRule = &rNumRule;

	String sName = rNumRule.GetName();
	if( !rNumRule.IsAutoRule() )
		sName = SwXStyleFamilies::GetProgrammaticName(
									rNumRule.GetName(),
									SFX_STYLE_FAMILY_PSEUDO );
	Export( sName, rNumRule.IsContinusNum() );

	pNumRule = 0;
}

#endif
// ---------------------------------------------------------------------

#ifdef XML_CORE_API
void SwXMLExport::ExportNumRules( sal_Bool bAuto, sal_Bool bUsed )
{
	sal_uInt16 nArrLen = pDoc->GetNumRuleTbl().Count();
	if( 0 == nArrLen && bAuto )
		return;

	SwXMLNumRuleExport_Impl aNumRuleExport( *this );

	if( !bAuto )
		aNumRuleExport.ExportOutline();

	for( sal_uInt16 i=0; i<nArrLen; i++ )
	{
		const SwNumRule *pNumRule = pDoc->GetNumRuleTbl()[i];
		if( pNumRule->IsAutoRule() == bAuto &&
			(!bUsed || pDoc->IsUsed( *pNumRule )) )
			aNumRuleExport.ExportSwNumRule( *pNumRule, GetNamespaceMap() );
	}
}

void SwXMLExport::ExportListChange( const SwXMLNumRuleInfo& rPrevInfo,
					  			    const SwXMLNumRuleInfo& rNextInfo )
{
	// end a list
	if( rPrevInfo.GetLevel() > 0 &&
		( rNextInfo.GetNumRule() != rPrevInfo.GetNumRule() ||
		  rNextInfo.GetLevel() < rPrevInfo.GetLevel() ||
	   	  rNextInfo.IsRestart()	) )
	{
		sal_Int8 nPrevLevel = rPrevInfo.GetLevel();
		sal_Int8 nNextLevel =
			( rNextInfo.GetNumRule() != rPrevInfo.GetNumRule() ||
			  rNextInfo.IsRestart() ) ?  0 : rNextInfo.GetLevel();

		ASSERT( pListElements &&
				pListElements->Count() >= 2*(nNextLevel-nPrevLevel),
				"SwXMLExport::ExportListChange: list elements missing" );

		for( sal_Int8 i=nPrevLevel; i > nNextLevel; i-- )
		{
			for( sal_uInt16 j=0; j<2; j++ )
			{
				OUString *pElem = (*pListElements)[pListElements->Count()-1];
				pListElements->Remove( pListElements->Count()-1 );

				GetDocHandler()->ignorableWhitespace( sWS );
				GetDocHandler()->endElement( *pElem );

				delete pElem;
			}
		}
	}

	// start a new list
	if( rNextInfo.GetLevel() > 0 &&
		( rPrevInfo.GetNumRule() != rNextInfo.GetNumRule() ||
		  rPrevInfo.GetLevel() < rNextInfo.GetLevel() ||
	   	  rNextInfo.IsRestart() ) )
	{
		sal_Int8 nPrevLevel =
			( rNextInfo.GetNumRule() != rPrevInfo.GetNumRule() ||
			  rNextInfo.IsRestart() ) ? 0 : rPrevInfo.GetLevel();
		sal_Int8 nNextLevel = rNextInfo.GetLevel();

		const OUString& rListName = rNextInfo.GetNumRule()->GetName();
		sal_Bool bListExported = pExportedLists &&
				 	 pExportedLists->Seek_Entry( (OUString *)&rListName );
		sal_Bool bContinue = rPrevInfo.GetNumRule() != rNextInfo.GetNumRule() &&
						 !rNextInfo.IsRestart() && bListExported;
		if( !bListExported )
		{
			if( !pExportedLists )
				pExportedLists = new OUStringsSort_Impl;
			pExportedLists->Insert( new OUString(rListName) );
		}

		for( sal_Int8 i=nPrevLevel; i < nNextLevel; i++)
		{
			// <text:ordered-list> or <text:unordered-list>
			CheckAttrList();
			if( 0 == i )
				AddAttribute( XML_NAMESPACE_TEXT, sXML_style_name,
					SwXStyleFamilies::GetProgrammaticName( rListName,
												SFX_STYLE_FAMILY_PSEUDO ) );
			if( bContinue && rNextInfo.IsOrdered() )
				AddAttributeASCII( XML_NAMESPACE_TEXT, sXML_continue_numbering,
								   sXML_true );

			const sal_Char *pLName =
					rNextInfo.IsOrdered() ? sXML_ordered_list
										  : sXML_unordered_list;

			OUString *pElem = new OUString( GetNamespaceMap().GetQNameByKey(
										XML_NAMESPACE_TEXT,
										OUString::createFromAscii(pLName) ) );
			GetDocHandler()->ignorableWhitespace( sWS );
			GetDocHandler()->startElement( *pElem, GetXAttrList() );
			ClearAttrList();

			if( !pListElements )
				pListElements = new OUStrings_Impl;
			pListElements->Insert( pElem, pListElements->Count() );

			// <text:list-header> or <text:list-item>
			CheckAttrList();
			if( rNextInfo.HasStartValue() )
			{
				OUStringBuffer aBuffer;
				aBuffer.append( (sal_Int32)rNextInfo.GetStartValue() );
				AddAttribute( XML_NAMESPACE_TEXT, sXML_start_value,
						      aBuffer.makeStringAndClear() );
			}
			pLName = (rNextInfo.IsNumbered() || i+1 < nNextLevel)
						? sXML_list_item
						: sXML_list_header;
			pElem = new OUString(  GetNamespaceMap().GetQNameByKey(
										XML_NAMESPACE_TEXT,
										OUString::createFromAscii(pLName) ) );
			GetDocHandler()->ignorableWhitespace( sWS );
			GetDocHandler()->startElement( *pElem, GetXAttrList() );

			pListElements->Insert( pElem, pListElements->Count() );
		}
	}

	if( rNextInfo.GetLevel() > 0 && rNextInfo.IsNumbered() &&
		rPrevInfo.GetNumRule() == rNextInfo.GetNumRule() &&
		rPrevInfo.GetLevel() >= rNextInfo.GetLevel() &&
		!rNextInfo.IsRestart() )
	{
		// </text:list-item> or </text:list-header>
		ASSERT( pListElements && pListElements->Count() >= 2,
				"SwXMLExport::ExportListChange: list elements missing" );

		OUString *pElem = (*pListElements)[pListElements->Count()-1];
		GetDocHandler()->ignorableWhitespace( sWS );
		GetDocHandler()->endElement( *pElem );

		pListElements->Remove( pListElements->Count()-1 );
		delete pElem;

		// <text:list-item>
		CheckAttrList();
		pElem = new OUString( GetNamespaceMap().GetQNameByKey(
								XML_NAMESPACE_TEXT,
								OUString::createFromAscii(sXML_list_item) ) );
		GetDocHandler()->ignorableWhitespace( sWS );
		GetDocHandler()->startElement( *pElem, GetXAttrList() );

		pListElements->Insert( pElem, pListElements->Count() );
	}
}

void SwXMLExport::_FinitNumRuleExport()
{
	ASSERT( !pListElements || 0 == pListElements->Count(),
			"SwXMLExport::_FinitNumRuleExport: list elements pending" );
	delete pListElements;
	pListElements = 0;

	delete pExportedLists;
	pExportedLists = 0;
}

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

void SwXMLNumRuleInfo::Set( const SwNode& rNode )
{
	Reset();

	if( rNode.IsTxtNode() )
	{
		const SwTxtNode *pTxtNd = rNode.GetTxtNode();
		if( pTxtNd->GetNum() )
		{
			pNumRule = pTxtNd->GetNumRule();
			if( pNumRule )
			{
				const SwNodeNum& rNum = *pTxtNd->GetNum();
				nLevel = GetRealLevel( rNum.GetLevel() ) + 1;

				if( (rNum.GetLevel() & NO_NUMLEVEL) == 0 )
				{
					bIsNumbered = sal_True;
					bIsRestart = rNum.IsStart();
					nStartValue = rNum.GetSetValue();
				}
				SvxExtNumType eType = pNumRule->Get( nLevel-1 ).eType;
				if( SVX_NUM_CHAR_SPECIAL != eType &&
				    SVX_NUM_BITMAP != eType )
					bIsOrdered = sal_True;
			}
		}
	}
}

#endif

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

	  Source Code Control System - Header

	  $Header: /cvs/oo/sw/sw/source/filter/xml/xmlnum.cxx,v 1.1.1.1 2000/09/18 17:15:00 hr Exp $

	  Source Code Control System - Update

	  $Log: xmlnum.cxx,v $
	  Revision 1.1.1.1  2000/09/18 17:15:00  hr
	  initial import
	
	  Revision 1.21  2000/09/18 16:05:07  willem.vandorp
	  OpenOffice header added.
	
	  Revision 1.20  2000/08/24 11:16:42  mib
	  text import continued
	
	  Revision 1.19  2000/08/10 10:22:16  mib
	  #74404#: Adeptions to new XSL/XLink working draft
	
	  Revision 1.18  2000/08/02 14:52:39  mib
	  text export continued
	
	  Revision 1.17  2000/07/21 12:55:15  mib
	  text import/export using StarOffice API
	
	  Revision 1.16  2000/06/08 09:45:54  aw
	  changed to use functionality from xmloff project now
	
	  Revision 1.15  2000/05/03 12:08:05  mib
	  unicode
	
	  Revision 1.14  2000/03/21 15:10:56  os
	  UNOIII
	
	  Revision 1.13  2000/03/13 14:33:44  mib
	  UNO3

	  Revision 1.12  2000/03/06 10:46:11  mib
	  #72585#: toInt32

	  Revision 1.11  2000/02/11 14:41:16  hr
	  #70473# changes for unicode ( patched by automated patchtool )

	  Revision 1.10  2000/01/27 08:59:02  mib
	  #70271#: outline numbering

	  Revision 1.9  2000/01/20 10:03:16  mib
	  #70271#: Lists reworked

	  Revision 1.8  2000/01/12 15:00:23  mib
	  #70271#: lists

	  Revision 1.7  2000/01/06 15:08:28  mib
	  #70271#:separation of text/layout, cond. styles, adaptions to wd-xlink-19991229

	  Revision 1.6  1999/11/10 15:08:09  mib
	  Import now uses XMLItemMapper

	  Revision 1.5  1999/11/03 11:13:50  mib
	  list style import continued

	  Revision 1.4  1999/11/01 11:38:50  mib
	  List style import

	  Revision 1.3  1999/10/26 13:33:12  mib
	  list styles continued

	  Revision 1.2  1999/10/25 10:41:48  mib
	  Using new OUString ASCII methods

	  Revision 1.1  1999/10/22 09:51:29  mib
	  List style import


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

