/*
 * 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.
 */
/*
 * Numeric Unary Functions like abs
 * Author : Xiaoyu Ma@UC Irvine
 * 01/30/2012
 */
package org.apache.asterix.om.typecomputer.impl;

import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.AUnionType;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.IAType;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;

/**
 * Type computer for round functions. This type computer receives 1 or 2 arguments. The 1st argument is the value to
 * round, and the 2nd argument (optional) is the digit to round to. The behavior of the type computer is as follows
 * depending on the instance:
 *
 * - For integer types, the return type is int64 or the same integer type.
 * - For float type, the return type is float.
 * - For double type, the return type is double.
 * - For any type, the return type is any.
 * - For all other types, the return type is null.
 */

public class NumericRoundTypeComputer extends AbstractResultTypeComputer {
    public static final NumericRoundTypeComputer INSTANCE = new NumericRoundTypeComputer(false);
    public static final NumericRoundTypeComputer INSTANCE_ROUND_HF_TRUNC = new NumericRoundTypeComputer(true);

    private final boolean returnSameIntType;

    private NumericRoundTypeComputer(boolean returnSameIntType) {
        this.returnSameIntType = returnSameIntType;
    }

    @Override
    protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
        IAType returnType;
        ATypeTag firstArgType = strippedInputTypes[0].getTypeTag();
        ATypeTag secondArgType = strippedInputTypes.length > 1 ? strippedInputTypes[1].getTypeTag() : null;

        switch (firstArgType) {
            case TINYINT:
            case SMALLINT:
            case INTEGER:
            case BIGINT:
                returnType = returnSameIntType ? strippedInputTypes[0] : BuiltinType.AINT64;
                break;
            case FLOAT:
            case DOUBLE:
            case ANY:
                returnType = strippedInputTypes[0];
                break;
            default:
                return BuiltinType.ANULL;
        }

        // No second argument
        if (secondArgType == null) {
            return returnType;
        }

        switch (secondArgType) {
            case TINYINT:
            case SMALLINT:
            case INTEGER:
            case BIGINT:
            case ANY:
                return returnType;
            case FLOAT:
            case DOUBLE:
                return AUnionType.createNullableType(returnType);
            default:
                return BuiltinType.ANULL;
        }
    }
}
