You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
10 KiB
282 lines
10 KiB
/* ====================================================================
|
|
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.
|
|
==================================================================== */
|
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using NPOI.SS.Formula.Function;
|
|
|
|
namespace NPOI.SS.Formula.Atp {
|
|
using System;
|
|
using System.Collections;
|
|
using NPOI.SS.Formula;
|
|
using NPOI.SS.Formula.Eval;
|
|
using NPOI.SS.Formula.Functions;
|
|
using NPOI.SS.Formula.UDF;
|
|
|
|
public class NotImplemented : FreeRefFunction
|
|
{
|
|
private String _functionName;
|
|
|
|
public NotImplemented(String functionName)
|
|
{
|
|
_functionName = functionName;
|
|
}
|
|
|
|
public ValueEval Evaluate(ValueEval[] args, OperationEvaluationContext ec)
|
|
{
|
|
throw new NotImplementedFunctionException(_functionName);
|
|
}
|
|
}
|
|
|
|
public class AnalysisToolPak : UDFFinder
|
|
{
|
|
public static UDFFinder instance = new AnalysisToolPak();
|
|
|
|
private static Dictionary<String, FreeRefFunction> _functionsByName = CreateFunctionsMap();
|
|
|
|
private AnalysisToolPak()
|
|
{
|
|
// no instances of this class
|
|
}
|
|
|
|
public override FreeRefFunction FindFunction(String name)
|
|
{
|
|
// functions that are available in Excel 2007+ have a prefix _xlfn.
|
|
// if you save such a .xlsx workbook as .xls
|
|
if (name.StartsWith("_xlfn.")) name = name.Substring(6);
|
|
|
|
string key = name.ToUpper();
|
|
if (_functionsByName.ContainsKey(key))
|
|
return (FreeRefFunction)_functionsByName[key];
|
|
|
|
return null;
|
|
}
|
|
|
|
private static Dictionary<String, FreeRefFunction> CreateFunctionsMap()
|
|
{
|
|
Dictionary<String, FreeRefFunction> m = new Dictionary<String, FreeRefFunction>(120);
|
|
|
|
r(m, "ACCRINT", null);
|
|
r(m, "ACCRINTM", null);
|
|
r(m, "AMORDEGRC", null);
|
|
r(m, "AMORLINC", null);
|
|
r(m, "AVERAGEIF", AverageIf.instance);
|
|
r(m, "AVERAGEIFS", AverageIfs.instance);
|
|
r(m, "BAHTTEXT", null);
|
|
r(m, "BESSELI", null);
|
|
r(m, "BESSELJ", null);
|
|
r(m, "BESSELK", null);
|
|
r(m, "BESSELY", null);
|
|
r(m, "BIN2DEC", Bin2Dec.instance);
|
|
r(m, "BIN2HEX", null);
|
|
r(m, "BIN2OCT", null);
|
|
r(m, "COMPLEX", Complex.Instance);
|
|
r(m, "CONVERT", null);
|
|
r(m, "COUNTIFS", Countifs.instance);
|
|
r(m, "COUPDAYBS", null);
|
|
r(m, "COUPDAYS", null);
|
|
r(m, "COUPDAYSNC", null);
|
|
r(m, "COUPNCD", null);
|
|
r(m, "COUPNUM", null);
|
|
r(m, "COUPPCD", null);
|
|
r(m, "CUBEKPIMEMBER", null);
|
|
r(m, "CUBEMEMBER", null);
|
|
r(m, "CUBEMEMBERPROPERTY", null);
|
|
r(m, "CUBERANKEDMEMBER", null);
|
|
r(m, "CUBESET", null);
|
|
r(m, "CUBESETCOUNT", null);
|
|
r(m, "CUBEVALUE", null);
|
|
r(m, "CUMIPMT", null);
|
|
r(m, "CUMPRINC", null);
|
|
r(m, "DEC2BIN", Dec2Bin.instance);
|
|
r(m, "DEC2HEX", Dec2Hex.instance);
|
|
r(m, "DEC2OCT", null);
|
|
r(m, "DELTA", Delta.instance);
|
|
r(m, "DISC", null);
|
|
r(m, "DOLLARDE", null);
|
|
r(m, "DOLLARFR", null);
|
|
r(m, "DURATION", null);
|
|
r(m, "EDATE", EDate.Instance);
|
|
r(m, "EFFECT", null);
|
|
r(m, "EOMONTH", EOMonth.instance);
|
|
r(m, "ERF", null);
|
|
r(m, "ERFC", null);
|
|
r(m, "FACTDOUBLE", FactDouble.instance);
|
|
r(m, "FVSCHEDULE", null);
|
|
r(m, "GCD", null);
|
|
r(m, "GESTEP", null);
|
|
r(m, "HEX2BIN", null);
|
|
r(m, "HEX2DEC", Hex2Dec.instance);
|
|
r(m, "HEX2OCT", null);
|
|
r(m, "IFERROR", IfError.Instance);
|
|
r(m, "IFNA", IfNa.instance);
|
|
r(m, "IFS", Ifs.Instance);
|
|
r(m, "IMABS", null);
|
|
r(m, "IMAGINARY", Imaginary.instance);
|
|
r(m, "IMARGUMENT", null);
|
|
r(m, "IMCONJUGATE", null);
|
|
r(m, "IMCOS", null);
|
|
r(m, "IMDIV", null);
|
|
r(m, "IMEXP", null);
|
|
r(m, "IMLN", null);
|
|
r(m, "IMLOG10", null);
|
|
r(m, "IMLOG2", null);
|
|
r(m, "IMPOWER", null);
|
|
r(m, "IMPRODUCT", null);
|
|
r(m, "IMREAL", ImReal.instance);
|
|
r(m, "IMSIN", null);
|
|
r(m, "IMSQRT", null);
|
|
r(m, "IMSUB", null);
|
|
r(m, "IMSUM", null);
|
|
r(m, "INTRATE", null);
|
|
r(m, "ISEVEN", ParityFunction.IS_EVEN);
|
|
r(m, "ISODD", ParityFunction.IS_ODD);
|
|
r(m, "JIS", null);
|
|
r(m, "LCM", null);
|
|
r(m, "MAXIFS", Maxifs.instance);
|
|
r(m, "MDURATION", null);
|
|
r(m, "MINIFS", Minifs.instance);
|
|
r(m, "MROUND", MRound.Instance);
|
|
r(m, "MULTINOMIAL", null);
|
|
r(m, "NETWORKDAYS", NetworkdaysFunction.instance);
|
|
r(m, "NOMINAL", null);
|
|
r(m, "OCT2BIN", null);
|
|
r(m, "OCT2DEC", Oct2Dec.instance);
|
|
r(m, "OCT2HEX", null);
|
|
r(m, "ODDFPRICE", null);
|
|
r(m, "ODDFYIELD", null);
|
|
r(m, "ODDLPRICE", null);
|
|
r(m, "ODDLYIELD", null);
|
|
r(m, "PRICE", null);
|
|
r(m, "PRICEDISC", null);
|
|
r(m, "PRICEMAT", null);
|
|
r(m, "QUOTIENT", Quotient.instance);
|
|
r(m, "RANDBETWEEN", RandBetween.Instance);
|
|
r(m, "RECEIVED", null);
|
|
r(m, "RTD", null);
|
|
r(m, "SERIESSUM", null);
|
|
r(m, "SQRTPI", null);
|
|
r(m, "SUMIFS", Sumifs.instance);
|
|
r(m, "SWITCH", Switch.instance);
|
|
r(m, "TBILLEQ", null);
|
|
r(m, "TBILLPRICE", null);
|
|
r(m, "TBILLYIELD", null);
|
|
r(m, "TEXTJOIN", TextJoinFunction.instance);
|
|
r(m, "WEEKNUM", WeekNum.instance);
|
|
r(m, "WORKDAY", WorkdayFunction.instance);
|
|
r(m, "XIRR", null);
|
|
r(m, "XLOOKUP", XLookupFunction.instance);
|
|
r(m, "XMATCH", XMatchFunction.instance);
|
|
r(m, "XNPV", null);
|
|
r(m, "YEARFRAC", YearFrac.instance);
|
|
r(m, "YIELD", null);
|
|
r(m, "YIELDDISC", null);
|
|
r(m, "YIELDMAT", null);
|
|
return m;
|
|
}
|
|
|
|
private static void r(Dictionary<String, FreeRefFunction> m, String functionName, FreeRefFunction pFunc)
|
|
{
|
|
FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
|
|
m[functionName]= func;
|
|
}
|
|
|
|
public static bool IsATPFunction(String name)
|
|
{
|
|
//AnalysisToolPak inst = (AnalysisToolPak)instance;
|
|
return AnalysisToolPak._functionsByName.ContainsKey(name);
|
|
}
|
|
|
|
/**
|
|
* Returns a collection of ATP function names implemented by POI.
|
|
*
|
|
* @return an array of supported functions
|
|
* @since 3.8 beta6
|
|
*/
|
|
public static ReadOnlyCollection<String> GetSupportedFunctionNames()
|
|
{
|
|
AnalysisToolPak inst = (AnalysisToolPak)instance;
|
|
List<String> lst = new List<String>();
|
|
foreach (KeyValuePair<String, FreeRefFunction> me in AnalysisToolPak._functionsByName)
|
|
{
|
|
FreeRefFunction func = me.Value;
|
|
if (func != null && !(func is NotImplemented))
|
|
{
|
|
lst.Add(me.Key);
|
|
}
|
|
}
|
|
return lst.AsReadOnly(); //Collections.unmodifiableCollection(lst);
|
|
}
|
|
|
|
/**
|
|
* Returns a collection of ATP function names NOT implemented by POI.
|
|
*
|
|
* @return an array of not supported functions
|
|
* @since 3.8 beta6
|
|
*/
|
|
public static ReadOnlyCollection<String> GetNotSupportedFunctionNames()
|
|
{
|
|
AnalysisToolPak inst = (AnalysisToolPak)instance;
|
|
List<String> lst = new List<String>();
|
|
foreach (KeyValuePair<String, FreeRefFunction> me in AnalysisToolPak._functionsByName)
|
|
{
|
|
FreeRefFunction func = me.Value;
|
|
if (func != null && (func is NotImplemented))
|
|
{
|
|
lst.Add(me.Key);
|
|
}
|
|
}
|
|
return lst.AsReadOnly(); //Collections.unmodifiableCollection(lst);
|
|
}
|
|
|
|
/**
|
|
* Register a ATP function in runtime.
|
|
*
|
|
* @param name the function name
|
|
* @param func the functoin to register
|
|
* @throws ArgumentException if the function is unknown or already registered.
|
|
* @since 3.8 beta6
|
|
*/
|
|
public static void RegisterFunction(String name, FreeRefFunction func)
|
|
{
|
|
AnalysisToolPak inst = (AnalysisToolPak)instance;
|
|
if (!IsATPFunction(name))
|
|
{
|
|
FunctionMetadata metaData = FunctionMetadataRegistry.GetFunctionByName(name);
|
|
if (metaData != null)
|
|
{
|
|
throw new ArgumentException(name + " is a built-in Excel function. " +
|
|
"Use FunctoinEval.RegisterFunction(String name, Function func) instead.");
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException(name + " is not a function from the Excel Analysis Toolpack.");
|
|
}
|
|
}
|
|
FreeRefFunction f = inst.FindFunction(name);
|
|
if (f != null && !(f is NotImplemented))
|
|
{
|
|
throw new ArgumentException("POI already implememts " + name +
|
|
". You cannot override POI's implementations of Excel functions");
|
|
}
|
|
if (_functionsByName.ContainsKey(name))
|
|
_functionsByName[name] = func;
|
|
else
|
|
_functionsByName.Add(name, func);
|
|
}
|
|
}
|
|
}
|