/**************************************************************
 * 
 * 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 "MergeElemTContext.hxx"
#include "MutableAttrList.hxx"
#ifndef _XMLOFF_TRANSFORMERBASE_HXX
#include "TransformerBase.hxx"
#endif
#include "TransformerActions.hxx"
#include "AttrTransformerAction.hxx"
#include "ElemTransformerAction.hxx"
#include "IgnoreTContext.hxx"
#include "xmloff/xmlnmspe.hxx"

using ::rtl::OUString;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

class XMLParagraphTransformerContext : public XMLTransformerContext 
{
public:
	TYPEINFO();

	XMLParagraphTransformerContext( XMLTransformerBase& rTransformer, 
						   const ::rtl::OUString& rQName );

	virtual ~XMLParagraphTransformerContext();

	// Create a childs element context. By default, the import's
	// CreateContext method is called to create a new default context.
	virtual XMLTransformerContext *CreateChildContext( sal_uInt16 nPrefix,
								   const ::rtl::OUString& rLocalName,
								   const ::rtl::OUString& rQName,
								   const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

	// StartElement is called after a context has been constructed and
	// before a elements context is parsed. It may be used for actions that
	// require virtual methods. The default is to do nothing.
	virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );

	// EndElement is called before a context will be destructed, but
	// after a elements context has been parsed. It may be used for actions
	// that require virtual methods. The default is to do nothing.
	virtual void EndElement();

	// This method is called for all characters that are contained in the
	// current element. The default is to ignore them.
	virtual void Characters( const ::rtl::OUString& rChars );
};

TYPEINIT1( XMLParagraphTransformerContext, XMLTransformerContext );

XMLParagraphTransformerContext::XMLParagraphTransformerContext( 
		XMLTransformerBase& rImp, 
		const OUString& rQName ) :
	XMLTransformerContext( rImp, rQName )
{
}

XMLParagraphTransformerContext::~XMLParagraphTransformerContext()
{
}

XMLTransformerContext *XMLParagraphTransformerContext::CreateChildContext(
		sal_uInt16 /*nPrefix*/,
		const OUString& /*rLocalName*/,
		const OUString& rQName,
		const Reference< XAttributeList >& )
{
	XMLTransformerContext *pContext = 0;

    pContext = new XMLIgnoreTransformerContext( GetTransformer(), 
												rQName, sal_True );

	return pContext;
}

void XMLParagraphTransformerContext::StartElement( const Reference< XAttributeList >& rAttrList )
{
    XMLTransformerContext::StartElement( rAttrList );
}

void XMLParagraphTransformerContext::EndElement()
{
    XMLTransformerContext::EndElement();
}

void XMLParagraphTransformerContext::Characters( const OUString& rChars )
{
    XMLTransformerContext::Characters( rChars );
}

class XMLPersTextContentRNGTransformTContext : public XMLPersTextContentTContext
{
public:
	TYPEINFO();

    XMLPersTextContentRNGTransformTContext(
        XMLTransformerBase& rTransformer,
        const ::rtl::OUString& rQName,
        sal_uInt16 nPrefix,
        ::xmloff::token::XMLTokenEnum eToken );
    virtual ~XMLPersTextContentRNGTransformTContext();

	virtual void Characters( const ::rtl::OUString& rChars );
};

TYPEINIT1( XMLPersTextContentRNGTransformTContext, XMLPersAttrListTContext );

XMLPersTextContentRNGTransformTContext::XMLPersTextContentRNGTransformTContext(
    XMLTransformerBase& rTransformer,
    const ::rtl::OUString& rQName,
    sal_uInt16 nPrefix,
    ::xmloff::token::XMLTokenEnum eToken ) :
        XMLPersTextContentTContext(
            rTransformer, rQName, nPrefix, eToken )
{}

XMLPersTextContentRNGTransformTContext::~XMLPersTextContentRNGTransformTContext()
{}

void XMLPersTextContentRNGTransformTContext::Characters( const ::rtl::OUString& rChars )
{
    OUString aConvChars( rChars );
    GetTransformer().ConvertRNGDateTimeToISO( aConvChars );
    XMLPersTextContentTContext::Characters( aConvChars );
}


TYPEINIT1( XMLMergeElemTransformerContext, XMLTransformerContext );

void XMLMergeElemTransformerContext::ExportStartElement()
{
	XMLPersTextContentTContextVector::iterator aIter = m_aChildContexts.begin();

	for( ; aIter != m_aChildContexts.end(); ++aIter )
	{
		XMLPersTextContentTContext *pContext = (*aIter).get();
		static_cast< XMLMutableAttributeList * >( m_xAttrList.get() )
			->AddAttribute( pContext->GetExportQName(), 
							pContext->GetTextContent() );
	}
	XMLTransformerContext::StartElement( m_xAttrList );

	m_bStartElementExported = sal_True;
}

XMLMergeElemTransformerContext::XMLMergeElemTransformerContext( 
		XMLTransformerBase& rImp, 
		const OUString& rQName,
	   sal_uInt16 nActionMap ) :
	XMLTransformerContext( rImp, rQName ),
	m_nActionMap( nActionMap ),
	m_bStartElementExported( sal_False )
{
}

XMLMergeElemTransformerContext::~XMLMergeElemTransformerContext()
{
}

void XMLMergeElemTransformerContext::StartElement( 
	const Reference< XAttributeList >& rAttrList )
{
	XMLMutableAttributeList *pMutableAttrList = 
		new XMLMutableAttributeList( rAttrList, sal_True );
	m_xAttrList = pMutableAttrList;

	sal_Int16 nAttrCount = m_xAttrList.is() ? m_xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = m_xAttrList->getNameByIndex( i );
		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, 
																&aLocalName );
        sal_Bool bRemove = sal_True;
        if( XML_NAMESPACE_OFFICE == nPrefix)
        {
            if (IsXMLToken( aLocalName, XML_DISPLAY ) )
                bRemove = sal_False;
            else if (IsXMLToken( aLocalName, XML_AUTHOR ) )
                bRemove = sal_False;
            else if (IsXMLToken( aLocalName, XML_CREATE_DATE ) )
                bRemove = sal_False;
            else if (IsXMLToken( aLocalName, XML_CREATE_DATE_STRING ) )
                bRemove = sal_False;
        }
        if (bRemove)
        {
            pMutableAttrList->RemoveAttributeByIndex( i );
            --i;
            --nAttrCount;
        }
	}
}

XMLTransformerContext *XMLMergeElemTransformerContext::CreateChildContext(
		sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const OUString& rQName,
		const Reference< XAttributeList >& rAttrList )
{
	XMLTransformerContext *pContext = 0;

	if( !m_bStartElementExported )
	{
		XMLTransformerActions *pActions = 
			GetTransformer().GetUserDefinedActions( m_nActionMap );
		OSL_ENSURE( pActions, "go no actions" );
		if( pActions )
		{
			XMLTransformerActions::key_type aKey( nPrefix, rLocalName );
			XMLTransformerActions::const_iterator aIter =
				pActions->find( aKey );

			if( !(aIter == pActions->end()) )
			{
				switch( (*aIter).second.m_nActionType )
				{
				case XML_ATACTION_MOVE_FROM_ELEM_RNG2ISO_DATETIME:
					{
						XMLPersTextContentTContext *pTC =
							new XMLPersTextContentRNGTransformTContext(
									GetTransformer(), rQName,
								    (*aIter).second.GetQNamePrefixFromParam1(),
									(*aIter).second.GetQNameTokenFromParam1() );
						XMLPersTextContentTContextVector::value_type aVal(pTC);
						m_aChildContexts.push_back( aVal );
						pContext = pTC;
					}
					break;
                case XML_ATACTION_MOVE_FROM_ELEM:
					{
						XMLPersTextContentTContext *pTC =
							new XMLPersTextContentTContext( 
									GetTransformer(), rQName,
								    (*aIter).second.GetQNamePrefixFromParam1(),
									(*aIter).second.GetQNameTokenFromParam1() );
						XMLPersTextContentTContextVector::value_type aVal(pTC);
						m_aChildContexts.push_back( aVal );
						pContext = pTC;
					}
					break;
                case XML_ETACTION_EXTRACT_CHARACTERS:
                    {
		                if( !m_bStartElementExported )
			                ExportStartElement();
                        XMLParagraphTransformerContext* pPTC =
	                        new XMLParagraphTransformerContext( GetTransformer(),
						    rQName);
						pContext = pPTC;
                    }
                    break;
				default:
					OSL_ENSURE( sal_False, "unknown action" );
					break;
				}
			}
		}
	}
    else
	{
		XMLTransformerActions *pActions = 
			GetTransformer().GetUserDefinedActions( m_nActionMap );
		OSL_ENSURE( pActions, "go no actions" );
		if( pActions )
		{
			XMLTransformerActions::key_type aKey( nPrefix, rLocalName );
			XMLTransformerActions::const_iterator aIter =
				pActions->find( aKey );

			if( !(aIter == pActions->end()) )
			{
				switch( (*aIter).second.m_nActionType )
				{
                case XML_ETACTION_EXTRACT_CHARACTERS:
                    {
		                if( !m_bStartElementExported )
			                ExportStartElement();
                        XMLParagraphTransformerContext* pPTC =
	                        new XMLParagraphTransformerContext( GetTransformer(),
						    rQName);
						pContext = pPTC;
                    }
                    break;
				default:
					OSL_ENSURE( sal_False, "unknown action" );
					break;
				}
			}
		}
	}

	// default is copying
	if( !pContext )
	{
		if( !m_bStartElementExported )
			ExportStartElement();
		pContext = XMLTransformerContext::CreateChildContext( nPrefix,
															  rLocalName,
															  rQName,
															  rAttrList );
	}

	return pContext;
}

void XMLMergeElemTransformerContext::EndElement()
{
	if( !m_bStartElementExported )
		ExportStartElement();
	XMLTransformerContext::EndElement();
}

void XMLMergeElemTransformerContext::Characters( const OUString& )
{
	// ignore
}