/*
 * Jakelib2 - General purpose C++ library
 * Copyright (C) 2001 Florian Wolff  (florian@donuz.de)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: Math.h,v 1.16 2003/08/26 19:50:16 florian Exp $
 */

#ifndef INCLUDE_JAKELIB2_LANG_MATH_H
# define INCLUDE_JAKELIB2_LANG_MATH_H

#if defined(JAKELIB_WIN32API)
# undef max
# undef min
#endif

#ifdef HAVE_MATH_H
# include <math.h>
#endif

namespace jakelib {
  namespace lang {

    /**
     *
     * @class Math
     * @version $Id: Math.h,v 1.16 2003/08/26 19:50:16 florian Exp $
     * @author Florian 'Overflo' Wolff (florian@donuz.de)
     */
    class Math : public Object
      {
      public:
	/**
	 * @brief The mathematical constant <em>e</em>.
	 * Used in natural log and exp.
	 */
	static const double E;

	/**
	 * @brief The mathematical constant <em>pi</em>.
	 * This is the ratio of a circle's diameter to its circumference.
	 */
	static const double PI;

	/**
	 * @brief The trigonometric function <em>cos</em>.
	 * @param a the angle (in radians).
	 * @return cos(a).
	 */
	static double cos(double a) { return ::cos(a); }

	/**
	 * @brief The trigonometric function <em>sin</em>.
	 * @param a the angle (in radians).
	 * @return sin(a).
	 */
	static double sin(double a) { return ::sin(a); }

	/**
	 * @brief The trigonometric function <em>tan</em>.
	 * @param a the angle (in radians).
	 * @return tan(a).
	 */
	static double tan(double a) { return ::tan(a); }

	/**
	 * @brief The trigonometric function <em>arccos</em>.
	 * The range of angles you will get are from 0 to pi radians (0 to 180 degrees).
	 * @param a the cos to turn back into an angle.
	 * @return arccos(a).
	 */
	static double acos(double a) { return ::acos(a); }

	/**
	 * @brief The trigonometric function <em>arcsin</em>.
	 * The range of angles you will get are from -pi/2 to pi/2 radians (-90 to 90 degrees)
	 * @param a the sin to turn back into an angle.
	 * @return arcsin(a).
	 */
	static double asin(double a) { return ::asin(a); }

	/**
	 * @brief The trigonometric function <em>arctan</em>.
	 * The range of angles you will get are from -pi/2 to pi/2 radians (-90 to 90 degrees)
	 * @param a the sin to turn back into an angle.
	 * @return arcsin(a).
	 */
	static double atan(double a) { return ::atan(a); }

	/**
	 * @brief A special version of the trigonometric function <em>arctan</em>.
	 * Given a position (x,y), this function will give you the angle of
	 * that position.
	 * The range of angles you will get are from -pi to pi radians (-180 to 180 degrees),
	 * the whole spectrum of angles.  That is what makes this function so
	 * much more useful than the other <code>atan()</code>.
	 * @param y the y position
	 * @param x the x position
	 * @return arctan2(y, x).
	 */
	static double atan2(double y, double x) { return ::atan2(y, x); }

	/**
	 * @brief Take <em>e</em><sup>a</sup>.  The opposite of <code>log()</code>.
	 * @param a the number to raise to the power.
	 * @return the number raised to the power of <em>e</em>.
	 */
	static double exp(double a) { return ::exp(a); }

	/**
	 * @brief Take ln(a) (the natural log).  The opposite of <code>exp()</code>.
	 * Note that the way to get log<sub>b</sub>(a) is to do this:
	 * <code>log(a) / log(b)</code>.
	 * @param a the number to take the natural log of.
	 * @return the natural log of <code>a</code>.
	 */
	static double log(double a) { return ::log(a); }

	/**
	 * @brief Take a square root.
	 * For other roots, to pow(a,1/rootNumber).
	 * @param a the numeric argument
	 * @return the square root of the argument.
	 */
	static double sqrt(double a) { return ::sqrt(a); }

	/**
	 * @brief Take a number to a power.
	 * @param a the number to raise.
	 * @param b the power to raise it to.
	 * @return a<sup>b</sup>.
	 */
	static double pow(double a, double b) { return ::pow(a, b); }

	/**
	 * @brief Take the nearest integer that is that is greater than or equal to the
	 * argument.
	 * @param a the value to act upon.
	 * @return the nearest integer >= <code>a</code>.
	 */
	static double ceil(double a) { return ::ceil(a); }

	/**
	 * @brief Take the nearest integer that is that is less than or equal to the
	 * argument.
	 * @param a the value to act upon.
	 * @return the nearest integer <= <code>a</code>.
	 */
	static double floor(double a) { return ::floor(a); }

	/**
	 * @brief Take the nearest integer to the argument.  If it is exactly between
	 * two integers, the even integer is taken.
	 * @param a the value to act upon.
	 * @return the nearest integer to <code>a</code>.
	 */
	//static double rint(double a) { return ::rint(a); }

	/**
	 * @brief Take the nearest integer to the argument.  If it is exactly between
	 * two integers, then the lower of the two (-10 lower than -9) is taken.
	 * If the argument is less than \c Integer.MIN_VALUE or negative infinity,
	 * \c Integer.MIN_VALUE will be returned.  If the argument is greater than
	 * \c Integer.MAX_VALUE, \c Integer.MAX_VALUE will be returned.
	 *
	 * @param a the argument to round.
	 * @return the nearest integer to the argument.
	 */
	static int round(float a) { return (int) ::floor (a + 0.5f); }

	/**
	 * @brief Take the nearest integer to the argument.  If it is exactly between
	 * two integers, then the lower of the two (-10 lower than -9) is taken.
	 * If the argument is less than \c Long.MIN_VALUE or negative infinity,
	 * \c Long.MIN_VALUE will be returned.  If the argument is greater than
	 * \c Long.MAX_VALUE, \c Long.MAX_VALUE will be returned.
	 *
	 * @param a the argument to round.
	 * @return the nearest integer to the argument.
	 */
	static jlong round(double a) { return (long) floor (a + 0.5F); }

	/**
	 * @brief Convert from degrees to radians.
	 * The formula for this is radians = degrees * (pi/180).
	 * @param degrees an angle in degrees
	 * @return the angle in radians
	 */
	static double toRadians(double degrees);

	/**
	 * @brief Convert from radians to degrees.
	 * The formula for this is degrees = radians * (180/pi).
	 * @param rads an angle in radians
	 * @return the angle in degrees
	 */
	static double toDegrees(double rads);

	/**
	 * @brief Returns the absolute (non-negative) value
         * of the given argument.
	 */
	static double abs(double a) { return (a < 0.0 ? -a : a); }

	/**
	 * @brief Get the floating point remainder on two numbers,
	 * which really does the following:
	 * <P>
	 *
	 * <OL>
	 *   <LI>
	 *       Takes x/y and finds the nearest integer <em>n</em> to the
	 *       quotient.  (Uses the <code>rint()</code> function to do this.
	 *   </LI>
	 *   <LI>
	 *       Takes x - y*<em>n</em>.
	 *   </LI>
	 *   <LI>
	 *       If x = y*n, then the result is 0 if x is positive and -0 if x
	 *       is negative.
	 *   </LI>
	 * </OL>
	 *
	 * @param x the dividend (the top half)
	 * @param y the divisor (the bottom half)
	 * @return the IEEE 754-defined floating point remainder of x/y.
	 */
	//static double IEEEremainder(double x, double y);

	/**
	 * @brief Returns the greater of the two given \c jlong values.
	 */
	static inline jlong max(jlong a, jlong b) { return (a > b ? a : b); };

	/**
	 * @brief Returns the smaller of the two given \c jlong values.
	 */
	static inline jlong min(jlong a, jlong b) { return (a < b ? a : b); };

	/**
	 * @brief Returns the greater of the two given \c jint values.
	 */
	static inline jint max(jint a, jint b) { return (a > b ? a : b); };

	/**
	 * @brief Returns the smaller of the two given \c jint values.
	 */
	static inline jint min(jint a, jint b) { return (a < b ? a : b); };

	/**
	 * @brief Returns the greater of the two given \c jdouble values.
	 */
	static inline jdouble max(jdouble a, jdouble b) { return (a > b ? a : b); };

	/**
	 * @brief Returns the smaller of the two given \c jdouble values.
	 */
	static inline jdouble min(jdouble a, jdouble b) { return (a < b ? a : b); };

	JAKELIB_DECLARE_CLASS(Math);
      };
  }
}
#endif

