#ifndef _BASIC_UTILS_H_
#define _BASIC_UTILS_H_

#include <iostream>
#include <string>
#include <assert.h>

#ifdef WIN32
#include <float.h>
#define isnan  _isnan
#define finite _finite
#define NORM2(X, Y) sqrt((X)*(X) + (Y)*(Y))
#define strcasecmp(A, B) _stricmp(A, B)
#else
#define NORM2(X, Y) std::sqrt((X)*(X) + (Y)*(Y))
#endif

#ifndef INFINITY
#define INFINITY	1000000
#endif

#define ShowStatus(M) std::cout << std::string(M) << std::endl
#define ShowStatus1(M,A) std::cout << std::string(M) << " " << std::string(A) << std::endl

#define ShowMsg(M) std::cout << std::endl << std::string(M) << std::endl

#define ShowError(M) std::cerr << std::string(M) << std::endl
#define ShowError1(M,A) std::cerr << std::string(M) << " " << std::string(A) << std::endl

#define round(x) ( x < 0 ? -(int)(0.5-x) : (int)(x+0.5) )
#define MIN(X, Y) ( (X) <= (Y) ? (X):(Y) )
#define MAX(X, Y) ( (X) >= (Y) ? (X):(Y) )
#define SIGN(X) ((X) == 0.0 ? 0:int((X) / fabs(X)))

// Simple printing functions
#define PRINT(OS, EXP)	OS << #EXP << ": " << EXP << ", "
#define PRINTN(OS, EXP)	OS << #EXP << ": " << EXP << std::endl
#define PRINT_OPEN(OS, EXP)	OS << '[' << #EXP << ": " << EXP << ", "
#define PRINT_CLOSE(OS, EXP) OS << #EXP << ": " << EXP << ']' << std::endl

// Debug Functions
#ifdef _DEBUG

#define DBG_PRINT1(A)        { std::cerr << (A) << std::flush; }
#define DBG_PRINT2(A,B)      { std::cerr << (A) << ' ' << (B) << std::flush; }
#define DBG_PRINT3(A,B,C)    { std::cerr << (A) << ' ' << (B) << ' ' << (C) << std::flush; }
#define DBG_PRINT4(A,B,C,D)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) << std::flush; }
#define DBG_PRINT5(A,B,C,D,E)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << std::flush; }
#define DBG_PRINT6(A,B,C,D,E,F)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << ' ' << (F) << std::flush; }

#define DBG_PRINTL1(A)       { std::cerr << (A) << std::endl; }
#define DBG_PRINTL2(A,B)     { std::cerr << (A) << ' ' << (B) << std::endl; }
#define DBG_PRINTL3(A,B,C)   { std::cerr << (A) << ' ' << (B) << ' ' << (C) << std::endl; }
#define DBG_PRINTL4(A,B,C,D) { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) << std::endl; }
#define DBG_PRINTL5(A,B,C,D,E)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << std::endl; }
#define DBG_PRINTL6(A,B,C,D,E,F)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << ' ' << (F) << std::endl; }

#define DBG_MSG(A)  { std::cerr << std::endl << __FILE__ << "/" << __LINE__ \
	<< ':' << (A) << std::endl; }

#define DBG_MSG1(A,B)  { std::cerr << std::endl << __FILE__ << "/" << __LINE__ \
	<< ':' << (A) << " (" << (B) << ')' << std::endl; }

#define DBG_MSG2(A,B,C)  { std::cerr << std::endl << __FILE__ << "/" << __LINE__ \
	<< ':' << (A) << " (" << (B) << ", " << (C) << ')' << std::endl; }

#define DBG_SHOW(A) { std::cerr << std::endl << __FILE__ << "/" << __LINE__ \
	<< ':' << #A << " = " << (A) << std::endl; }
	
#define DBG_LINE  { std::cerr << std::endl << "DBG_LINE " << __LINE__ \
	<< " at " << __FILE__ << std::endl; }
	
#define ASSERT(X) \
	if(!(X)) { \
		std::cerr << "ERROR: Assertion failed \"" << #X << "\" in " __FILE__ \
			<< ':' << __LINE__ << std::endl; \
		assert(false); \
	}

#define WARNING(X, M) \
	if(X) { \
		std::cerr << "WARNING! " << M << ": \"" << #X << "\" in " __FILE__ \
			<< ':' << __LINE__ << std::endl; \
	}

	
#define ASSERT_VALID_NUM(A) ASSERT(!isnan(A) && finite(A))

#else
	#define DBG_PRINT1(A)
	#define DBG_PRINT2(A,B)
	#define DBG_PRINT3(A,B,C)
	#define DBG_PRINT4(A,B,C,D)
	#define DBG_PRINT5(A,B,C,D,E)
	#define DBG_PRINT6(A,B,C,D,E,F)
	
	#define DBG_PRINTL1(A)
	#define DBG_PRINTL2(A,B)
	#define DBG_PRINTL3(A,B,C)
	#define DBG_PRINTL4(A,B,C,D)
	#define DBG_PRINTL5(A,B,C,D,E)
	#define DBG_PRINTL6(A,B,C,D,E,F)
	
	#define DBG_LINE
	#define DBG_MSG(A) 
	#define DBG_MSG1(A,B)
	#define DBG_MSG2(A,B,C)
	#define DBG_SHOW(A) 
	#define DBG_VAL(A)
	#define ASSERT(X)
	#define WARNING(X, M)
	#define ASSERT_VALID_NUM(A)

#endif //_DEBUG


#endif //_BASIC_UTILS_H_
