/******************************** LICENSE ********************************

 Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)

 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.

 ******************************** LICENSE ********************************/


/*! \file magics.h

  \brief This file contains all global definition for the MagPlus library.
  \author Meteorological Visualisation Section, ECMWF
  \license Apache License 2.0

  Started: January 2004

  Changes:
  
*/
#ifndef magicsplusplus_H
#define magicsplusplus_H

#include <magics_config.h>
#if defined(MAGICS_AIX_XLC)
 #include <unistd.h>           // for AIX
#endif
#include <climits>

// do the export restriction only if NOT for Metview
#ifndef MAGICS_METVIEW

#ifdef WIN32
  #define MAGICS_IMPORT __declspec(dllimport)
  #define MAGICS_EXPORT __declspec(dllexport)
  #define MAGICS_DLLLOCAL
  #define MAGICS_DLLPUBLIC
#endif

#if (__GNUC__ - 0 > 3) || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 > 2)
  #define MAGICS_GCC 4
  #define MAGICS_NO_EXPORT __attribute__ ((visibility("hidden")))
  #define MAGICS_EXPORT    __attribute__ ((visibility("default")))
  #define MAGICS_IMPORT    __attribute__ ((visibility("default")))
  #define MAGICS_DLLLOCAL  __attribute__ ((visibility("hidden")))
  #define MAGICS_DLLPUBLIC __attribute__ ((visibility("default")))
#else
  #define MAGICS_GCC 3
  #define MAGICS_NO_EXPORT
  #define MAGICS_IMPORT
  #define MAGICS_EXPORT
  #define MAGICS_DLLLOCAL
  #define MAGICS_DLLPUBLIC
#endif

#else
  #define MAGICS_GCC 3
  #define MAGICS_NO_EXPORT
  #define MAGICS_IMPORT
  #define MAGICS_EXPORT
  #define MAGICS_DLLLOCAL
  #define MAGICS_DLLPUBLIC
#endif

#ifdef __GNUC__
#define MAGICS_DEPRECATED __attribute__((deprecated))
#else
#define MAGICS_DEPRECATED
#endif

#include <iostream>
#include <cstring>
#include <string>
#include <sstream>
#include <fstream>

using std::string;
using std::ostream;
using std::endl;
using std::ends;
using std::cout;
using std::cerr;
using std::ostringstream;
using std::ofstream;
using std::ifstream;

#include <list>
#include <vector>
#include <stack>
#include <memory>
#include <map>
#include <set>
#include <iterator>
#include <numeric>
//#include <cfloat>
#include <algorithm>

using std::allocator;
using std::vector;
using std::pair;
using std::list;
using std::map;
using std::set;
using std::auto_ptr;

#include <exception>
using std::exception;

#include <cassert>
#include <cmath>

#if defined(MAGICS_AIX_XLC) || defined(MAGICS_WINDOWS_CYGWIN) || defined(MAGICS_MAC_GCC)
inline double exp10(const double r) { return exp(r*2.302585093);} // exp(r*ln(10))
#endif

/*! \namespace magics

 The <I>magics</I> namespace encapsulates all elements of Magics++.
 The namespace prevents confusions with other libraries or 
 older versions of Magics.
 
 You can use this namespace by simple prefix all Magics elements
 by <I>magics::</I> or by typing <I>using namespace magics;</I>
 before any calls in your program.

*/
namespace magics {


//const double double_MIN = DBL_MIN;


template <class P>
class magvector : public std::vector<P>
{
public:
    magvector() {}
    magvector(const std::vector<P>& list) :  std::vector<P>(list) {}
    virtual ~magvector() {} 
    virtual MAGICS_NO_EXPORT void print(ostream& out) const
    { 
        if ( this->size() < 10 ) {
            out << "Vector[";
            string sep = "";
	    const unsigned int si = this->size();
            for (unsigned int i = 0; i < si; i++) {
                out << sep << (*this)[i];
                sep = ", ";
            }
            out << "]";
        }
        else {
            unsigned int nb = this->size();
            out << "Vector[" << (*this)[0] << ", " << (*this)[1] << ", " << (*this)[2];
            out << "...." << (*this)[nb-3] << ", " << (*this)[nb-2]  << ", " << (*this)[nb-1];
            out << "(" << nb << " elements)]";
        }
    }
// -- Friends
	friend MAGICS_NO_EXPORT ostream& operator<<(ostream& s,const magvector<P>& p)
		{ p.print(s); return s; }
};


typedef magvector<string>	stringarray;
typedef magvector<int>		intarray;
typedef magvector<double>	doublearray;
typedef magvector<double>	floatarray;

enum LineStyle { M_SOLID , M_DASH , M_DOT , M_CHAIN_DASH , M_CHAIN_DOT };
enum Hemisphere { NORTH , SOUTH };
enum Justification { MLEFT, MCENTRE, MRIGHT };
enum VerticalAlign { MNORMAL, MTOP, MCAP, MHALF, MBASE, MBOTTOM };
//enum VerticalAlign { MBASE, MTOP, MHALF, MBOTTOM };   // if change you need to change also share/magics/PostScriptMacros2.dat
enum Shading { M_SH_NONE, M_SH_SOLID, M_SH_HATCH, M_SH_DOT };
enum ArrowPosition { M_TAIL, M_CENTRE };
enum DisplayType { ABSOLUTE, INLINE, BLOCK, NONE, HIDDEN };
enum ListPolicy { M_LASTONE, M_CYCLE };
enum GraphicsFormat {PS, EPS, PDF, SVG, KML, PNG, X, CPS, CSVG, GIF, AGIF, JPG, QT};
enum AxisAutomaticSetting {m_off, m_both, m_min_only, m_max_only};

/*
inline MAGICS_NO_EXPORT string getOutputString()
{
	const string outputs = MAGICS_OUTPUTS;
	return outputs;
}
*/
const double epsilon = 1.25e-7;

template<class T>
inline MAGICS_NO_EXPORT T abs(const T a) { return (a < 0) ? -a : a; }

#ifndef PI
const double PI = atan(1.)*4.;
#endif

inline MAGICS_NO_EXPORT double RAD(const double r) { return r*PI/180.;}
inline MAGICS_NO_EXPORT double DEG(const double d) { return d*180./PI;}
inline MAGICS_NO_EXPORT bool zero(const double v) { return abs(v) < epsilon; }
inline MAGICS_NO_EXPORT bool same(const double a, const double b) { return zero(a-b); }

//! Global function to read env variables
inline MAGICS_NO_EXPORT string getEnvVariable(const string var)
{
	const char* va = var.c_str();
	const char* ww = getenv(va);
	if(ww) return string(ww);
	if(!strcmp(va,"MAGPLUS_HOME")) return string(MAGICS_INSTALL_PATH);
	return "";
}

//! Global function to return the Magics++ version for ID line
/*! comes from magics_config.h !!! */
inline string getMagicsVersionString()
{
	const string magics  = MAGICS_NAME;
	string version = MAGICS_VERSION;
	if(sizeof(long)==8) version=MAGICS_VERSION+string(" (64 bit)");
	return magics+string(" ")+version;
}

// inline MAGICS_NO_EXPORT int upper_case(const int c) { return toupper(c);}
inline MAGICS_NO_EXPORT char lower_case(const char c) { return tolower(c);}

//! Make an lowercase copy of s:
inline MAGICS_NO_EXPORT string lowerCase(const string& s)
{
	std::string out;
	std::string::const_iterator se = s.end();
	for ( string::const_iterator l = s.begin(); l != se; ++l)
	{
		char ii = tolower(*l);
		out.push_back(ii);
	}
	return out;
}

/*!
  \brief compares two strings
*/
inline MAGICS_NO_EXPORT bool magCompare(const string &s1, const string &s2)
{
	if(s1.size() != s2.size()) return false;
#ifndef MAGICS_WINDOWS_CYGWIN
	return !( strcasecmp(s1.c_str(),s2.c_str()) );
#endif
}

/*!
  \brief returns the biggest integer inside a double
*/
inline double maground(double x)
{
	return floor(x + 0.5);
}

inline double tonumber(const string& str) 
{
	double r;
	std::stringstream ss(str);
	ss >> r;
	return r;
}

template <class T>
inline string tostring(const T& in) 
{
	std::ostringstream out;
	out << in;
	return out.str();
}


/*!
  \brief checks if file readable or not
*/
/*
inline MAGICS_NO_EXPORT bool fileReadable(const string &strFile)
{
    FILE *fp = fopen (strFile.c_str(), "r");
    if (fp != NULL)
    {
        fclose (fp);
        return true;
    }
    else
    {
        return false;
    }
}
*/

#define MAGPLUS_PATH_TO_SHARE_ "/share/magics/"
#define MAGPLUS_LINK_  "http://www.ecmwf.int/publications/manuals/magics"
#define MAGPLUS_PATH_TO_PS_FONTS_ POSTSCRIPT_FONT_PATH;
}
#endif
