/**************************************************************
 * 
 * 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.
 * 
 *************************************************************/


#ifndef ANALYSISHELPER_HXX
#define ANALYSISHELPER_HXX


#include <com/sun/star/lang/XServiceName.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/XNumberFormatter.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <com/sun/star/sheet/XAddIn.hpp>
#include <com/sun/star/sheet/addin/XAnalysis.hpp>

#include <math.h>

#include <tools/resid.hxx>
#include <tools/rc.hxx>

#include "analysisdefs.hxx"


class ResMgr;
class SortedIndividualInt32List;
class ScaAnyConverter;


#define	PI			3.1415926535897932
#define PI_2		(PI/2.0)
//#define	EULER		2.7182818284590452
#define	EOL			( ( const sal_Char* ) 1 )
#define	EOE			( ( const sal_Char* ) 2 )


//double				_Test( sal_Int32 nMode, double f1, double f2, double f3 );
inline sal_Bool     IsLeapYear( sal_uInt16 nYear );
sal_uInt16			DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear );
sal_Int32			DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear );
void				DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear ) throw( ::com::sun::star::lang::IllegalArgumentException );
sal_Int32           GetNullDate( const REF( CSS::beans::XPropertySet )& xOptions ) THROWDEF_RTE;
sal_Int32			GetDiffDate360(
						sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, sal_Bool bLeapYear1,
						sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
						sal_Bool bUSAMethod );
inline sal_Int32	GetDiffDate360( constREFXPS& xOpt, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod );
sal_Int32			GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod );

sal_Int32			GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 );
inline sal_Int16	GetDayOfWeek( sal_Int32 nDate );
void				GetDiffParam( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
						sal_uInt16& rYears, sal_Int32& rDayDiffPart, sal_Int32& rDaysInYear ) THROWDEF_RTE_IAE;
						// rYears = full num of years
						// rDayDiffPart = num of days for last year
						// rDaysInYear = num of days in first year
sal_Int32			GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
								sal_Int32* pOptDaysIn1stYear = NULL ) THROWDEF_RTE_IAE;
double				GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode )
								THROWDEF_RTE_IAE;
sal_Int32			GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE;
double				GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode )
						THROWDEF_RTE_IAE;
inline double		GetYearFrac( constREFXPS& xOpt, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode )
						THROWDEF_RTE_IAE;
inline void			AlignDate( sal_uInt16& rDay, sal_uInt16 nMonth, sal_uInt16 nYear );

double				Fak( sal_Int32 n );
double				GetGcd( double f1, double f2 );
double				ConvertToDec( const STRING& rFromNum, sal_uInt16 nBaseFrom, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE;
STRING				ConvertFromDec(
                        double fNum, double fMin, double fMax, sal_uInt16 nBase,
                        sal_Int32 nPlaces, sal_Int32 nMaxPlaces, sal_Bool bUsePlaces ) THROWDEF_RTE_IAE;
double				Erf( double fX );
double				Erfc( double fX );
sal_Bool			ParseDouble( const sal_Unicode*& rpDoubleAsString, double& rReturn );
STRING				GetString( double fNumber, sal_Bool bLeadingSign = sal_False, sal_uInt16 nMaxNumOfDigits = 15 );
inline double		Exp10( sal_Int16 nPower );		// 10 ^ nPower

double				GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
								double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
								double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
								double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
								double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
								sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp,
								sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
								double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
								double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetOddfyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
								sal_Int32 nFirstCoup, double fRate, double fPrice, double fRedemp,
								sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
								double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
								double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF );
double				GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF );
//double				TBillYield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice )THROWDEF_RTE_IAE;

double				GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
								sal_Int32 nBase ) THROWDEF_RTE_IAE;
double              GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
								sal_Int32 nBase ) THROWDEF_RTE_IAE;
double              GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
								sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
								sal_Int32 nBase ) THROWDEF_RTE_IAE;

double              GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat,
								sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE;
double				GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq,
								sal_Int32 nBase ) THROWDEF_RTE_IAE;




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



class MyList
{
private:
	static const sal_uInt32	nStartSize;
	static const sal_uInt32	nIncrSize;

	void**					pData;			// pointer array
	sal_uInt32				nSize;			// array size
	sal_uInt32				nNew;			// next index to be inserted at
	sal_uInt32				nAct;			// actual for iterations

	void					_Grow( void );
	inline void				Grow( void );
protected:
public:
							MyList( void );
	virtual					~MyList();

	inline const void*		GetObject( sal_uInt32 nIndex ) const;
	inline const void*		First( void );
	inline const void*		Next( void );

	inline void				Append( void* pNewElement );
	void					Insert( void* pNewLement, sal_uInt32 nPlace );

	inline sal_uInt32		Count( void ) const;
};




class StringList : protected MyList
{
public:
	virtual					~StringList();

	inline const STRING*	First( void );
	inline const STRING*	Next( void );
	inline const STRING*	Get( sal_uInt32 nIndex ) const;

    using MyList::Append;
	inline void				Append( STRING* pNew );
	inline void				Append( const STRING& rNew );

	using MyList::Count;
};




enum FDCategory
{
	FDCat_AddIn,
	FDCat_DateTime,
	FDCat_Finance,
	FDCat_Inf,
	FDCat_Math,
	FDCat_Tech
};


struct FuncDataBase
{
	const sal_Char*			pIntName;
	sal_uInt16				nUINameID;			// resource ID to UI name
	sal_uInt16				nDescrID;			// resource ID to description, parameter names and ~ description
	sal_Bool				bDouble;			// name already exist in Calc
	sal_Bool				bWithOpt;			// first parameter is internal
	sal_uInt16				nCompListID;		// resource ID to list of valid names
	sal_uInt16				nNumOfParams;		// number of named / described parameters
	FDCategory				eCat;				// function category
};




class FuncData
{
private:
    ::rtl::OUString         aIntName;
	sal_uInt16				nUINameID;
	sal_uInt16				nDescrID;			// leads also to parameter descriptions!
	sal_Bool				bDouble;			// flag for names, wich already exist in Calc
	sal_Bool				bWithOpt;			// has internal parameter on first position

	sal_uInt16				nParam;				// num of parameters
	sal_uInt16				nCompID;
	StringList				aCompList;			// list of all valid names
	FDCategory				eCat;				// function category
public:
							FuncData( const FuncDataBase& rBaseData, ResMgr& );
	virtual					~FuncData();

	inline sal_uInt16		GetUINameID( void ) const;
	inline sal_uInt16		GetDescrID( void ) const;
	inline sal_Bool			IsDouble( void ) const;
	inline sal_Bool			HasIntParam( void ) const;

	sal_uInt16				GetStrIndex( sal_uInt16 nParamNum ) const;
    inline sal_Bool         Is( const ::rtl::OUString& rCompareTo ) const;

	inline const StringList&	GetCompNameList( void ) const;

	inline FDCategory		GetCategory( void ) const;
};




class CStrList : private MyList
{
public:
    using MyList::Append;
	inline void				Append( const sal_Char* pNew );
	inline const sal_Char*	Get( sal_uInt32 nIndex ) const;
	using MyList::Count;
};




class FuncDataList : private MyList
{
    ::rtl::OUString         aLastName;
	sal_uInt32				nLast;
public:
							FuncDataList( ResMgr& );
	virtual					~FuncDataList();
    using MyList::Append;
	inline void				Append( FuncData* pNew );
	inline const FuncData*	Get( sal_uInt32 nIndex ) const;
	using MyList::Count;

    const FuncData*         Get( const ::rtl::OUString& aProgrammaticName ) const;
};



class AnalysisResId : public ResId
{
 public:
					AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr );
};




class AnalysisRscStrLoader : public Resource
{
private:
	String			aStr;
public:
	AnalysisRscStrLoader( sal_uInt16 nRsc, sal_uInt16 nStrId, ResMgr& rResMgr ) :
		Resource( AnalysisResId( nRsc, rResMgr ) ),
		aStr( AnalysisResId( nStrId, rResMgr ) )
	{
		FreeResource();
	}

	const String&	GetString() const { return aStr; }

};



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

/// sorted list with unique sal_Int32 values
class SortedIndividualInt32List : private MyList
{
protected:
    using MyList::Insert;
    void                        Insert( sal_Int32 nDay );
    void                        Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend );
    void                        Insert( double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
                                    throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** @param rAnyConv  must be an initialized ScaAnyConmverter
                                    @param bInsertOnWeekend  insertion mode: sal_False = holidays on weekend are omitted */
    void                        InsertHolidayList(
                                    const ScaAnyConverter& rAnyConv,
                                    const CSS::uno::Any& rHolAny,
                                    sal_Int32 nNullDate,
                                    sal_Bool bInsertOnWeekend ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

public:
                                SortedIndividualInt32List();
    virtual                     ~SortedIndividualInt32List();

                                using MyList::Count;

                                /// @return  element on position nIndex or 0 on invalid index
    inline sal_Int32            Get( sal_uInt32 nIndex ) const
                                    { return (sal_Int32)(sal_IntPtr) MyList::GetObject( nIndex ); }

                                /// @return  sal_True if nVal (internal date representation) is contained
    sal_Bool                    Find( sal_Int32 nVal ) const;

                                /** @param rAnyConv  is an initialized or uninitialized ScaAnyConverter
                                    @param bInsertOnWeekend  insertion mode: sal_False = holidays on weekend are omitted */
    void                        InsertHolidayList(
                                    ScaAnyConverter& rAnyConv,
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xOptions,
                                    const CSS::uno::Any& rHolAny,
                                    sal_Int32 nNullDate,
                                    sal_Bool bInsertOnWeekend ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );
};


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

class ScaDoubleList : protected MyList
{
protected:
    inline void                 ListAppend( double fValue ) { MyList::Append( new double( fValue ) ); }

    using MyList::Append;
    inline void                 Append( double fValue ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException )
                                    { if( CheckInsert( fValue ) ) ListAppend( fValue ); }

                                /** @param rAnyConv  must be an initialized ScaAnyConmverter
                                    @param bIgnoreEmpty  handling of empty Any's/strings: sal_False = inserted as 0.0; sal_True = omitted */
    void                        Append(
                                    const ScaAnyConverter& rAnyConv,
                                    const CSS::uno::Any& rAny,
                                    sal_Bool bIgnoreEmpty ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** @param rAnyConv  must be an initialized ScaAnyConmverter
                                    @param bIgnoreEmpty  handling of empty Any's/strings: sal_False = inserted as 0.0; sal_True = omitted */
    void                        Append(
                                    const ScaAnyConverter& rAnyConv,
                                    const CSS::uno::Sequence< CSS::uno::Any >& rAnySeq,
                                    sal_Bool bIgnoreEmpty ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** @param rAnyConv  must be an initialized ScaAnyConmverter
                                    @param bIgnoreEmpty  handling of empty Any's/strings: sal_False = inserted as 0.0; sal_True = omitted */
    void                        Append(
                                    const ScaAnyConverter& rAnyConv,
                                    const CSS::uno::Sequence< CSS::uno::Sequence< CSS::uno::Any > >& rAnySeq,
                                    sal_Bool bIgnoreEmpty ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

public:
    virtual                     ~ScaDoubleList();

                                using MyList::Count;
    inline const double*        Get( sal_uInt32 nIndex ) const
                                        { return static_cast< const double* >( MyList::GetObject( nIndex ) ); }

    inline const double*        First() { return static_cast< const double* >( MyList::First() ); }
    inline const double*        Next()  { return static_cast< const double* >( MyList::Next() ); }

    void                        Append( const CSS::uno::Sequence< CSS::uno::Sequence< double > >& rValueArr )
                                    throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );
    void                        Append( const CSS::uno::Sequence< CSS::uno::Sequence< sal_Int32 > >& rValueArr )
                                    throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** @param rAnyConv  is an initialized or uninitialized ScaAnyConverter
                                    @param bIgnoreEmpty  handling of empty Any's/strings: sal_False = inserted as 0.0; sal_True = omitted */
    void                        Append(
                                    ScaAnyConverter& rAnyConv,
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xOpt,
                                    const CSS::uno::Sequence< CSS::uno::Any >& rAnySeq,
                                    sal_Bool bIgnoreEmpty = sal_True ) throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

    virtual sal_Bool            CheckInsert( double fValue ) const
                                    throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );
};


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

/// stores double values >0.0, throws exception for double values <0.0, does nothing for 0.0
class ScaDoubleListGT0 : public ScaDoubleList
{
public:
    virtual sal_Bool            CheckInsert( double fValue ) const
                                    throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );
};


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

/// stores double values >=0.0, throws exception for double values <0.0
class ScaDoubleListGE0 : public ScaDoubleList
{
public:
    virtual sal_Bool            CheckInsert( double fValue ) const
                                    throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );
};


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

class Complex
{
	double					r;
	double					i;
    sal_Unicode             c;

public:
    inline                  Complex( double fReal, double fImag = 0.0, sal_Char cC = '\0' );
							Complex( const STRING& rComplexAsString ) THROWDEF_RTE_IAE;

	inline static sal_Bool	IsImagUnit( sal_Unicode c );
	static sal_Bool			ParseString( const STRING& rComplexAsString, Complex& rReturn );
    STRING                  GetString() const THROWDEF_RTE_IAE;

	inline double			Real( void ) const;
	inline double			Imag( void ) const;

	double					Arg( void ) const THROWDEF_RTE_IAE;
	inline double			Abs( void ) const;

	// following functions change the complex number itself to avoid unnecessary copy actions!
	void					Power( double fPower ) THROWDEF_RTE_IAE;
	void					Sqrt( void );
	void					Sin( void ) THROWDEF_RTE_IAE;
	void					Cos( void ) THROWDEF_RTE_IAE;
	void					Div( const Complex& rDivisor ) THROWDEF_RTE_IAE;
	void					Exp( void );
	inline void				Conjugate( void );
	void					Ln( void ) THROWDEF_RTE_IAE;
	void					Log10( void ) THROWDEF_RTE_IAE;
	void					Log2( void ) THROWDEF_RTE_IAE;
	inline void				Mult( double fFact );
	inline void				Mult( const Complex& rMult );
	inline void				Sub( const Complex& rMult );
	inline void				Add( const Complex& rAdd );
};




enum ComplListAppendHandl
{
	AH_EmptyAsErr,
	AH_EmpyAs0,
	AH_IgnoreEmpty
};


class ComplexList : protected MyList
{
public:
	virtual					~ComplexList();

	inline const Complex*	Get( sal_uInt32 nIndex ) const;
	inline const Complex*	First( void );
	inline const Complex*	Next( void );

	using MyList::Count;

    using MyList::Append;
	inline void				Append( Complex* pNew );
	void					Append( const SEQSEQ( STRING )& rComplexNumList, ComplListAppendHandl eAH = AH_EmpyAs0 ) THROWDEF_RTE_IAE;
	void					Append( const SEQ( ANY )& aMultPars,ComplListAppendHandl eAH = AH_EmpyAs0 ) THROWDEF_RTE_IAE;
};




enum ConvertDataClass
{
	CDC_Mass, CDC_Length, CDC_Time, CDC_Pressure, CDC_Force, CDC_Energy, CDC_Power, CDC_Magnetism,
	CDC_Temperature, CDC_Volume, CDC_Area, CDC_Speed, CDC_Information
};


#define	INV_MATCHLEV		1764					// guess, what this is... :-)


class ConvertDataList;




class ConvertData
{
protected:
	friend class ConvertDataList;
	double					fConst;
	STRING					aName;
	ConvertDataClass		eClass;
    sal_Bool                bPrefixSupport;
public:
							ConvertData(
								const sal_Char		pUnitName[],
								double				fConvertConstant,
								ConvertDataClass	eClass,
                                sal_Bool            bPrefSupport = sal_False );

    virtual                 ~ConvertData();

	sal_Int16				GetMatchingLevel( const STRING& rRef ) const;
									// 0.0 = no equality
									// 1.0 = matches exact
									// rest = matches without an assumed prefix of one character
									//  rest gives power for 10 represented by the prefix (e.g. 3 for k or -9 for n

	virtual double			Convert( double fVal, const ConvertData& rTo,
								sal_Int16 nMatchLevelFrom, sal_Int16 nMatchLevelTo ) const THROWDEF_RTE_IAE;
									// converts fVal from this unit to rFrom unit
									// throws exception if not from same class
									// this implementation is for proportional cases only
	virtual double			ConvertToBase( double fVal, sal_Int16 nMatchLevel ) const;
	virtual double			ConvertFromBase( double fVal, sal_Int16 nMatchLevel ) const;

	inline ConvertDataClass	Class( void ) const;
    inline sal_Bool         IsPrefixSupport( void ) const;
};




class ConvertDataLinear : public ConvertData
{
protected:
	double					fOffs;
public:
	inline					ConvertDataLinear(
								const sal_Char		pUnitName[],
								double				fConvertConstant,
								double				fConvertOffset,
								ConvertDataClass	eClass,
                                sal_Bool            bPrefSupport = sal_False );

    virtual                 ~ConvertDataLinear();

	virtual double			Convert( double fVal, const ConvertData& rTo,
								sal_Int16 nMatchLevelFrom, sal_Int16 nMatchLevelTo ) const THROWDEF_RTE_IAE;
									// for cases where f(x) = a + bx applies (e.g. Temperatures)

	virtual double			ConvertToBase( double fVal, sal_Int16 nMatchLevel ) const;
	virtual double			ConvertFromBase( double fVal, sal_Int16 nMatchLevel ) const;
};




class ConvertDataList : protected MyList
{
private:
protected:
	inline ConvertData*		First( void );
	inline ConvertData*		Next( void );
public:
							ConvertDataList( void );
	virtual					~ConvertDataList();

	double					Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE;
};




inline sal_Bool IsLeapYear( sal_uInt16 n )
{
    return ( (( ( n % 4 ) == 0 ) && ( ( n % 100 ) != 0)) || ( ( n % 400 ) == 0 ) );
}


inline sal_Int32 GetDiffDate360( constREFXPS& xOpt, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod )
{
	return GetDiffDate360( GetNullDate( xOpt ), nDate1, nDate2, bUSAMethod );
}


inline sal_Int16 GetDayOfWeek( sal_Int32 n )
{	// monday = 0, ..., sunday = 6
    return static_cast< sal_Int16 >( ( n - 1 ) % 7 );
}


inline double GetYearFrac( constREFXPS& xOpt, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
{
	return GetYearFrac( GetNullDate( xOpt ), nStartDate, nEndDate, nMode );
}


inline void AlignDate( sal_uInt16& rD, sal_uInt16 nM, sal_uInt16 nY )
{
	sal_uInt16	nMax = DaysInMonth( nM, nY );

	if( rD > nMax )
		rD = nMax;
}


inline void MyList::Grow( void )
{
	if( nNew >= nSize )
		_Grow();
}


inline const void* MyList::GetObject( sal_uInt32 n ) const
{
	if( n < nNew )
		return pData[ n ];
	else
		return NULL;
}


inline const void* MyList::First( void )
{
	nAct = 0;
	if( nNew )
		return pData[ 0 ];
	else
		return NULL;
}


inline const void* MyList::Next( void )
{
	nAct++;
	if( nAct < nNew )
		return pData[ nAct ];
	else
	{
		nAct--;
		return NULL;
	}
}


inline void MyList::Append( void* p )
{
	Grow();
	pData[ nNew ] = p;
	nNew++;
}


inline sal_uInt32 MyList::Count( void ) const
{
	return nNew;
}




inline const STRING* StringList::First( void )
{
	return ( const STRING* ) MyList::First();
}


inline const STRING* StringList::Next( void )
{
	return ( const STRING* ) MyList::Next();
}


inline const STRING* StringList::Get( sal_uInt32 n ) const
{
	return ( const STRING* ) MyList::GetObject( n );
}


inline void StringList::Append( STRING* p )
{
	MyList::Append( p );
}


inline void StringList::Append( const STRING& r )
{
	MyList::Append( new STRING( r ) );
}




inline sal_uInt16 FuncData::GetUINameID( void ) const
{
	return nUINameID;
}


inline sal_uInt16 FuncData::GetDescrID( void ) const
{
	return nDescrID;
}


inline sal_Bool FuncData::IsDouble( void ) const
{
	return bDouble;
}


inline sal_Bool FuncData::HasIntParam( void ) const
{
	return bWithOpt;
}


inline sal_Bool FuncData::Is( const ::rtl::OUString& r ) const
{
	return aIntName == r;
}


inline const StringList& FuncData::GetCompNameList( void ) const
{
	return aCompList;
}


inline FDCategory FuncData::GetCategory( void ) const
{
	return eCat;
}




inline void CStrList::Append( const sal_Char* p )
{
	MyList::Append( ( void* ) p );
}


inline const sal_Char* CStrList::Get( sal_uInt32 n ) const
{
	return ( const sal_Char* ) MyList::GetObject( n );
}




inline void FuncDataList::Append( FuncData* p )
{
	MyList::Append( p );
}


inline const FuncData* FuncDataList::Get( sal_uInt32 n ) const
{
	return ( const FuncData* ) MyList::GetObject( n );
}


inline Complex::Complex( double fReal, double fImag, sal_Char cC ) :
		r( fReal ), i( fImag ), c( cC )
{
}


inline double Complex::Real( void ) const
{
	return r;
}


inline double Complex::Imag( void ) const
{
	return i;
}


inline double Complex::Abs( void ) const
{
	return sqrt( r * r + i * i );
}


void Complex::Conjugate( void )
{
	i = -i;
}


inline void Complex::Mult( double f )
{
	i *= f;
	r *= f;
}


inline void Complex::Mult( const Complex& rM )
{
	double	r_ = r;
	double	i_ = i;

	r = r_ * rM.r - i_ * rM.i;
	i = r_ * rM.i + i_ * rM.r;

    if( !c ) c = rM.c;
}


inline void Complex::Sub( const Complex& rC )
{
	r -= rC.r;
	i -= rC.i;
    if( !c ) c = rC.c;
}


inline void Complex::Add( const Complex& rAdd )
{
	r += rAdd.r;
	i += rAdd.i;
    if( !c ) c = rAdd.c;
}




inline const Complex* ComplexList::Get( sal_uInt32 n ) const
{
	return ( const Complex* ) MyList::GetObject( n );
}


inline const Complex* ComplexList::First( void )
{
	return ( const Complex* ) MyList::First();
}


inline const Complex* ComplexList::Next( void )
{
	return ( const Complex* ) MyList::Next();
}


inline void ComplexList::Append( Complex* p )
{
	MyList::Append( p );
}




inline ConvertDataClass	ConvertData::Class( void ) const
{
	return eClass;
}



inline sal_Bool ConvertData::IsPrefixSupport( void ) const
{
    return bPrefixSupport;
}

inline ConvertDataLinear::ConvertDataLinear( const sal_Char* p, double fC, double fO, ConvertDataClass e, 
        sal_Bool bPrefSupport ) :
	ConvertData( p, fC, e, bPrefSupport ),
	fOffs( fO )
{
}




inline ConvertData* ConvertDataList::First( void )
{
	return ( ConvertData* ) MyList::First();
}


inline ConvertData* ConvertDataList::Next( void )
{
	return ( ConvertData* ) MyList::Next();
}

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

/// Helper class for date calculation for various financial functions
class ScaDate
{
private:
    sal_uInt16                  nOrigDay;           /// is the day of the original date.
    sal_uInt16                  nDay;               /// is the calculated day depending on the current month/year.
    sal_uInt16                  nMonth;             /// is the current month (one-based).
    sal_uInt16                  nYear;              /// is the current year.
    sal_Bool                    bLastDayMode : 1;   /// if sal_True, recalculate nDay after every calculation.
    sal_Bool                    bLastDay : 1;       /// is sal_True, if original date was the last day in month.
    sal_Bool                    b30Days : 1;        /// is sal_True, if every month has 30 days in calculations.
    sal_Bool                    bUSMode : 1;        /// is sal_True, if the US method of 30-day-calculations is used.

                                /// Calculates nDay from nOrigDay and current date.
    void                        setDay();

                                /// @return  count of days in current month
    inline sal_uInt16           getDaysInMonth() const;
                                /// @return  count of days in given month
    inline sal_uInt16           getDaysInMonth( sal_uInt16 _nMon ) const;

                                /// @ return  count of days in the given month range
    sal_Int32                   getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const;
                                /// @ return  count of days in the given year range
    sal_Int32                   getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const;

                                /// Adds/subtracts the given count of years, does not adjust day.
    void                        doAddYears( sal_Int32 nYearCount ) throw( CSS::lang::IllegalArgumentException );

public:
                                ScaDate();
                                /** @param nBase
                                        date handling mode (days in month / days in year):
                                        0 = 30 days / 360 days (US NASD)
                                        1 = exact / exact
                                        2 = exact / 360
                                        3 = exact / 365
                                        4 = 30 days / 360 days (Europe)
                                        5 = exact / exact (no last day adjustment) */
                                ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase );
                                ScaDate( const ScaDate& rCopy );
    ScaDate&                    operator=( const ScaDate& rCopy );

                                /// @return  the current month.
    inline sal_uInt16           getMonth() const    { return nMonth; };
                                /// @return  the current year.
    inline sal_uInt16           getYear() const     { return nYear; };

                                /// adds/subtracts the given count of months, adjusts day
    void                        addMonths( sal_Int32 nMonthCount ) throw( CSS::lang::IllegalArgumentException );

                                /// sets the given year, adjusts day
    inline void                 setYear( sal_uInt16 nNewYear );
                                /// adds/subtracts the given count of years, adjusts day
    inline void                 addYears( sal_Int32 nYearCount ) throw( CSS::lang::IllegalArgumentException );

                                /// @return  the internal number of the current date
    sal_Int32                   getDate( sal_Int32 nNullDate ) const;
                                /// @return  the number of days between the two dates
    static sal_Int32            getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( CSS::lang::IllegalArgumentException );

    sal_Bool                    operator<( const ScaDate& rCmp ) const;
    inline sal_Bool             operator<=( const ScaDate& rCmp ) const { return !(rCmp < *this); }
    inline sal_Bool             operator>( const ScaDate& rCmp ) const  { return rCmp < *this; }
    inline sal_Bool             operator>=( const ScaDate& rCmp ) const { return !(*this < rCmp); }
};

inline sal_uInt16 ScaDate::getDaysInMonth() const
{
    return getDaysInMonth( nMonth );
}

inline sal_uInt16 ScaDate::getDaysInMonth( sal_uInt16 _nMon ) const
{
    return b30Days ? 30 : DaysInMonth( _nMon, nYear );
}

inline void ScaDate::setYear( sal_uInt16 nNewYear )
{
    nYear = nNewYear;
    setDay();
}

inline void ScaDate::addYears( sal_Int32 nYearCount ) throw( CSS::lang::IllegalArgumentException )
{
    doAddYears( nYearCount );
    setDay();
}


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

/// Helper class for Any->double conversion, using current language settings
class ScaAnyConverter
{
private:
    CSS::uno::Reference< CSS::util::XNumberFormatter > xFormatter;
    sal_Int32                   nDefaultFormat;
    sal_Bool                    bHasValidFormat;

                                /** Converts a string to double using the number formatter. If the formatter is not
                                    valid, ::rtl::math::stringToDouble() with english separators will be used.
                                    @throws com::sun::star::lang::IllegalArgumentException
                                        on strings not representing any double value.
                                    @return  the converted double value. */
    double                      convertToDouble(
                                    const ::rtl::OUString& rString ) const
                                throw( CSS::lang::IllegalArgumentException );

public:
                                ScaAnyConverter(
                                    const CSS::uno::Reference< CSS::lang::XMultiServiceFactory >& xServiceFact );
                                ~ScaAnyConverter();

                                /// Initializing with current language settings
    void                        init(
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xPropSet )
                                throw( CSS::uno::RuntimeException );

                                /** Converts an Any to double (without initialization).
                                    The Any can be empty or contain a double or string.
                                    @throws com::sun::star::lang::IllegalArgumentException
                                        on other Any types or on invalid strings.
                                    @return  sal_True if the Any contains a double or a non-empty valid string,
                                             sal_False if the Any is empty or the string is empty */
    sal_Bool                    getDouble(
                                    double& rfResult,
                                    const CSS::uno::Any& rAny ) const
                                throw( CSS::lang::IllegalArgumentException );

                                /** Converts an Any to double (with initialization).
                                    The Any can be empty or contain a double or string.
                                    @throws com::sun::star::lang::IllegalArgumentException
                                        on other Any types or on invalid strings.
                                    @return  sal_True if the Any contains a double or a non-empty valid string,
                                             sal_False if the Any is empty or the string is empty */
    sal_Bool                    getDouble(
                                    double& rfResult,
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xPropSet,
                                    const CSS::uno::Any& rAny )
                                throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** Converts an Any to double (with initialization).
                                    The Any can be empty or contain a double or string.
                                    @throws com::sun::star::lang::IllegalArgumentException
                                        on other Any types or on invalid strings.
                                    @return  the value of the double or string or fDefault if the Any or string is empty */
    double                      getDouble(
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xPropSet,
                                    const CSS::uno::Any& rAny,
                                    double fDefault )
                                throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** Converts an Any to sal_Int32 (with initialization).
                                    The Any can be empty or contain a double or string.
                                    @throws com::sun::star::lang::IllegalArgumentException
                                        on other Any types or on invalid values or strings.
                                    @return  sal_True if the Any contains a double or a non-empty valid string,
                                             sal_False if the Any is empty or the string is empty */
    sal_Bool                    getInt32(
                                    sal_Int32& rnResult,
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xPropSet,
                                    const CSS::uno::Any& rAny )
                                throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );

                                /** Converts an Any to sal_Int32 (with initialization).
                                    The Any can be empty or contain a double or string.
                                    @throws com::sun::star::lang::IllegalArgumentException
                                        on other Any types or on invalid values or strings.
                                    @return  the truncated value of the double or string or nDefault if the Any or string is empty */
    sal_Int32                   getInt32(
                                    const CSS::uno::Reference< CSS::beans::XPropertySet >& xPropSet,
                                    const CSS::uno::Any& rAny,
                                    sal_Int32 nDefault )
                                throw( CSS::uno::RuntimeException, CSS::lang::IllegalArgumentException );
};


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


#endif