1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.cst.math;
7   
8   import dev.metaschema.core.metapath.DynamicContext;
9   import dev.metaschema.core.metapath.IExpression;
10  import dev.metaschema.core.metapath.cst.IExpressionVisitor;
11  import dev.metaschema.core.metapath.function.FunctionUtils;
12  import dev.metaschema.core.metapath.function.impl.OperationFunctions;
13  import dev.metaschema.core.metapath.item.ISequence;
14  import dev.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
15  import dev.metaschema.core.metapath.item.atomic.IIntegerItem;
16  import dev.metaschema.core.metapath.item.atomic.INumericItem;
17  import edu.umd.cs.findbugs.annotations.NonNull;
18  import edu.umd.cs.findbugs.annotations.Nullable;
19  
20  /**
21   * An XPath 3.1
22   * <a href="https://www.w3.org/TR/xpath-31/#id-arithmetic">arithmetic
23   * expression</a> supporting integer division.
24   */
25  public class IntegerDivision
26      extends AbstractArithmeticExpression<IIntegerItem> {
27  
28    /**
29     * Create an expression that gets the whole number quotient result by dividing
30     * the dividend by the divisor.
31     *
32     * @param text
33     *          the parsed text of the expression
34     * @param dividend
35     *          the expression whose item result will be divided
36     * @param divisor
37     *          the expression whose item result will be divided by
38     */
39    public IntegerDivision(
40        @NonNull String text,
41        @NonNull IExpression dividend,
42        @NonNull IExpression divisor) {
43      super(text, dividend, divisor, IIntegerItem.class);
44    }
45  
46    @Override
47    public Class<IIntegerItem> getBaseResultType() {
48      return IIntegerItem.class;
49    }
50  
51    @Override
52    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
53      return visitor.visitIntegerDivision(this, context);
54    }
55  
56    @Override
57    protected ISequence<? extends IIntegerItem> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
58      IAnyAtomicItem leftItem = ISequence.of(getLeft().accept(dynamicContext, focus).atomize()).getFirstItem(true);
59      IAnyAtomicItem rightItem = ISequence.of(getRight().accept(dynamicContext, focus).atomize()).getFirstItem(true);
60      INumericItem dividend = leftItem == null ? null : FunctionUtils.castToNumeric(leftItem);
61      INumericItem divisor = rightItem == null ? null : FunctionUtils.castToNumeric(rightItem);
62  
63      return resultOrEmpty(dividend, divisor);
64    }
65  
66    /**
67     * Get the whole number quotient result by dividing the dividend by the divisor.
68     *
69     * @param dividend
70     *          the item to be divided
71     * @param divisor
72     *          the item to divide by
73     * @return the quotient result or an empty {@link ISequence} if either item is
74     *         {@code null}
75     */
76    @NonNull
77    protected static ISequence<? extends IIntegerItem> resultOrEmpty(@Nullable INumericItem dividend,
78        @Nullable INumericItem divisor) {
79      ISequence<? extends IIntegerItem> retval;
80      if (dividend == null || divisor == null) {
81        retval = ISequence.empty();
82      } else {
83        IIntegerItem result = divide(dividend, divisor);
84        retval = ISequence.of(result);
85      }
86      return retval;
87    }
88  
89    /**
90     * Get the whole number quotient result by dividing the dividend by the divisor.
91     *
92     * @param dividend
93     *          the item to be divided
94     * @param divisor
95     *          the item to divide by
96     * @return the quotient result
97     */
98    public static IIntegerItem divide(@NonNull INumericItem dividend, @NonNull INumericItem divisor) {
99      return OperationFunctions.opNumericIntegerDivide(dividend, divisor);
100   }
101 }