/*
* © Copyright FOCONIS AG, 2014
*
* Licensed 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.
*
*/
package org.openntf.formula.function;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Date;
import java.util.Map;
import java.util.MissingResourceException;
import org.openntf.formula.DateTime;
import org.openntf.formula.Formatter;
import org.openntf.formula.FormulaContext;
import org.openntf.formula.Function;
import org.openntf.formula.FunctionFactory;
import org.openntf.formula.FunctionSet;
import org.openntf.formula.ValueHolder;
import org.openntf.formula.ValueHolder.DataType;
import org.openntf.formula.annotation.ParamCount;
import com.ibm.icu.util.Calendar;
/*----------------------------------------------------------------------------*/
public enum FocFunctions {
;
public static class Functions extends FunctionSet {
private static final Map<String, Function> functionSet = FunctionFactory.getFunctions(FocFunctions.class);
@Override
public Map<String, Function> getFunctions() {
return functionSet;
}
}
/*----------------------------------------------------------------------------*/
/*
* @FocDate
*/
/*----------------------------------------------------------------------------*/
private static int getRelativePart(final FormulaContext ctx, final Object o, final boolean ultimoAllowed, final boolean[] auxRes) {
if (o instanceof Number) {
int part = ((Number) o).intValue();
auxRes[0] = (part > 0);
return part;
}
if (!(o instanceof String))
throw new IllegalArgumentException("Expected Number or String, got " + o.getClass());
String s = (String) o;
if (ultimoAllowed && s.equalsIgnoreCase("ultimo")) {
auxRes[0] = true;
auxRes[1] = true;
return 1;
}
int part = ctx.getFormatter().parseNumber(s).intValue();
auxRes[0] = (part > 0 && Character.isDigit(s.charAt(0)));
return part;
}
/*----------------------------------------------------------------------------*/
@ParamCount({ 3, 4 })
public static ValueHolder atFocDate(final FormulaContext ctx, final ValueHolder[] params) {
boolean[] aux = new boolean[2];
int yearPart = getRelativePart(ctx, params[0].getObject(0), false, aux);
boolean yearIsAbs = aux[0];
int monthPart = getRelativePart(ctx, params[1].getObject(0), false, aux);
boolean monthIsAbs = aux[0];
int dayPart = getRelativePart(ctx, params[2].getObject(0), true, aux);
boolean dayIsAbs = aux[0];
boolean dayIsUltimo = aux[1];
DateTime refDate;
Formatter formatter = ctx.getFormatter();
if (params.length == 4)
refDate = formatter.getCopyOfSDTInstance(params[3].getDateTime(0));
else {
Object o = ctx.getParam("@FocDate:Bezug");
if (o instanceof DateTime)
refDate = formatter.getCopyOfSDTInstance((DateTime) o);
else
refDate = formatter.getNewInitializedSDTInstance(new Date(), false, true);
}
if (yearIsAbs || monthIsAbs || dayIsAbs) {
Calendar cal = refDate.toJavaCal();
int year = yearIsAbs ? yearPart : cal.get(Calendar.YEAR);
int month = monthIsAbs ? monthPart : cal.get(Calendar.MONTH) + 1;
int day = dayIsAbs ? dayPart : cal.get(Calendar.DAY_OF_MONTH);
refDate.setLocalDate(year, month, day);
}
if (!yearIsAbs && yearPart != 0)
refDate.adjustYear(yearPart);
if (!monthIsAbs && monthPart != 0)
refDate.adjustMonth(monthPart);
if (!dayIsAbs && dayPart != 0)
refDate.adjustDay(dayPart);
if (dayIsUltimo) {
refDate.adjustMonth(1);
refDate.adjustDay(-1);
}
refDate.setAnyTime();
return ValueHolder.valueOf(refDate);
}
/*----------------------------------------------------------------------------*/
/*
* @FocFormat
*/
/*----------------------------------------------------------------------------*/
@ParamCount(2)
public static ValueHolder atFocFormat(final FormulaContext ctx, final ValueHolder[] params) {
ValueHolder whatVH = params[0];
String how = params[1].getString(0);
if (whatVH.dataType != DataType.DATETIME)
throw new UnsupportedOperationException("@FocFormat doesn't yet support formatting objects of class "
+ whatVH.getObject(0).getClass());
if (how.equalsIgnoreCase("General Date") || how.equalsIgnoreCase("Long Date") || how.equalsIgnoreCase("Medium Date")
|| how.equalsIgnoreCase("Short Date") || how.equalsIgnoreCase("Long Time") || how.equalsIgnoreCase("Medium Time")
|| how.equalsIgnoreCase("Short Time"))
throw new UnsupportedOperationException("@FocFormat doesn't yet support date format '" + how + "'");
how = how.replace('m', 'M');
how = how.replace('n', 'm');
ValueHolder ret = ValueHolder.createValueHolder(String.class, whatVH.size);
for (int i = 0; i < whatVH.size; i++)
ret.add(ctx.getFormatter().formatDateTimeWithFormat(whatVH.getDateTime(i), how));
return ret;
}
/*----------------------------------------------------------------------------*/
/*
* @FocResolve
*/
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static ValueHolder atFocResolve(final FormulaContext ctx, final ValueHolder[] params) {
return ValueHolder.valueOf(ctx.getParam(params[0].getString(0)));
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static ValueHolder atP(final FormulaContext ctx, final ValueHolder[] params) {
return ValueHolder.valueOf(ctx.getParam(Integer.toString(params[0].getInt(0))));
}
/*----------------------------------------------------------------------------*/
@ParamCount(0)
public static ValueHolder atP1(final FormulaContext ctx) {
return p1To9(ctx, 1);
}
@ParamCount(0)
public static ValueHolder atP2(final FormulaContext ctx) {
return p1To9(ctx, 2);
}
@ParamCount(0)
public static ValueHolder atP3(final FormulaContext ctx) {
return p1To9(ctx, 3);
}
@ParamCount(0)
public static ValueHolder atP4(final FormulaContext ctx) {
return p1To9(ctx, 4);
}
@ParamCount(0)
public static ValueHolder atP5(final FormulaContext ctx) {
return p1To9(ctx, 5);
}
@ParamCount(0)
public static ValueHolder atP6(final FormulaContext ctx) {
return p1To9(ctx, 6);
}
@ParamCount(0)
public static ValueHolder atP7(final FormulaContext ctx) {
return p1To9(ctx, 7);
}
@ParamCount(0)
public static ValueHolder atP8(final FormulaContext ctx) {
return p1To9(ctx, 8);
}
@ParamCount(0)
public static ValueHolder atP9(final FormulaContext ctx) {
return p1To9(ctx, 9);
}
private static ValueHolder p1To9(final FormulaContext ctx, final int i) {
return atP(ctx, new ValueHolder[] { ValueHolder.valueOf(i) });
}
/*----------------------------------------------------------------------------*/
@ParamCount({ 2, 99 })
public static ValueHolder atCallback(final ValueHolder[] params) {
final String className = params[0].getString(0);
final String methodName = params[1].getString(0);
if (!className.startsWith("de.foconis.lib.util.cb."))
throw new IllegalArgumentException("Invalid class name");
int numPars = params.length - 2;
final Class<?>[] parTypes = new Class<?>[numPars];
final Object[] parValues = new Object[numPars];
for (int i = 0; i < numPars; i++) {
parValues[i] = params[i + 2].getObject(0);
parTypes[i] = parValues[i].getClass();
}
Object o = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null)
return null;
try {
Class<?> c = cl.loadClass(className);
Method m = c.getMethod(methodName, parTypes);
return m.invoke(c.newInstance(), parValues);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
});
if (o == null)
throw new MissingResourceException("Can't call callback method", className, methodName);
return ValueHolder.valueOf(o);
}
/*----------------------------------------------------------------------------*/
}