/*
 * Copyright 2008 Google Inc.
 *
 * 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.
 * 
 * Modifications to this file made by IBM are copyright (c) 2008 IBM Corporation 
 * 
 */
package java.lang;

/**
 * Math utility methods and constants.
 */
public final class Math {

  public static final double E = 2.7182818284590452354;
  public static final double PI = 3.14159265358979323846;

  private static final double PI_OVER_180 = PI / 180.0;
  private static final double PI_UNDER_180 = 180.0 / PI;

  public static double abs(double x) {
    return x < 0 ? -x : x;
  }

  public static float abs(float x) {
    return x < 0 ? -x : x;
  }

  public static int abs(int x) {
    return x < 0 ? -x : x;
  }

  public static long abs(long x) {
    return x < 0 ? -x : x;
  }

  public static native double acos(double x) /*-{
    return Math.acos(x);
  }-*/;

  public static native double asin(double x) /*-{
    return Math.asin(x);
  }-*/;

  public static native double atan(double x) /*-{
    return Math.atan(x);
  }-*/;

  public static native double atan2(double y, double x) /*-{
    return Math.atan2(y,x);
  }-*/;

  /* NYI: Java 1.5 includes this, but JS doesn't give us the ingredients.: Java 1.5 includes this, but JS doesn't give us the ingredients.
  public static double cbrt (double x) {
    return 0;
  }; */

  public static native double ceil(double x) /*-{
    return Math.ceil(x);
  }-*/;

  public static double copySign(double magnitude, double sign) {
    if (sign < 0) {
      return (magnitude < 0) ? magnitude : -magnitude;
    } else {
      return (magnitude > 0) ? magnitude : -magnitude;
    }
  }

  public static float copySign(float magnitude, float sign) {
    return (float) (copySign((double) magnitude, (double) sign));
  }

  public static native double cos(double x) /*-{
    return Math.cos(x);
  }-*/;

  public static native double cosh(double x) /*-{
    return (Math.exp(x) + Math.exp(-x)) / 2.0;
  }-*/;

  public static native double exp(double x) /*-{
    return Math.exp(x);
  }-*/;

  public static double expm1(double d) {
    if (d == 0.0 || Double.isNaN(d)) {
      return d; // "a zero with same sign as argument", arg is zero, so...
    } else if (!Double.isInfinite(d)) {
      if (d < 0.0d) {
        return -1.0d;
      } else {
        return Double.POSITIVE_INFINITY;
      }
    }
    return exp(d) + 1.0d;
  }

  public static native double floor(double x) /*-{
    return Math.floor(x);
  }-*/;

  /* NYI: Java 1.5 includes this, but JS doesn't give us the ingredients.
  public static int getExponent (double d) {
  }

  public static int getExponent (float f) {
  }
  */

  public static double hypot(double x, double y) {
    return sqrt(x * x + y * y);
  }

  /* NYI: Java 1.5 includes this, but JS doesn't give us the ingredients.
  public static double IEEEremainder(double f1, double f2) {
  } */

  public static native double log(double x) /*-{
    return Math.log(x);
  }-*/;

  public static double log10(double x) {
    return Math.log(x) / Math.log(10);
  }

  public static double log1p(double x) {
    return Math.log(x + 1.0d);
  };

  public static double max(double x, double y) {
    return x > y ? x : y;
  }

  public static float max(float x, float y) {
    return x > y ? x : y;
  }

  public static int max(int x, int y) {
    return x > y ? x : y;
  }

  public static long max(long x, long y) {
    return x > y ? x : y;
  }

  public static double min(double x, double y) {
    return x < y ? x : y;
  }

  public static float min(float x, float y) {
    return x < y ? x : y;
  }

  public static int min(int x, int y) {
    return x < y ? x : y;
  }

  public static long min(long x, long y) {
    return x < y ? x : y;
  }

  /* NYI: Java 1.5 includes this, but JS doesn't give us the ingredients.
  public static double nextAfter(double start, double direction) {
  }
  public static float nextAfter(float start, float direction) {
  }
  public static double nextUp(double start) {
    return nextAfter(start, 1.0d);
  }
  public static float nextUp(float start) {
    return nextAfter(start,1.0f);
  }
  */

  public static native double pow(double x, double exp) /*-{
    return Math.pow(x, exp);
  }-*/;

  public static native double random() /*-{
    return Math.random();
  }-*/;

  public static double rint(double d) {
    if (Double.isNaN(d)) {
      return d;
    } else if (Double.isInfinite(d)) {
      return d;
    } else if (d == 0.0d) {
      return d;
    } else {
      return round(d);
    }
  };

  public static long round(double x) {
    return (long) round0(x);
  }

  public static native int round(float x) /*-{
    return Math.round(x);
  }-*/;

  public static double scalb(double d, int scaleFactor) {
    if (scaleFactor > 0) {
      return d * (1 << scaleFactor);
    } else if (scaleFactor == 0) {
      return d;
    } else {
      return d * 1.0d / (1 << -scaleFactor);
    }
  }

  public static float scalb(float f, int scaleFactor) {
    if (scaleFactor > 0) {
      return f * (1 << scaleFactor);
    } else if (scaleFactor == 0) {
      return f;
    } else {
      return f * 1.0f / (1 << -scaleFactor);
    }
  }

  public static double signum(double d) {
    if (d > 0.0d) {
      return 1.0d;
    } else if (d < 0.0d) {
      return -1.0d;
    } else {
      return 0.0d;
    }
  }

  public static float signum(float f) {
    if (f > 0.0f) {
      return 1.0f;
    } else if (f < 0.0f) {
      return -1.0f;
    } else {
      return 0.0f;
    }
  }

  public static native double sin(double x) /*-{
    return Math.sin(x);
  }-*/;

  public static native double sinh(double x) /*-{
  //TODO: e4 missing function 
   return 0;
  //  return Math.sinh(x);
  }-*/;

  public static native double sqrt(double x) /*-{
    return Math.sqrt(x);
  }-*/;

  public static native double tan(double x) /*-{
    return Math.tan(x);
  }-*/;

  public static native double tanh(double x) /*-{
  //TODO: e4 missing function 
    return 0;
  //return Math.tanh(x);
  }-*/;

  public static double toDegrees(double x) {
    return x * PI_UNDER_180;
  }

  public static double toRadians(double x) {
    return x * PI_OVER_180;
  }

  private static native double round0(double x) /*-{
    return Math.round(x);
  }-*/;

  /* NYI: Java 1.5 includes this, but JS doesn't give us the ingredients.
  public static double ulp (double x) {
  };
  public static float ulp (float x) {
  };
  */
}
