// ================================================================
// $Id: basic.h,v 1.5 2003/10/30 16:36:35 havran Exp $
//
// basic.h
//     Basic definitions
//
// Class: CLimits
//
// Licence and usage conditions in November 2003:
// This file can be used and modified only with written permission of
// Vlastimil Havran, Pohodli 27, 57001 Litomysl, the Czech Republic.
// This library is granted to be used by Polina Kondratieva within
// her MPI HIWI job working on BRDFLIB library. The usage condition
// may change in the next version of the library. At the moment,
// the library development is supported by Max-Planck-Institut for
// Informatik, Stuhlsatzenhausweg 85, 66123 Saarbruecken Germany
// See WWW: http://www.mpi-sb.mpg.de
// REPLACEMENT_STRING
//
// Initial coding by Vlastimil Havran, 2000.
//
// Given to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.

#ifndef __BASIC_H__
#define __BASIC_H__

// BRDFLIB headers
#include "configh.h"

// Standard headers
#include <cmath>
#ifdef __UNIX__
#include <values.h>
#endif // __UNIX__
#include <string>

#include <stdlib.h>



__BEGIN_BRDFLIB_HEADER


// The definition of some constants
#ifndef M_PI
#define M_PI        3.14159265358979323846f
#endif
#ifndef M_PI_2
#define M_PI_2	    1.57079632679489661923f
#endif
#ifndef M_PI_4
#define M_PI_4	    0.78539816339744830962f
#endif
#ifndef M_1_PI
#define M_1_PI	    0.31830988618379067154f
#endif
#ifndef M_2_PI
#define M_2_PI	    0.63661977236758134308f
#endif

#ifndef MAXFLOAT
#define MAXFLOAT    ((float)3.40282347e+38)
#endif

#ifndef RAND_MULT
#define RAND_MULT  1.0 / (RAND_MAX + 1.0)
#endif

// some compilers do not define the bool yet, but it was declared by ANSI
#if defined (__GNUC__) || (_BOOL)
//#error "HAS BOOL defined"
#define HAS_BOOL
#endif

#if  (__WATCOMC__ > 1060)
//#error "Watcom HAS BOOL defined"
#define HAS_BOOL
#endif

#if defined(_MSC_VER)
// Microsoft compiler
#define HAS_BOOL
#endif

#if defined(__INTEL_COMPILER)
// Intel compiler for Linux/Windows
#define HAS_BOOL
#endif

#ifdef sgi
#define OUT_BIN_MODE ios::out
#define IN_BIN_MODE ios::in
#define APPEND_BIN_MODE ios::app
#endif // sgi

#ifdef __WATCOMC__
#define OUT_BIN_MODE ios::out | ios::binary
#define IN_BIN_MODE ios::in | ios::binary
#define APPEND_BIN_MODE  ios::out | ios::app | ios::binary
#endif

#if defined(_MSC_VER)
// Microsoft settings
#define OUT_BIN_MODE ios::out | ios::binary
#define IN_BIN_MODE ios::in | ios::binary
#define APPEND_BIN_MODE ios::out | ios::app | ios::binary
#endif

#ifndef OUT_BIN_MODE
// otherwise, use standard definitions
#define OUT_BIN_MODE ios::out | ios::binary
#define IN_BIN_MODE ios::in | ios::binary
#define APPEND_BIN_MODE ios::out | ios::app | ios::binary
#endif // _OUT_BIN_MODE

#ifndef DSTRSTREAM_H
#define DSTRSTREAM_H <strstream>
#endif

#ifndef HAS_BOOL
//enum bool {
//  false = 0,
//  true
//};
#define bool int
#define false 0
#define true  1

#endif // HAS_BOOL


#ifndef NULL
#define NULL (void *)0
#endif // NULL

#define WTINY 1e-06			// added by PK
#define WTINY1G 1.000001    // greater than 1.0 by WTINY
#define WTINY1L 0.999999    // lesser than 1.0 by WTINY

// -------------------------------------------------------------------
// Limits.
//  This class encapsulates all the concessions to floating-point
//  error made by ray tracers.
// -------------------------------------------------------------------
class CLimits
{
public:
  // This is a "small" number.  Less than this number is assumed to
  // be 0, when such things matter. The default value is 1e-6
  static float Small;
  static float Large;
};

// -------------------------------------------------------------------
// Support functions
// -------------------------------------------------------------------

template<class T>
T
sqr(T a)
{
  return (a) * (a);
}

inline int
signum(float a, float epsilon = CLimits::Small) 
{
  if (a > epsilon)
    return 1; 
  else
    if (a < -epsilon)
      return -1; 
  return 0;
}

// -------------------------------------------------------------------
// Indents to a given stream by the number of spaces specified.
// This routine is located in main.cpp, for lack of a better place.
// -------------------------------------------------------------------
void
indent(ostream &app, int ind);

// ------------------------------------------------------------------
// Abs
//   Returns absolute value of a given type for floating point values
// ------------------------------------------------------------------
template<class T>
T
Abs(const T &x)
{
  return (x < 0) ? -x : x; 
}

// -------------------------------------------------------------------
// RandomValue
//	Returns a random floating-point value between the two 
//	values. The range is [a; b).
// -------------------------------------------------------------------
inline float
RandomValue(float a, float b)
{
  float range = Abs(a - b);
#ifdef __UNIX__
  return drand48() * range + ((a < b) ? a : b);
#else // __UNIX__
  return ((float)rand() * RAND_MULT) * range + ((a < b) ? a : b);
#endif // __UNIX__
}

// -------------------------------------------------------------------
// RandomValue in the range [0; 1)
// -------------------------------------------------------------------
inline float
RandomValue()
{
#ifdef __UNIX__
  return drand48();
#else // __UNIX__
  // 05.03.04 P.K.
  // Here is a mistake: (RAND_MAX +1) is considered as 32-bit int
  // => if RAND_MAX = 2^31-1 is the maximum long value
  // => RAND_MAX + 1 < 0 (32th bit is the sigh bit!)
  //const double MULT = 1.0 / (RAND_MAX + 1);
  return max(rand(),1) * RAND_MULT;
#endif // __UNIX__
}

// ---------------------------------------------------------
// SetRandomSeed
//      Sets the random seed for standard random generator
// ---------------------------------------------------------
inline void
SetRandomSeed(int seed = 1)
{
  srand(seed);
#ifdef __UNIX__
  srand48(seed);
#endif // __UNIX__
}



// ---------------------------------------------------------
// Swaps two values.
// ---------------------------------------------------------
template<class T>
inline void 
Swap(T &x, T &y)
{
  T temp = x;
  x = y;
  y = temp;
}

// ---------------------------------------------------------
// InRange
//	Returns nonzero if min <= candidate <= max.
// ---------------------------------------------------------
template<class T>
inline int 
InRange(T min, T max, T candidate)
{
  return (candidate >= min) && (candidate <= max);
}

// ---------------------------------------------------------
// Max
//   Returns maximum of two values
// ---------------------------------------------------------
template<class T>
inline const T&
Max(const T &x, const T &y)
{
  return (x < y) ? y : x;
}

// ---------------------------------------------------------
// Min
//   Returns minimum of two values
// ---------------------------------------------------------
template<class T>
inline const T&
Min(const T &x, const T &y)
{
  return (x > y) ? y : x;
}

// ---------------------------------------------------------
// EpsilonEqual(x,y)
//   Returns if two values are equal or not (by epsilon)
// ---------------------------------------------------------
inline int
EpsilonEqual(const float &x, const float &y)
{
  return Abs(x-y) < CLimits::Small;
}

// ---------------------------------------------------------
// EpsilonEqual(x)
//   Returns if a value is zero (+/- epsilon)
// ---------------------------------------------------------
inline int
EpsilonEqual(const float &x)
{
  return Abs(x) < CLimits::Small;
}

// ---------------------------------------------------------
// IsNumber(x)
//   Returns true if a value is number (false if its "nan")
// ---------------------------------------------------------
template<class T>
inline bool
IsNumber(const T &x)
{
  return (x == x);
}

// ---------------------------------------------------------
// IsValid3(x)
//   Returns true if all 3 given values are numbers (false if 
//   any of them is "nan")
// ---------------------------------------------------------
template<class T>
inline bool
IsValid3(const T &x, const T &y, const T &z)
{
  return (x == x) && (y == y) && (z == z);
}

// ---------------------------------------------------------
// AssignPointer(destination,source)
//   Assigns source pointer to destination pointer. If 
//   destination pointer is not NULL it is safely deleted. 
//   Safety here stands for the fact, that if object behind 
//   the destination pointer is accessed in the same time it
//   is deleted, error can occur. For safety deletion
//   temporary pointer is used.
// ---------------------------------------------------------
template<class T>
inline void 
AssignPointer(T &dest, T &source)
{
  if (dest != NULL)
  {
    T temp = dest;
	dest = source;
	delete temp;
  }
  else
  {
    dest = source;
  }
}

// ---------------------------------------------------------
// EpsilonEqual(x,y,epsilon)
//   Returns if two values are equal or not by a given epsilon
// ---------------------------------------------------------
inline int
EpsilonEqual(const float &x, const float &y, const float &epsilon)
{
  return Abs(x-y) < epsilon;
}

// ---------------------------------------------------------------------
// prefix filename by a given directory name e.g. "aa.out","ref" makes
// "ref/aa.out", but "stats/aa.out","ref" makes "stats/ref/aa.out"
// ---------------------------------------------------------------------
void
PrefixNameByDir(const string &filename, const string &dirname,
		string &outputName);

// ---------------------------------------------------------------------
// prefix filename extension by a given extPrefix
// for example the filename "data/tetra.rgb" and extPrefix 0102 makes
// the output filename "data/tetra0102.rgb"
// If no extension is found, then extPrefix is simply appended to the
// file name, e.g. for "balls" makes "balls0102"
// ---------------------------------------------------------------------
void
PrefixExtensionByName(const string &filename, const string &extPrefix,
		      string &outputName);

// ---------------------------------------------------------------------
// adding/replacing the extension of the filename to outputName
// filename .. filename to be changed  .. "tetra.rgb"
// newExtension .. newExtension added/replaced  ("vis", "dbg", "rgb" etc.)
// "tetra.rgb" makes "tetra.dbg", and "aaaaa/bbb" makes "aaaaa/bbb.dbg"
// ---------------------------------------------------------------------
void
ChangeFilenameExtension(const string &filename, const string &newExt,
			string &outputName);


// Skip all the rows in a text file starting from the current character,
// when the current character is a 'mark'. All the following lines starting
// with the 'mark' character are also skipped.
void
EatComments(istream &inpf, const char mark);

// Skip all the whitespaces in the input stream = it means
// the characters ' ','\t','\n','\f','\r','\b'
void
EatWhitespace(istream &inpf);

// Find the first line from now on that starts with a given keyword,
// read the keyword and do not read other characters
// Returns 'false' on success (line found), 'true' if not found.
bool
FindLineWithKeyword(istream &inpf, const string &keyword);

// Converts all the possible characters in the string to lowercase.
void
ToLowerCase(string &str);

// VERSION OF THE LIBRARY HERE
extern string STRINGVERSION;

#ifndef MAX_SHININESS
#define MAX_SHININESS    ((float)99999)
#endif
#ifndef MAX_IOR
#define MAX_IOR    ((float)10)
#define MAX_EXTCOEF    ((float)1000)
#endif

__END_BRDFLIB_HEADER

#endif // __BASIC_H__

