1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "analysis.hxx"
29 
30 #include <cppuhelper/factory.hxx>
31 #include <osl/diagnose.h>
32 #include <rtl/ustrbuf.hxx>
33 #include <rtl/math.hxx>
34 #include <string.h>
35 
36 #include <tools/resmgr.hxx>
37 #include <tools/rcid.h>
38 #include "analysis.hrc"
39 #include "bessel.hxx"
40 
41 #define ADDIN_SERVICE				"com.sun.star.sheet.AddIn"
42 #define MY_SERVICE					"com.sun.star.sheet.addin.Analysis"
43 #define MY_IMPLNAME					"com.sun.star.sheet.addin.AnalysisImpl"
44 
45 using namespace                 ::rtl;
46 using namespace                 ::com::sun::star;
47 
48 //------------------------------------------------------------------
49 //
50 //	entry points for service registration / instantiation
51 //
52 //------------------------------------------------------------------
53 
54 extern "C" {
55 
56 
57 void SAL_CALL component_getImplementationEnvironment( const sal_Char** ppEnvTypeName, uno_Environment** /*ppEnv*/ )
58 {
59 	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
60 }
61 
62 void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /*pRegistryKey*/ )
63 {
64 	void*									pRet = 0;
65 
66 	if( pServiceManager && STRING::createFromAscii( pImplName ) == AnalysisAddIn::getImplementationName_Static() )
67 	{
68 		REF( lang::XSingleServiceFactory )	xFactory( cppu::createOneInstanceFactory(
69 				reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ),
70 				AnalysisAddIn::getImplementationName_Static(),
71 				AnalysisAddIn_CreateInstance,
72 				AnalysisAddIn::getSupportedServiceNames_Static() ) );
73 
74 		if( xFactory.is() )
75 		{
76 			xFactory->acquire();
77 			pRet = xFactory.get();
78 		}
79 	}
80 
81 	return pRet;
82 }
83 
84 
85 }	// extern C
86 
87 
88 
89 
90 //------------------------------------------------------------------------
91 //
92 //	"normal" service implementation
93 //
94 //------------------------------------------------------------------------
95 
96 
97 ResMgr& AnalysisAddIn::GetResMgr( void ) THROWDEF_RTE
98 {
99 	if( !pResMgr )
100 	{
101 		InitData();		// try to get resource manager
102 
103 		if( !pResMgr )
104 			THROW_RTE;
105 	}
106 
107 	return *pResMgr;
108 }
109 
110 
111 STRING AnalysisAddIn::GetDisplFuncStr( sal_uInt16 nFuncNum ) THROWDEF_RTE
112 {
113 	return String( AnalysisRscStrLoader( RID_ANALYSIS_FUNCTION_NAMES, nFuncNum, GetResMgr() ).GetString() );
114 }
115 
116 
117 class AnalysisResourcePublisher : public Resource
118 {
119 public:
120 					AnalysisResourcePublisher( const AnalysisResId& rId ) : Resource( rId ) {}
121 	sal_Bool			IsAvailableRes( const ResId& rId ) const { return Resource::IsAvailableRes( rId ); }
122 	void			FreeResource() { Resource::FreeResource(); }
123 };
124 
125 
126 class AnalysisFuncRes : public Resource
127 {
128 public:
129 	AnalysisFuncRes( ResId& rRes, ResMgr& rResMgr, sal_uInt16 nInd, STRING& rRet );
130 };
131 
132 
133 AnalysisFuncRes::AnalysisFuncRes( ResId& rRes, ResMgr& rResMgr, sal_uInt16 nInd, STRING& rRet ) : Resource( rRes )
134 {
135 	rRet = String( AnalysisResId( nInd, rResMgr ) );
136 
137 	FreeResource();
138 }
139 
140 
141 STRING AnalysisAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) THROWDEF_RTE
142 {
143 	STRING						aRet;
144 	AnalysisResourcePublisher	aResPubl( AnalysisResId( RID_ANALYSIS_FUNCTION_DESCRIPTIONS, GetResMgr() ) );
145 	AnalysisResId				aRes( nResId, GetResMgr() );
146 	aRes.SetRT( RSC_RESOURCE );
147 	if( aResPubl.IsAvailableRes( aRes ) )
148 	{
149 		AnalysisFuncRes			aSubRes( aRes, GetResMgr(), nStrIndex, aRet );
150 	}
151 
152 	aResPubl.FreeResource();
153 
154 	return aRet;
155 }
156 
157 
158 void AnalysisAddIn::InitData( void )
159 {
160 	if( pResMgr )
161 		delete pResMgr;
162 
163 	OString				aModName( "analysis" );
164 	pResMgr = ResMgr::CreateResMgr( ( const sal_Char* ) aModName,
165 										aFuncLoc );
166 
167 	if( pFD )
168 		delete pFD;
169 
170 	if( pResMgr )
171 		pFD = new FuncDataList( *pResMgr );
172 	else
173 		pFD = NULL;
174 
175 	if( pDefLocales )
176 	{
177 		delete pDefLocales;
178 		pDefLocales = NULL;
179 	}
180 }
181 
182 
183 AnalysisAddIn::AnalysisAddIn( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
184     pDefLocales( NULL ),
185     pFD( NULL ),
186     pFactDoubles( NULL ),
187     pCDL( NULL ),
188     pResMgr( NULL ),
189     aAnyConv( xServiceFact )
190 {
191 }
192 
193 
194 AnalysisAddIn::~AnalysisAddIn()
195 {
196 	if( pFD )
197 		delete pFD;
198 
199 	if( pFactDoubles )
200 		delete[] pFactDoubles;
201 
202 	if( pCDL )
203 		delete pCDL;
204 
205 //	if( pResMgr )			no delete, because _all_ resource managers are deleted _before_ this dtor is called
206 //		delete pResMgr;
207 
208 	if( pDefLocales )
209 		delete[] pDefLocales;
210 }
211 
212 
213 sal_Int32 AnalysisAddIn::getDateMode(
214         const uno::Reference< beans::XPropertySet >& xPropSet,
215         const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
216 {
217     sal_Int32 nMode = aAnyConv.getInt32( xPropSet, rAny, 0 );
218     if( (nMode < 0) || (nMode > 4) )
219         throw lang::IllegalArgumentException();
220     return nMode;
221 }
222 
223 
224 
225 //-----------------------------------------------------------------------------
226 
227 
228 #define	MAXFACTDOUBLE	300
229 
230 double AnalysisAddIn::FactDouble( sal_Int32 nNum ) THROWDEF_RTE_IAE
231 {
232 	if( nNum < 0 || nNum > MAXFACTDOUBLE )
233 		THROW_IAE;
234 
235 	if( !pFactDoubles )
236 	{
237 		pFactDoubles = new double[ MAXFACTDOUBLE + 1 ];
238 
239 		pFactDoubles[ 0 ] = 1.0;	// by default
240 
241 		double		fOdd = 1.0;
242 		double		fEven = 2.0;
243 
244 		pFactDoubles[ 1 ] = fOdd;
245 		pFactDoubles[ 2 ] = fEven;
246 
247 		sal_Bool	bOdd = sal_True;
248 
249 		for( sal_uInt16	nCnt = 3 ; nCnt <= MAXFACTDOUBLE ; nCnt++ )
250 		{
251 			if( bOdd )
252 			{
253 				fOdd *= nCnt;
254 				pFactDoubles[ nCnt ] = fOdd;
255 			}
256 			else
257 			{
258 				fEven *= nCnt;
259 				pFactDoubles[ nCnt ] = fEven;
260 			}
261 
262 			bOdd = !bOdd;
263 
264 		}
265 	}
266 
267 	return pFactDoubles[ nNum ];
268 }
269 
270 
271 STRING AnalysisAddIn::getImplementationName_Static()
272 {
273 	return STRFROMASCII( MY_IMPLNAME );
274 }
275 
276 
277 SEQ( STRING ) AnalysisAddIn::getSupportedServiceNames_Static()
278 {
279 	SEQ( STRING )	aRet(2);
280 	STRING*			pArray = aRet.getArray();
281 	pArray[0] = STRFROMASCII( ADDIN_SERVICE );
282 	pArray[1] = STRFROMASCII( MY_SERVICE );
283 	return aRet;
284 }
285 
286 
287 REF( uno::XInterface ) SAL_CALL AnalysisAddIn_CreateInstance(
288         const uno::Reference< lang::XMultiServiceFactory >& xServiceFact )
289 {
290     static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new AnalysisAddIn( xServiceFact );
291 	return xInst;
292 }
293 
294 
295 // XServiceName
296 
297 STRING SAL_CALL AnalysisAddIn::getServiceName() THROWDEF_RTE
298 {
299 	// name of specific AddIn service
300 	return STRFROMASCII( MY_SERVICE );
301 }
302 
303 
304 // XServiceInfo
305 
306 STRING SAL_CALL AnalysisAddIn::getImplementationName() THROWDEF_RTE
307 {
308 	return getImplementationName_Static();
309 }
310 
311 
312 sal_Bool SAL_CALL AnalysisAddIn::supportsService( const STRING& aName ) THROWDEF_RTE
313 {
314 	return aName.compareToAscii( ADDIN_SERVICE ) == 0 || aName.compareToAscii( MY_SERVICE ) == 0;
315 }
316 
317 
318 SEQ( STRING ) SAL_CALL AnalysisAddIn::getSupportedServiceNames() THROWDEF_RTE
319 {
320 	return getSupportedServiceNames_Static();
321 }
322 
323 
324 // XLocalizable
325 
326 void SAL_CALL AnalysisAddIn::setLocale( const lang::Locale& eLocale ) THROWDEF_RTE
327 {
328 	aFuncLoc = eLocale;
329 
330 	InitData();		// change of locale invalidates resources!
331 }
332 
333 lang::Locale SAL_CALL AnalysisAddIn::getLocale() THROWDEF_RTE
334 {
335 	return aFuncLoc;
336 }
337 
338 
339 // XAddIn
340 
341 STRING SAL_CALL AnalysisAddIn::getProgrammaticFuntionName( const STRING& ) THROWDEF_RTE
342 {
343 	//	not used by calc
344 	//	(but should be implemented for other uses of the AddIn service)
345 
346 	return STRING();
347 }
348 
349 
350 STRING SAL_CALL AnalysisAddIn::getDisplayFunctionName( const STRING& aProgrammaticName ) THROWDEF_RTE
351 {
352 	STRING			aRet;
353 
354 	const FuncData*	p = pFD->Get( aProgrammaticName );
355 	if( p )
356 	{
357 		aRet = GetDisplFuncStr( p->GetUINameID() );
358 		if( p->IsDouble() )
359 			aRet += STRFROMANSI( "_ADD" );
360 	}
361 	else
362 	{
363 		aRet = STRFROMANSI( "UNKNOWNFUNC_" );
364 		aRet += aProgrammaticName;
365 	}
366 
367 	return aRet;
368 }
369 
370 
371 STRING SAL_CALL AnalysisAddIn::getFunctionDescription( const STRING& aProgrammaticName ) THROWDEF_RTE
372 {
373 	STRING			aRet;
374 
375 	const FuncData*	p = pFD->Get( aProgrammaticName );
376 	if( p )
377 		aRet = GetFuncDescrStr( p->GetDescrID(), 1 );
378 
379 	return aRet;
380 }
381 
382 
383 STRING SAL_CALL AnalysisAddIn::getDisplayArgumentName( const STRING& aName, sal_Int32 nArg ) THROWDEF_RTE
384 {
385 	STRING			aRet;
386 
387 	const FuncData*	p = pFD->Get( aName );
388 	if( p && nArg <= 0xFFFF )
389 	{
390 		sal_uInt16	nStr = p->GetStrIndex( sal_uInt16( nArg ) );
391 		if( nStr /*&& nStr < 4*/ )
392 			aRet = GetFuncDescrStr( p->GetDescrID(), nStr );
393 		else
394 			aRet = STRFROMANSI( "internal" );
395 	}
396 
397 	return aRet;
398 }
399 
400 
401 STRING SAL_CALL AnalysisAddIn::getArgumentDescription( const STRING& aName, sal_Int32 nArg ) THROWDEF_RTE
402 {
403 	STRING			aRet;
404 
405 	const FuncData*	p = pFD->Get( aName );
406 	if( p && nArg <= 0xFFFF )
407 	{
408 		sal_uInt16	nStr = p->GetStrIndex( sal_uInt16( nArg ) );
409 		if( nStr /*&& nStr < 4*/ )
410 			aRet = GetFuncDescrStr( p->GetDescrID(), nStr + 1 );
411 		else
412 			aRet = STRFROMANSI( "for internal use only" );
413 	}
414 
415 	return aRet;
416 }
417 
418 
419 static const char*	pDefCatName = "Add-In";
420 
421 
422 STRING SAL_CALL AnalysisAddIn::getProgrammaticCategoryName( const STRING& aName ) THROWDEF_RTE
423 {
424 	//	return non-translated strings
425 //	return STRFROMASCII( "Add-In" );
426 	const FuncData*		p = pFD->Get( aName );
427 	STRING				aRet;
428 	if( p )
429 	{
430 		const sal_Char*	pStr;
431 
432 		switch( p->GetCategory() )
433 		{
434 			case FDCat_DateTime:	pStr = "Date&Time";			break;
435 			case FDCat_Finance:		pStr = "Financial";			break;
436 			case FDCat_Inf:			pStr = "Information";		break;
437 			case FDCat_Math:		pStr = "Mathematical";		break;
438 			case FDCat_Tech:		pStr = "Technical";			break;
439 			default:
440 									pStr = pDefCatName;			break;
441 		}
442 
443 		aRet = STRFROMASCII( pStr );
444 	}
445 	else
446 		aRet = STRFROMASCII( pDefCatName );
447 
448 	return aRet;
449 }
450 
451 
452 STRING SAL_CALL AnalysisAddIn::getDisplayCategoryName( const STRING& aProgrammaticFunctionName ) THROWDEF_RTE
453 {
454 	//	return translated strings, not used for predefined categories
455 //	return STRFROMASCII( "Add-In" );
456 	const FuncData*		p = pFD->Get( aProgrammaticFunctionName );
457 	STRING				aRet;
458 	if( p )
459 	{
460 		const sal_Char*	pStr;
461 
462 		switch( p->GetCategory() )
463 		{
464 			case FDCat_DateTime:	pStr = "Date&Time";			break;
465 			case FDCat_Finance:		pStr = "Financial";			break;
466 			case FDCat_Inf:			pStr = "Information";		break;
467 			case FDCat_Math:		pStr = "Mathematical";		break;
468 			case FDCat_Tech:		pStr = "Technical";			break;
469 			default:
470 									pStr = pDefCatName;			break;
471 		}
472 
473 		aRet = STRFROMASCII( pStr );
474 	}
475 	else
476 		aRet = STRFROMASCII( pDefCatName );
477 
478 	return aRet;
479 }
480 
481 
482 static const sal_Char*		pLang[] = { "de", "en" };
483 static const sal_Char*		pCoun[] = { "DE", "US" };
484 static const sal_uInt32		nNumOfLoc = sizeof( pLang ) / sizeof( sal_Char* );
485 
486 
487 void AnalysisAddIn::InitDefLocales( void )
488 {
489 	pDefLocales = new CSS::lang::Locale[ nNumOfLoc ];
490 
491 	for( sal_uInt32 n = 0 ; n < nNumOfLoc ; n++ )
492 	{
493 		pDefLocales[ n ].Language = STRING::createFromAscii( pLang[ n ] );
494 		pDefLocales[ n ].Country = STRING::createFromAscii( pCoun[ n ] );
495 	}
496 }
497 
498 
499 inline const CSS::lang::Locale& AnalysisAddIn::GetLocale( sal_uInt32 nInd )
500 {
501 	if( !pDefLocales )
502 		InitDefLocales();
503 
504 	if( nInd < sizeof( pLang ) )
505 		return pDefLocales[ nInd ];
506 	else
507 		return aFuncLoc;
508 }
509 
510 
511 SEQofLocName SAL_CALL AnalysisAddIn::getCompatibilityNames( const STRING& aProgrammaticName ) THROWDEF_RTE
512 {
513 	const FuncData*				p = pFD->Get( aProgrammaticName );
514 
515 	if( !p )
516 		return SEQofLocName( 0 );
517 
518 	const StringList&			r = p->GetCompNameList();
519 	sal_uInt32					nCount = r.Count();
520 
521 	SEQofLocName				aRet( nCount );
522 
523 	CSS::sheet::LocalizedName*	pArray = aRet.getArray();
524 
525 	for( sal_uInt32 n = 0 ; n < nCount ; n++ )
526 	{
527 		pArray[ n ] = CSS::sheet::LocalizedName( GetLocale( n ), *r.Get( n ) );
528 	}
529 
530 	return aRet;
531 }
532 
533 
534 // XAnalysis
535 
536 /*double SAL_CALL AnalysisAddIn::get_Test( constREFXPS&,
537 	sal_Int32 nMode, double f1, double f2, double f3 ) THROWDEF_RTE
538 {
539 	return _Test( nMode, f1, f2, f3 );
540 }*/
541 
542 
543 /**
544  * Workday
545  */
546 
547 sal_Int32 SAL_CALL AnalysisAddIn::getWorkday( constREFXPS& xOptions,
548 	sal_Int32 nDate, sal_Int32 nDays, const ANY& aHDay ) THROWDEF_RTE_IAE
549 {
550 	if( !nDays )
551 		return nDate;
552 
553 	sal_Int32					nNullDate = GetNullDate( xOptions );
554 
555 	SortedIndividualInt32List	aSrtLst;
556 
557     aSrtLst.InsertHolidayList( aAnyConv, xOptions, aHDay, nNullDate, sal_False );
558 
559 	sal_Int32					nActDate = nDate + nNullDate;
560 
561 	if( nDays > 0 )
562 	{
563 		if( GetDayOfWeek( nActDate ) == 5 )
564 			// when starting on Saturday, assuming we're starting on Sunday to get the jump over the weekend
565 			nActDate++;
566 
567 		while( nDays )
568 		{
569 			nActDate++;
570 
571 			if( GetDayOfWeek( nActDate ) < 5 )
572 			{
573 				if( !aSrtLst.Find( nActDate ) )
574 					nDays--;
575 			}
576 			else
577 				nActDate++;		// jump over weekend
578 		}
579 	}
580 	else
581 	{
582 		if( GetDayOfWeek( nActDate ) == 6 )
583 			// when starting on Sunday, assuming we're starting on Saturday to get the jump over the weekend
584 			nActDate--;
585 
586 		while( nDays )
587 		{
588 			nActDate--;
589 
590 			if( GetDayOfWeek( nActDate ) < 5 )
591 			{
592 				if( !aSrtLst.Find( nActDate ) )
593 					nDays++;
594 			}
595 			else
596 				nActDate--;		// jump over weekend
597 		}
598 	}
599 
600 	return nActDate - nNullDate;
601 }
602 
603 
604 /**
605  * Yearfrac
606  */
607 
608 double SAL_CALL AnalysisAddIn::getYearfrac( constREFXPS& xOpt,
609 	sal_Int32 nStartDate, sal_Int32 nEndDate, const ANY& rMode ) THROWDEF_RTE_IAE
610 {
611     double fRet = GetYearFrac( xOpt, nStartDate, nEndDate, getDateMode( xOpt, rMode ) );
612     RETURN_FINITE( fRet );
613 }
614 
615 
616 sal_Int32 SAL_CALL AnalysisAddIn::getEdate( constREFXPS& xOpt, sal_Int32 nStartDate, sal_Int32 nMonths ) THROWDEF_RTE_IAE
617 {
618     sal_Int32 nNullDate = GetNullDate( xOpt );
619     ScaDate aDate( nNullDate, nStartDate, 5 );
620     aDate.addMonths( nMonths );
621     return aDate.getDate( nNullDate );
622 }
623 
624 
625 sal_Int32 SAL_CALL AnalysisAddIn::getWeeknum( constREFXPS& xOpt, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
626 {
627 	nDate += GetNullDate( xOpt );
628 
629 	sal_uInt16	nDay, nMonth, nYear;
630 	DaysToDate( nDate, nDay, nMonth, nYear );
631 
632 	sal_Int32	nFirstInYear = DateToDays( 1, 1, nYear );
633 	sal_uInt16	nFirstDayInYear = GetDayOfWeek( nFirstInYear );
634 
635 	return ( nDate - nFirstInYear + ( ( nMode == 1 )? ( nFirstDayInYear + 1 ) % 7 : nFirstDayInYear ) ) / 7 + 1;
636 }
637 
638 
639 sal_Int32 SAL_CALL AnalysisAddIn::getEomonth( constREFXPS& xOpt, sal_Int32 nDate, sal_Int32 nMonths ) THROWDEF_RTE_IAE
640 {
641 	sal_Int32	nNullDate = GetNullDate( xOpt );
642 	nDate += nNullDate;
643 	sal_uInt16	nDay, nMonth, nYear;
644 	DaysToDate( nDate, nDay, nMonth, nYear );
645 
646 	sal_Int32	nNewMonth = nMonth + nMonths;
647 
648 	if( nNewMonth > 12 )
649 	{
650         nYear = sal::static_int_cast<sal_uInt16>( nYear + ( nNewMonth / 12 ) );
651 		nNewMonth %= 12;
652 	}
653 	else if( nNewMonth < 1 )
654 	{
655 		nNewMonth = -nNewMonth;
656         nYear = sal::static_int_cast<sal_uInt16>( nYear - ( nNewMonth / 12 ) );
657 		nYear--;
658 		nNewMonth %= 12;
659 		nNewMonth = 12 - nNewMonth;
660 	}
661 
662 	return DateToDays( DaysInMonth( sal_uInt16( nNewMonth ), nYear ), sal_uInt16( nNewMonth ), nYear ) - nNullDate;
663 }
664 
665 
666 sal_Int32 SAL_CALL AnalysisAddIn::getNetworkdays( constREFXPS& xOpt,
667 		sal_Int32 nStartDate, sal_Int32 nEndDate, const ANY& aHDay ) THROWDEF_RTE_IAE
668 {
669 	sal_Int32					nNullDate = GetNullDate( xOpt );
670 
671 	SortedIndividualInt32List	aSrtLst;
672 
673     aSrtLst.InsertHolidayList( aAnyConv, xOpt, aHDay, nNullDate, sal_False );
674 
675 	sal_Int32					nActDate = nStartDate + nNullDate;
676 	sal_Int32					nStopDate = nEndDate + nNullDate;
677 	sal_Int32					nCnt = 0;
678 
679 	if( nActDate <= nStopDate )
680 	{
681 		while( nActDate <= nStopDate )
682 		{
683 			if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) )
684 				nCnt++;
685 
686 			nActDate++;
687 		}
688 	}
689 	else
690 	{
691 		while( nActDate >= nStopDate )
692 		{
693 			if( GetDayOfWeek( nActDate ) < 5 && !aSrtLst.Find( nActDate ) )
694 				nCnt--;
695 
696 			nActDate--;
697 		}
698 	}
699 
700 	return nCnt;
701 }
702 
703 
704 sal_Int32 SAL_CALL AnalysisAddIn::getIseven( sal_Int32 nVal ) THROWDEF_RTE_IAE
705 {
706 	return ( nVal & 0x00000001 )? 0 : 1;
707 }
708 
709 
710 sal_Int32 SAL_CALL AnalysisAddIn::getIsodd( sal_Int32 nVal ) THROWDEF_RTE_IAE
711 {
712 	return ( nVal & 0x00000001 )? 1 : 0;
713 }
714 
715 double SAL_CALL
716 AnalysisAddIn::getMultinomial( constREFXPS& xOpt, const SEQSEQ( sal_Int32 )& aVLst,
717 							   const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE
718 {
719     ScaDoubleListGE0 aValList;
720 
721 	aValList.Append( aVLst );
722     aValList.Append( aAnyConv, xOpt, aOptVLst );
723 
724 	if( aValList.Count() == 0 )
725 		return 0.0;
726 
727 	sal_Int32 nZ = 0;
728 	double    fN = 1.0;
729 
730 	for( const double *p = aValList.First(); p; p = aValList.Next() )
731 	{
732         double fInt = (*p >= 0.0) ? rtl::math::approxFloor( *p ) : rtl::math::approxCeil( *p );
733         if ( fInt < 0.0 || fInt > 170.0 )
734             THROW_IAE;
735         sal_Int32 n = static_cast< sal_Int32 >( fInt );
736         if( n > 0 )
737 		{
738 			nZ += n;
739 			fN *= Fak( n );
740 		}
741 	}
742 
743     if( nZ > 170 )
744         THROW_IAE;
745 
746     double fRet = Fak( nZ ) / fN;
747     RETURN_FINITE( fRet );
748 }
749 
750 
751 double SAL_CALL AnalysisAddIn::getSeriessum( double fX, double fN, double fM, const SEQSEQ( double )& aCoeffList ) THROWDEF_RTE_IAE
752 {
753 	double							fRet = 0.0;
754 
755     // #i32269# 0^0 is undefined, Excel returns #NUM! error
756     if( fX == 0.0 && fN == 0 )
757         THROW_RTE;
758 
759 	if( fX != 0.0 )
760 	{
761 		sal_Int32		n1, n2;
762 		sal_Int32		nE1 = aCoeffList.getLength();
763 		sal_Int32		nE2;
764 		//sal_Int32		nZ = 0;
765 
766 		for( n1 = 0 ; n1 < nE1 ; n1++ )
767 		{
768 			const SEQ( double )&	rList = aCoeffList[ n1 ];
769 			nE2 = rList.getLength();
770 			const double*			pList = rList.getConstArray();
771 
772 			for( n2 = 0 ; n2 < nE2 ; n2++ )
773 			{
774 				fRet += pList[ n2 ] * pow( fX, fN );
775 
776 				fN += fM;
777 			}
778 		}
779 	}
780 
781     RETURN_FINITE( fRet );
782 }
783 
784 
785 double SAL_CALL AnalysisAddIn::getQuotient( double fNum, double fDenom ) THROWDEF_RTE_IAE
786 {
787     double fRet;
788     if( (fNum < 0) != (fDenom < 0) )
789         fRet = ::rtl::math::approxCeil( fNum / fDenom );
790     else
791         fRet = ::rtl::math::approxFloor( fNum / fDenom );
792     RETURN_FINITE( fRet );
793 }
794 
795 
796 double SAL_CALL AnalysisAddIn::getMround( double fNum, double fMult ) THROWDEF_RTE_IAE
797 {
798 	if( fMult == 0.0 )
799 		return fMult;
800 
801     double fRet = fMult * ::rtl::math::round( fNum / fMult );
802     RETURN_FINITE( fRet );
803 }
804 
805 
806 double SAL_CALL AnalysisAddIn::getSqrtpi( double fNum ) THROWDEF_RTE_IAE
807 {
808     double fRet = sqrt( fNum * PI );
809     RETURN_FINITE( fRet );
810 }
811 
812 
813 double SAL_CALL AnalysisAddIn::getRandbetween( double fMin, double fMax ) THROWDEF_RTE_IAE
814 {
815     fMin = ::rtl::math::round( fMin, 0, rtl_math_RoundingMode_Up );
816     fMax = ::rtl::math::round( fMax, 0, rtl_math_RoundingMode_Up );
817 	if( fMin > fMax )
818 		THROW_IAE;
819 
820 	// fMax -> range
821     double fRet = fMax - fMin + 1.0;
822     fRet *= rand();
823     fRet /= (RAND_MAX + 1.0);
824     fRet += fMin;
825     fRet = floor( fRet );   // simple floor is sufficient here
826     RETURN_FINITE( fRet );
827 }
828 
829 
830 double SAL_CALL AnalysisAddIn::getGcd( constREFXPS& xOpt, const SEQSEQ( double )& aVLst, const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE
831 {
832     ScaDoubleListGT0 aValList;
833 
834 	aValList.Append( aVLst );
835     aValList.Append( aAnyConv, xOpt, aOptVLst );
836 
837 	if( aValList.Count() == 0 )
838 		return 0.0;
839 
840 	const double*	p = aValList.First();
841 	double			f = *p;
842 
843 	p = aValList.Next();
844 
845 	while( p )
846 	{
847 		f = GetGcd( *p, f );
848 		p = aValList.Next();
849 	}
850 
851     RETURN_FINITE( f );
852 }
853 
854 
855 double SAL_CALL AnalysisAddIn::getLcm( constREFXPS& xOpt, const SEQSEQ( double )& aVLst, const SEQ( uno::Any )& aOptVLst ) THROWDEF_RTE_IAE
856 {
857     ScaDoubleListGE0 aValList;
858 
859 	aValList.Append( aVLst );
860     aValList.Append( aAnyConv, xOpt, aOptVLst );
861 
862 	if( aValList.Count() == 0 )
863 		return 0.0;
864 
865 	const double*	p = aValList.First();
866 	double			f = *p;
867 
868 	if( f == 0.0 )
869 		return f;
870 
871 	p = aValList.Next();
872 
873 	while( p )
874 	{
875 		double		fTmp = *p;
876 		if( f == 0.0 )
877 			return f;
878 		else
879 			f = fTmp * f / GetGcd( fTmp, f );
880 		p = aValList.Next();
881 	}
882 
883     RETURN_FINITE( f );
884 }
885 
886 
887 double SAL_CALL AnalysisAddIn::getBesseli( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
888 {
889     double fRet = sca::analysis::BesselI( fNum, nOrder );
890     RETURN_FINITE( fRet );
891 }
892 
893 
894 double SAL_CALL AnalysisAddIn::getBesselj( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
895 {
896     double fRet = sca::analysis::BesselJ( fNum, nOrder );
897     RETURN_FINITE( fRet );
898 }
899 
900 
901 double SAL_CALL AnalysisAddIn::getBesselk( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
902 {
903 	if( nOrder < 0 || fNum <= 0.0 )
904 		THROW_IAE;
905 
906     double fRet = sca::analysis::BesselK( fNum, nOrder );
907     RETURN_FINITE( fRet );
908 }
909 
910 
911 double SAL_CALL AnalysisAddIn::getBessely( double fNum, sal_Int32 nOrder ) THROWDEF_RTE_IAE_NCE
912 {
913 	if( nOrder < 0 || fNum <= 0.0 )
914 		THROW_IAE;
915 
916 //	return yn( nOrder, fNum );
917     double fRet = sca::analysis::BesselY( fNum, nOrder );
918     RETURN_FINITE( fRet );
919 }
920 
921 
922 const double    SCA_MAX2        = 511.0;            // min. val for binary numbers (9 bits + sign)
923 const double    SCA_MIN2        = -SCA_MAX2-1.0;    // min. val for binary numbers (9 bits + sign)
924 const double    SCA_MAX8        = 536870911.0;      // max. val for octal numbers (29 bits + sign)
925 const double    SCA_MIN8        = -SCA_MAX8-1.0;    // min. val for octal numbers (29 bits + sign)
926 const double    SCA_MAX16       = 549755813888.0;   // max. val for hexadecimal numbers (39 bits + sign)
927 const double    SCA_MIN16       = -SCA_MAX16-1.0;   // min. val for hexadecimal numbers (39 bits + sign)
928 const sal_Int32 SCA_MAXPLACES   = 10;               // max. number of places
929 
930 
931 STRING SAL_CALL AnalysisAddIn::getBin2Oct( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
932 {
933     double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
934     sal_Int32 nPlaces = 0;
935     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
936     return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
937 }
938 
939 
940 double SAL_CALL AnalysisAddIn::getBin2Dec( const STRING& aNum ) THROWDEF_RTE_IAE
941 {
942     double fRet = ConvertToDec( aNum, 2, SCA_MAXPLACES );
943     RETURN_FINITE( fRet );
944 }
945 
946 
947 STRING SAL_CALL AnalysisAddIn::getBin2Hex( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
948 {
949     double fVal = ConvertToDec( aNum, 2, SCA_MAXPLACES );
950     sal_Int32 nPlaces = 0;
951     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
952     return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
953 }
954 
955 
956 STRING SAL_CALL AnalysisAddIn::getOct2Bin( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
957 {
958     double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
959     sal_Int32 nPlaces = 0;
960     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
961     return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
962 }
963 
964 
965 double SAL_CALL AnalysisAddIn::getOct2Dec( const STRING& aNum ) THROWDEF_RTE_IAE
966 {
967     double fRet = ConvertToDec( aNum, 8, SCA_MAXPLACES );
968     RETURN_FINITE( fRet );
969 }
970 
971 
972 STRING SAL_CALL AnalysisAddIn::getOct2Hex( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
973 {
974     double fVal = ConvertToDec( aNum, 8, SCA_MAXPLACES );
975     sal_Int32 nPlaces = 0;
976     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
977     return ConvertFromDec( fVal, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
978 }
979 
980 
981 STRING SAL_CALL AnalysisAddIn::getDec2Bin( constREFXPS& xOpt, sal_Int32 nNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
982 {
983     sal_Int32 nPlaces = 0;
984     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
985     return ConvertFromDec( nNum, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
986 }
987 
988 
989 STRING SAL_CALL AnalysisAddIn::getDec2Oct( constREFXPS& xOpt, sal_Int32 nNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
990 {
991     sal_Int32 nPlaces = 0;
992     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
993     return ConvertFromDec( nNum, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
994 }
995 
996 
997 STRING SAL_CALL AnalysisAddIn::getDec2Hex( constREFXPS& xOpt, double fNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
998 {
999     sal_Int32 nPlaces = 0;
1000     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
1001     return ConvertFromDec( fNum, SCA_MIN16, SCA_MAX16, 16, nPlaces, SCA_MAXPLACES, bUsePlaces );
1002 }
1003 
1004 
1005 STRING SAL_CALL AnalysisAddIn::getHex2Bin( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
1006 {
1007     double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
1008     sal_Int32 nPlaces = 0;
1009     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
1010     return ConvertFromDec( fVal, SCA_MIN2, SCA_MAX2, 2, nPlaces, SCA_MAXPLACES, bUsePlaces );
1011 }
1012 
1013 
1014 double SAL_CALL AnalysisAddIn::getHex2Dec( const STRING& aNum ) THROWDEF_RTE_IAE
1015 {
1016     double fRet = ConvertToDec( aNum, 16, SCA_MAXPLACES );
1017     RETURN_FINITE( fRet );
1018 }
1019 
1020 
1021 STRING SAL_CALL AnalysisAddIn::getHex2Oct( constREFXPS& xOpt, const STRING& aNum, const ANY& rPlaces ) THROWDEF_RTE_IAE
1022 {
1023     double fVal = ConvertToDec( aNum, 16, SCA_MAXPLACES );
1024     sal_Int32 nPlaces = 0;
1025     sal_Bool bUsePlaces = aAnyConv.getInt32( nPlaces, xOpt, rPlaces );
1026     return ConvertFromDec( fVal, SCA_MIN8, SCA_MAX8, 8, nPlaces, SCA_MAXPLACES, bUsePlaces );
1027 }
1028 
1029 
1030 sal_Int32 SAL_CALL AnalysisAddIn::getDelta( constREFXPS& xOpt, double fNum1, const ANY& rNum2 ) THROWDEF_RTE_IAE
1031 {
1032     return fNum1 == aAnyConv.getDouble( xOpt, rNum2, 0.0 );
1033 }
1034 
1035 
1036 double SAL_CALL AnalysisAddIn::getErf( constREFXPS& xOpt, double fLL, const ANY& rUL ) THROWDEF_RTE_IAE
1037 {
1038     double fUL, fRet;
1039     sal_Bool bContainsValue = aAnyConv.getDouble( fUL, xOpt, rUL );
1040 
1041     fRet = bContainsValue ? (Erf( fUL ) - Erf( fLL )) : Erf( fLL );
1042     RETURN_FINITE( fRet );
1043 }
1044 
1045 
1046 double SAL_CALL AnalysisAddIn::getErfc( double f ) THROWDEF_RTE_IAE
1047 {
1048 	double fRet = Erfc( f );
1049     RETURN_FINITE( fRet );
1050 }
1051 
1052 
1053 sal_Int32 SAL_CALL AnalysisAddIn::getGestep( constREFXPS& xOpt, double fNum, const ANY& rStep ) THROWDEF_RTE_IAE
1054 {
1055     return fNum >= aAnyConv.getDouble( xOpt, rStep, 0.0 );
1056 }
1057 
1058 
1059 double SAL_CALL AnalysisAddIn::getFactdouble( sal_Int32 nNum ) THROWDEF_RTE_IAE
1060 {
1061     double fRet = FactDouble( nNum );
1062     RETURN_FINITE( fRet );
1063 }
1064 
1065 
1066 double SAL_CALL AnalysisAddIn::getImabs( const STRING& aNum ) THROWDEF_RTE_IAE
1067 {
1068     double fRet = Complex( aNum ).Abs();
1069     RETURN_FINITE( fRet );
1070 }
1071 
1072 
1073 double SAL_CALL AnalysisAddIn::getImaginary( const STRING& aNum ) THROWDEF_RTE_IAE
1074 {
1075     double fRet = Complex( aNum ).Imag();
1076     RETURN_FINITE( fRet );
1077 }
1078 
1079 
1080 STRING SAL_CALL AnalysisAddIn::getImpower( const STRING& aNum, double f ) THROWDEF_RTE_IAE
1081 {
1082 	Complex		z( aNum );
1083 
1084 	z.Power( f );
1085 
1086 	return z.GetString();
1087 }
1088 
1089 
1090 double SAL_CALL AnalysisAddIn::getImargument( const STRING& aNum ) THROWDEF_RTE_IAE
1091 {
1092     double fRet = Complex( aNum ).Arg();
1093     RETURN_FINITE( fRet );
1094 }
1095 
1096 
1097 STRING SAL_CALL AnalysisAddIn::getImcos( const STRING& aNum ) THROWDEF_RTE_IAE
1098 {
1099 	Complex		z( aNum );
1100 
1101 	z.Cos();
1102 
1103 	return z.GetString();
1104 }
1105 
1106 
1107 STRING SAL_CALL AnalysisAddIn::getImdiv( const STRING& aDivid, const STRING& aDivis ) THROWDEF_RTE_IAE
1108 {
1109 	Complex		z( aDivid );
1110 
1111 	z.Div( Complex( aDivis ) );
1112 
1113 	return z.GetString();
1114 }
1115 
1116 
1117 STRING SAL_CALL AnalysisAddIn::getImexp( const STRING& aNum ) THROWDEF_RTE_IAE
1118 {
1119 	Complex		z( aNum );
1120 
1121 	z.Exp();
1122 
1123 	return z.GetString();
1124 }
1125 
1126 
1127 STRING SAL_CALL AnalysisAddIn::getImconjugate( const STRING& aNum ) THROWDEF_RTE_IAE
1128 {
1129 	Complex		z( aNum );
1130 
1131 	z.Conjugate();
1132 
1133 	return z.GetString();
1134 }
1135 
1136 
1137 STRING SAL_CALL AnalysisAddIn::getImln( const STRING& aNum ) THROWDEF_RTE_IAE
1138 {
1139 	Complex		z( aNum );
1140 
1141 	z.Ln();
1142 
1143 	return z.GetString();
1144 }
1145 
1146 
1147 STRING SAL_CALL AnalysisAddIn::getImlog10( const STRING& aNum ) THROWDEF_RTE_IAE
1148 {
1149 	Complex		z( aNum );
1150 
1151 	z.Log10();
1152 
1153 	return z.GetString();
1154 }
1155 
1156 
1157 STRING SAL_CALL AnalysisAddIn::getImlog2( const STRING& aNum ) THROWDEF_RTE_IAE
1158 {
1159 	Complex		z( aNum );
1160 
1161 	z.Log2();
1162 
1163 	return z.GetString();
1164 }
1165 
1166 
1167 STRING SAL_CALL AnalysisAddIn::getImproduct( constREFXPS&, const SEQSEQ( STRING )& aNum1, const SEQ( uno::Any )& aNL ) THROWDEF_RTE_IAE
1168 {
1169 	ComplexList		z_list;
1170 
1171 	z_list.Append( aNum1, AH_IgnoreEmpty );
1172 	z_list.Append( aNL, AH_IgnoreEmpty );
1173 
1174 	const Complex*	p = z_list.First();
1175 
1176 	if( !p )
1177 		return Complex( 0 ).GetString();
1178 
1179 	Complex			z( *p );
1180 
1181 	for( p = z_list.Next() ; p ; p = z_list.Next() )
1182 		z.Mult( *p );
1183 
1184 	return z.GetString();
1185 }
1186 
1187 
1188 double SAL_CALL AnalysisAddIn::getImreal( const STRING& aNum ) THROWDEF_RTE_IAE
1189 {
1190     double fRet = Complex( aNum ).Real();
1191     RETURN_FINITE( fRet );
1192 }
1193 
1194 
1195 STRING SAL_CALL AnalysisAddIn::getImsin( const STRING& aNum ) THROWDEF_RTE_IAE
1196 {
1197 	Complex		z( aNum );
1198 
1199 	z.Sin();
1200 
1201 	return z.GetString();
1202 }
1203 
1204 
1205 STRING SAL_CALL AnalysisAddIn::getImsub( const STRING& aNum1, const STRING& aNum2 ) THROWDEF_RTE_IAE
1206 {
1207 	Complex		z( aNum1 );
1208 
1209 	z.Sub( Complex( aNum2 ) );
1210 
1211 	return z.GetString();
1212 }
1213 
1214 
1215 STRING SAL_CALL AnalysisAddIn::getImsum( constREFXPS&, const SEQSEQ( STRING )& aNum1, const SEQ( CSS::uno::Any )& aFollowingPars ) THROWDEF_RTE_IAE
1216 {
1217 	ComplexList		z_list;
1218 
1219 	z_list.Append( aNum1, AH_IgnoreEmpty );
1220 	z_list.Append( aFollowingPars, AH_IgnoreEmpty );
1221 
1222 	const Complex*	p = z_list.First();
1223 
1224 	if( !p )
1225 		return Complex( 0 ).GetString();
1226 
1227 	Complex			z( *p );
1228 
1229 	for( p = z_list.Next() ; p ; p = z_list.Next() )
1230 		z.Add( *p );
1231 
1232 	return z.GetString();
1233 }
1234 
1235 
1236 STRING SAL_CALL AnalysisAddIn::getImsqrt( const STRING& aNum ) THROWDEF_RTE_IAE
1237 {
1238 	Complex		z( aNum );
1239 
1240 //	z.Power( 0.5 );
1241 	z.Sqrt();
1242 
1243 	return z.GetString();
1244 }
1245 
1246 
1247 STRING SAL_CALL AnalysisAddIn::getComplex( double fR, double fI, const ANY& rSuff ) THROWDEF_RTE_IAE
1248 {
1249 	sal_Bool	bi;
1250 
1251 	switch( rSuff.getValueTypeClass() )
1252 	{
1253 		case uno::TypeClass_VOID:
1254 			bi = sal_True;
1255 			break;
1256 		case uno::TypeClass_STRING:
1257 			{
1258 			const STRING*	pSuff = ( const STRING* ) rSuff.getValue();
1259 			bi = pSuff->compareToAscii( "i" ) == 0 || pSuff->getLength() == 0;
1260 			if( !bi && pSuff->compareToAscii( "j" ) != 0 )
1261 				THROW_IAE;
1262 			}
1263 			break;
1264 		default:
1265 			THROW_IAE;
1266 	}
1267 
1268 	return Complex( fR, fI, bi ? 'i' : 'j' ).GetString();
1269 }
1270 
1271 
1272 double SAL_CALL AnalysisAddIn::getConvert( double f, const STRING& aFU, const STRING& aTU ) THROWDEF_RTE_IAE
1273 {
1274 	if( !pCDL )
1275 		pCDL = new ConvertDataList();
1276 
1277     double fRet = pCDL->Convert( f, aFU, aTU );
1278     RETURN_FINITE( fRet );
1279 }
1280 
1281 
1282