/*
 * 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.
 */
package org.apache.commons.jexl.util;

/**
 *  Coercion utilities for the JSTL EL-like coercion.
 *
 *  @since 1.0
 *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
 */
public class Coercion {

    /**
     * Coerce to a Boolean.
     *
     * @param val Object to be coerced.
     * @return The Boolean coerced value, or null if none possible.
     */
    public static Boolean coerceBoolean(Object val) {
        if (val == null) {
            return Boolean.FALSE;
        } else if (val instanceof Boolean) {
            return (Boolean) val;
        } else if (val instanceof String) {
            return Boolean.valueOf((String) val);
        }
        return null;
    }

    /**
     * Coerce to a Integer.
     *
     * @param val Object to be coerced.
     * @return The Integer coerced value.
     * @throws Exception If Integer coercion fails.
     */
    public static Integer coerceInteger(Object val)
    throws Exception {
        if (val == null) {
            return new Integer(0);
        } else if (val instanceof String) {
            if ("".equals(val)) {
                return new Integer(0);
            }
            return Integer.valueOf((String) val);
        } else if (val instanceof Character) {
            return new Integer(((Character) val).charValue());
        } else if (val instanceof Boolean) {
            throw new Exception("Boolean->Integer coercion exception");
        } else if (val instanceof Number) {
            return new Integer(((Number) val).intValue());
        }

        throw new Exception("Integer coercion exception");
    }

    /**
     * Coerce to a Long.
     *
     * @param val Object to be coerced.
     * @return The Long coerced value.
     * @throws Exception If Long coercion fails.
     */
    public static Long coerceLong(Object val)
    throws Exception {
        if (val == null) {
            return new Long(0);
        } else if (val instanceof String) {
            if ("".equals(val)) {
                return new Long(0);
            }
            return Long.valueOf((String) val);
        } else if (val instanceof Character) {
            return new Long(((Character) val).charValue());
        } else if (val instanceof Boolean) {
            throw new Exception("Boolean->Long coercion exception");
        } else if (val instanceof Number) {
            return new Long(((Number) val).longValue());
        }

        throw new Exception("Long coercion exception");
    }

    /**
     * Coerce to a Double.
     *
     * @param val Object to be coerced.
     * @return The Double coerced value.
     * @throws Exception If Double coercion fails.
     */
    public static Double coerceDouble(Object val)
    throws Exception {
        if (val == null) {
            return new Double(0);
        } else if (val instanceof String) {
            if ("".equals(val)) {
                return new Double(0);
            }

            /*
             * the spec seems to be iffy about this.  Going to give it a wack
             *  anyway
             */

            return new Double((String) val);
        } else if (val instanceof Character) {
            int i = ((Character) val).charValue();

            return new Double(Double.parseDouble(String.valueOf(i)));
        } else if (val instanceof Boolean) {
            throw new Exception("Boolean->Double coercion exception");
        } else if (val instanceof Double) {
            return (Double) val;
        } else if (val instanceof Number) {
            //The below construct is used rather than ((Number)val).doubleValue() to ensure
            //equality between comparint new Double( 6.4 / 3 ) and the jexl expression of 6.4 / 3
            return new Double(Double.parseDouble(String.valueOf(val)));
        }

        throw new Exception("Double coercion exception");
    }

    /**
     * Is Object a floating point number.
     *
     * @param o Object to be analyzed.
     * @return true if it is a Float or a Double.
     */
    public static boolean isFloatingPoint(final Object o) {
        return o instanceof Float || o instanceof Double;
    }

    /**
     * Is Object a whole number.
     *
     * @param o Object to be analyzed.
     * @return true if Integer, Long, Byte, Short or Character.
     */
    public static boolean isNumberable(final Object o) {
        return o instanceof Integer
            || o instanceof Long
            || o instanceof Byte
            || o instanceof Short
            || o instanceof Character;
    }

}

@@ -2396,32 +2396,37 @@
 ption%22);%0A    %7D%0A%0A
+    %0A
     /**%0A     * C
@@ -2436,20 +2436,43 @@
 ce to a 
+long (not a java.lang.
 Long
+)
 .%0A     *
@@ -2555,57 +2555,8 @@
 ue.%0A
-     * @throws Exception If Long coercion fails.%0A
     
@@ -2577,17 +2577,17 @@
  static 
-L
+l
 ong coer
@@ -2588,17 +2588,17 @@
 g coerce
-L
+l
 ong(Obje
@@ -2604,37 +2604,16 @@
 ect val)
-%0A    throws Exception
  %7B%0A     
@@ -2649,35 +2649,25 @@
      return 
-new Long(0)
+0
 ;%0A        %7D 
@@ -2761,19 +2761,9 @@
 urn 
-new Long(0)
+0
 ;%0A  
@@ -2798,23 +2798,25 @@
 rn Long.
-valueOf
+parseLong
 ((String
@@ -2889,25 +2889,16 @@
  return 
-new Long(
 ((Charac
@@ -2910,33 +2910,32 @@
 val).charValue()
-)
 ;%0A        %7D else
@@ -2979,32 +2979,44 @@
       throw new 
+NumberFormat
 Exception(%22Boole
@@ -3113,17 +3113,8 @@
 urn 
-new Long(
 ((Nu
@@ -3131,25 +3131,24 @@
 .longValue()
-)
 ;%0A        %7D%0A
@@ -3158,32 +3158,44 @@
       throw new 
+NumberFormat
 Exception(%22Long 
@@ -3204,33 +3204,275 @@
 ercion exception
-%22
+ for '%22 + val + %22'%22);%0A    %7D%0A%0A    /**%0A     * Coerce to a Long.%0A     *%0A     * @param val Object to be coerced.%0A     * @return The Long coerced value.%0A     */%0A    public static Long coerceLong(Object val) %7B%0A        return new Long(coercelong(val)
 );%0A    %7D%0A%0A    /*

add coercelong method so primitive values can be used and less objects are created