/**************************************************************
 * 
 * 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 <xmloff/controlpropertyhdl.hxx>
#include <com/sun/star/awt/TextAlign.hpp>
#include <com/sun/star/awt/FontWidth.hpp>
#include <com/sun/star/awt/FontEmphasisMark.hpp>
#include <xmloff/xmltypes.hxx>
#include "xmloff/NamedBoolPropertyHdl.hxx"
#include "formenums.hxx"
#include <xmloff/xmluconv.hxx>
#include <xmloff/xmltoken.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>
#include "callbacks.hxx"
#include <xmloff/XMLConstantsPropertyHandler.hxx>

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

	using namespace ::com::sun::star::uno;
	using namespace ::com::sun::star::awt;
	using namespace ::com::sun::star::beans;
	using namespace ::xmloff::token;

	//=====================================================================
	//= OControlPropertyHandlerFactory
	//=====================================================================
	//---------------------------------------------------------------------
	OControlPropertyHandlerFactory::OControlPropertyHandlerFactory()
		:m_pTextAlignHandler(NULL)
		,m_pControlBorderStyleHandler(NULL)
        ,m_pControlBorderColorHandler(NULL)
		,m_pRotationAngleHandler(NULL)
		,m_pFontWidthHandler(NULL)
		,m_pFontEmphasisHandler(NULL)
		,m_pFontReliefHandler(NULL)
	{
	}

	//---------------------------------------------------------------------
	OControlPropertyHandlerFactory::~OControlPropertyHandlerFactory()
	{
		delete m_pTextAlignHandler;
		delete m_pControlBorderStyleHandler;
        delete m_pControlBorderColorHandler;
		delete m_pRotationAngleHandler;
		delete m_pFontWidthHandler;
		delete m_pFontEmphasisHandler;
		delete m_pFontReliefHandler;
	}

	//---------------------------------------------------------------------
	const XMLPropertyHandler* OControlPropertyHandlerFactory::GetPropertyHandler(sal_Int32 _nType) const
	{
		const XMLPropertyHandler* pHandler = NULL;

		switch (_nType)
		{
			case XML_TYPE_TEXT_ALIGN:
				if (!m_pTextAlignHandler)
					m_pTextAlignHandler = new XMLConstantsPropertyHandler(OEnumMapper::getEnumMap(OEnumMapper::epTextAlign), XML_TOKEN_INVALID );
				pHandler = m_pTextAlignHandler;
				break;

			case XML_TYPE_CONTROL_BORDER:
				if (!m_pControlBorderStyleHandler)
                    m_pControlBorderStyleHandler = new OControlBorderHandler( OControlBorderHandler::STYLE );
				pHandler = m_pControlBorderStyleHandler;
				break;

			case XML_TYPE_CONTROL_BORDER_COLOR:
				if ( !m_pControlBorderColorHandler )
					m_pControlBorderColorHandler = new OControlBorderHandler( OControlBorderHandler::COLOR );
				pHandler = m_pControlBorderColorHandler;
				break;

			case XML_TYPE_ROTATION_ANGLE:
				if (!m_pRotationAngleHandler)
					m_pRotationAngleHandler = new ORotationAngleHandler;
				pHandler = m_pRotationAngleHandler;
				break;

			case XML_TYPE_FONT_WIDTH:
				if (!m_pFontWidthHandler)
					m_pFontWidthHandler = new OFontWidthHandler;
				pHandler = m_pFontWidthHandler;
				break;

			case XML_TYPE_CONTROL_TEXT_EMPHASIZE:
				if (!m_pFontEmphasisHandler)
					m_pFontEmphasisHandler = new XMLConstantsPropertyHandler( OEnumMapper::getEnumMap(OEnumMapper::epFontEmphasis), XML_NONE );
				pHandler = m_pFontEmphasisHandler;
				break;

			case XML_TYPE_TEXT_FONT_RELIEF:
				if (!m_pFontReliefHandler)
					m_pFontReliefHandler = new XMLConstantsPropertyHandler( OEnumMapper::getEnumMap(OEnumMapper::epFontRelief), XML_NONE );
				pHandler = m_pFontReliefHandler;
				break;
            case XML_TYPE_TEXT_LINE_MODE:
		        pHandler = new XMLNamedBoolPropertyHdl(
									        ::xmloff::token::XML_SKIP_WHITE_SPACE,
                                            ::xmloff::token::XML_CONTINUOUS);
		        break;
		}

		if (!pHandler)
			pHandler = XMLPropertyHandlerFactory::GetPropertyHandler(_nType);
		return pHandler;
	}

	//=====================================================================
	//= OControlTextEmphasisHandler
	//=====================================================================
	OControlTextEmphasisHandler::OControlTextEmphasisHandler()
	{
	}

	//---------------------------------------------------------------------
	sal_Bool OControlTextEmphasisHandler::exportXML( ::rtl::OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
	{
		::rtl::OUStringBuffer aReturn;
		sal_Bool bSuccess = sal_False;
		sal_Int16 nFontEmphasis = sal_Int16();
		if (_rValue >>= nFontEmphasis)
		{
			// the type
			sal_Int16 nType = nFontEmphasis & ~(FontEmphasisMark::ABOVE | FontEmphasisMark::BELOW);
			// the position of the mark
			sal_Bool bBelow = 0 != (nFontEmphasis & FontEmphasisMark::BELOW);

			// convert
            bSuccess = SvXMLUnitConverter::convertEnum(aReturn, nType, OEnumMapper::getEnumMap(OEnumMapper::epFontEmphasis), XML_NONE);
			if (bSuccess)
			{
				aReturn.append( (sal_Unicode)' ' );
				aReturn.append( GetXMLToken(bBelow ? XML_BELOW : XML_ABOVE) );

				_rStrExpValue = aReturn.makeStringAndClear();
			}
		}

		return bSuccess;
	}

	//---------------------------------------------------------------------
	sal_Bool OControlTextEmphasisHandler::importXML( const ::rtl::OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
	{
		sal_Bool bSuccess = sal_True;
		sal_uInt16 nEmphasis = FontEmphasisMark::NONE;

		sal_Bool bBelow = sal_False;
		sal_Bool bHasPos = sal_False, bHasType = sal_False;

		::rtl::OUString sToken;
		SvXMLTokenEnumerator aTokenEnum(_rStrImpValue);
		while (aTokenEnum.getNextToken(sToken))
		{
			if (!bHasPos)
			{
				if (IsXMLToken(sToken, XML_ABOVE))
				{
					bBelow = sal_False;
					bHasPos = sal_True;
				}
				else if (IsXMLToken(sToken, XML_BELOW))
				{
					bBelow = sal_True;
					bHasPos = sal_True;
				}
			}
			if (!bHasType)
			{
				if (SvXMLUnitConverter::convertEnum(nEmphasis, sToken, OEnumMapper::getEnumMap(OEnumMapper::epFontEmphasis)))
				{
					bHasType = sal_True;
				}
				else
				{
					bSuccess = sal_False;
					break;
				}
			}
		}

		if (bSuccess)
		{
			nEmphasis |= bBelow ? FontEmphasisMark::BELOW : FontEmphasisMark::ABOVE;
			_rValue <<= (sal_Int16)nEmphasis;
		}

		return bSuccess;
	}

	//=====================================================================
	//= OControlBorderHandlerBase
	//=====================================================================
	//---------------------------------------------------------------------
	OControlBorderHandler::OControlBorderHandler( const OControlBorderHandler::BorderFacet _eFacet )
        :m_eFacet( _eFacet )
	{
	}

	//---------------------------------------------------------------------
	sal_Bool OControlBorderHandler::importXML( const ::rtl::OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
	{
		::rtl::OUString sToken;
		SvXMLTokenEnumerator aTokens(_rStrImpValue);

		sal_uInt16 nStyle = 1;
        Color aColor;

		while	(	aTokens.getNextToken(sToken)	// have a new token
				&&	(0 != sToken.getLength())		// really have a new token
				)
		{
            // try interpreting the token as border style
            if ( m_eFacet == STYLE )
            {
                // is it a valid enum value?
			    if ( SvXMLUnitConverter::convertEnum( nStyle, sToken, OEnumMapper::getEnumMap( OEnumMapper::epBorderWidth ) ) )
                {
                    _rValue <<= nStyle;
                    return sal_True;
                }
            }

            // try interpreting it as color value
            if ( m_eFacet == COLOR )
            {
                if ( SvXMLUnitConverter::convertColor( aColor, sToken ) )
                {
                    _rValue <<= (sal_Int32)aColor.GetColor();
                    return sal_True;
                }
            }
		}

		return sal_False;
	}

	//---------------------------------------------------------------------
	sal_Bool OControlBorderHandler::exportXML( ::rtl::OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
	{
		sal_Bool bSuccess = sal_False;

	    ::rtl::OUStringBuffer aOut;
        switch ( m_eFacet )
        {
        case STYLE:
        {
		    sal_Int16 nBorder = 0;
		    bSuccess =	(_rValue >>= nBorder)
			    	&&	SvXMLUnitConverter::convertEnum( aOut, nBorder, OEnumMapper::getEnumMap( OEnumMapper::epBorderWidth ) );
        }
        break;
        case COLOR:
        {
		    sal_Int32 nBorderColor = 0;
		    if ( _rValue >>= nBorderColor )
            {
                SvXMLUnitConverter::convertColor( aOut, Color( nBorderColor ) );
                bSuccess = sal_True;
            }
        }
        break;
        }   // switch ( m_eFacet )

        if ( !bSuccess )
            return sal_False;

        if ( _rStrExpValue.getLength() )
            _rStrExpValue += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " " ) );
		_rStrExpValue += aOut.makeStringAndClear();

		return sal_True;
    }

	//=====================================================================
	//= OFontWidthHandler
	//=====================================================================
	//---------------------------------------------------------------------
	OFontWidthHandler::OFontWidthHandler()
	{
	}

	//---------------------------------------------------------------------
	sal_Bool OFontWidthHandler::importXML( const ::rtl::OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
	{
		sal_Int32 nWidth = 0;
		sal_Bool bSuccess = SvXMLUnitConverter::convertMeasure(nWidth, _rStrImpValue, MAP_POINT);
		if (bSuccess)
			_rValue <<= (sal_Int16)nWidth;

		return bSuccess;
	}

	//---------------------------------------------------------------------
	sal_Bool OFontWidthHandler::exportXML( ::rtl::OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
	{
		sal_Int16 nWidth = 0;
		::rtl::OUStringBuffer aResult;
		if (_rValue >>= nWidth)
			SvXMLUnitConverter::convertMeasure(aResult, nWidth, MAP_POINT, MAP_POINT);
		_rStrExpValue = aResult.makeStringAndClear();

		return _rStrExpValue.getLength() != 0;
	}

	//=====================================================================
	//= ORotationAngleHandler
	//=====================================================================
	//---------------------------------------------------------------------
	ORotationAngleHandler::ORotationAngleHandler()
	{
	}

	//---------------------------------------------------------------------
	sal_Bool ORotationAngleHandler::importXML( const ::rtl::OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const
	{
		double fValue;
		sal_Bool bSucces =
            SvXMLUnitConverter::convertDouble(fValue, _rStrImpValue);
		if (bSucces)
		{
			fValue *= 10;
			_rValue <<= (float)fValue;
		}

		return bSucces;
	}

	//---------------------------------------------------------------------
	sal_Bool ORotationAngleHandler::exportXML( ::rtl::OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const
	{
		float fAngle = 0;
		sal_Bool bSuccess = (_rValue >>= fAngle);

		if (bSuccess)
		{
			rtl::OUStringBuffer sValue;
			SvXMLUnitConverter::convertDouble(sValue, ((double)fAngle) / 10);
			_rStrExpValue = sValue.makeStringAndClear();
		}

		return bSuccess;
	}

	//=====================================================================
	//= ImageScaleModeHandler
	//=====================================================================
	//---------------------------------------------------------------------
    ImageScaleModeHandler::ImageScaleModeHandler()
        :XMLConstantsPropertyHandler( OEnumMapper::getEnumMap( OEnumMapper::epImageScaleMode ), XML_STRETCH )
    {
    }

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