/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* librvngabw
 * Version: MPL 2.0 / LGPLv2.1+
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Major Contributor(s):
 * Copyright (C) 2014 osnola
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms
 * of the GNU Lesser General Public License Version 2.1 or later
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
 * applicable instead of those above.
 *
 * For further information visit http://libwpd.sourceforge.net
 */

#ifndef __FILTERINTERNAL_HXX__
#define __FILTERINTERNAL_HXX__

#include <string.h> // for strcmp

#include <memory>
#include <vector>

#include <librevenge/librevenge.h>

#ifdef HAVE_CONFIG_H
#  include <config.h>
#  ifdef HAVE_STDINT_H
#    include <stdint.h>
#  endif
#  ifdef HAVE_INTTYPES_H
#    include <inttypes.h>
#  endif
#endif

#if defined(_MSC_VER) || defined(__DJGPP__)
typedef unsigned int uint32_t;
#elif !defined(HAVE_CONFIG_H)
// assume that the headers are there inside LibreOffice build when no HAVE_CONFIG_H is defined
#    include <stdint.h>
#    include <inttypes.h>
#endif

#if defined(HAVE_FUNC_ATTRIBUTE_FORMAT)
#  define RVNGABW_ATTRIBUTE_PRINTF(fmt, arg) __attribute__((format(printf, fmt, arg)))
#else
#  define RVNGABW_ATTRIBUTE_PRINTF(fmt, arg)
#endif

#ifdef DEBUG
#include <stdio.h>
namespace librvngabw
{
void printDebugMsg(const char *format, ...) RVNGABW_ATTRIBUTE_PRINTF(1, 2);
}
#define RVNGABW_DEBUG_MSG(M) librvngabw::printDebugMsg M
#else
#define RVNGABW_DEBUG_MSG(M)
#endif

#define RVNGABW_N_ELEMENTS(m) sizeof(m)/sizeof(m[0])

namespace librvngabw
{

class DocumentElement;

// Various exceptions:
class GenericException
{
};

//! converts a double in string
librevenge::RVNGString doubleToString(const double value);
//! tries to retrieve/convert a property value in inch
bool getInchValue(librevenge::RVNGProperty const &prop, double &value);
//! retrieves a property value in inch if possible or return 0
double getInchValue(librevenge::RVNGProperty const &prop);

/** tries to append border properties */
void appendBorderProperties(librevenge::RVNGPropertyList const &borderProp,
                            librevenge::RVNGPropertyList &propPropList,
                            bool toParagraph);

//! adds an unicode character to a string
void appendUnicode(uint32_t val, librevenge::RVNGString &buffer);

} // namespace librvngabw

/*! \class RVNGABWVec2
 *   \brief small class which defines a vector with 2 elements
 */
template <class T> class RVNGABWVec2
{
public:
	//! constructor
	RVNGABWVec2(T xx=0,T yy=0) : m_x(xx), m_y(yy) { }
	//! generic copy constructor
	template <class U> RVNGABWVec2(RVNGABWVec2<U> const &p) : m_x(T(p.x())), m_y(T(p.y())) {}

	//! first element
	T x() const
	{
		return m_x;
	}
	//! second element
	T y() const
	{
		return m_y;
	}
	//! operator[]
	T operator[](int c) const
	{
		if (c<0 || c>1) throw librvngabw::GenericException();
		return (c==0) ? m_x : m_y;
	}
	//! operator[]
	T &operator[](int c)
	{
		if (c<0 || c>1) throw librvngabw::GenericException();
		return (c==0) ? m_x : m_y;
	}

	//! resets the two elements
	void set(T xx, T yy)
	{
		m_x = xx;
		m_y = yy;
	}
	//! resets the first element
	void setX(T xx)
	{
		m_x = xx;
	}
	//! resets the second element
	void setY(T yy)
	{
		m_y = yy;
	}

	//! increases the actuals values by \a dx and \a dy
	void add(T dx, T dy)
	{
		m_x += dx;
		m_y += dy;
	}

	//! operator+=
	RVNGABWVec2<T> &operator+=(RVNGABWVec2<T> const &p)
	{
		m_x += p.m_x;
		m_y += p.m_y;
		return *this;
	}
	//! operator-=
	RVNGABWVec2<T> &operator-=(RVNGABWVec2<T> const &p)
	{
		m_x -= p.m_x;
		m_y -= p.m_y;
		return *this;
	}
	//! generic operator*=
	template <class U>
	RVNGABWVec2<T> &operator*=(U scale)
	{
		m_x = T(m_x*scale);
		m_y = T(m_y*scale);
		return *this;
	}

	//! operator+
	friend RVNGABWVec2<T> operator+(RVNGABWVec2<T> const &p1, RVNGABWVec2<T> const &p2)
	{
		RVNGABWVec2<T> p(p1);
		return p+=p2;
	}
	//! operator-
	friend RVNGABWVec2<T> operator-(RVNGABWVec2<T> const &p1, RVNGABWVec2<T> const &p2)
	{
		RVNGABWVec2<T> p(p1);
		return p-=p2;
	}
	//! generic operator*
	template <class U>
	friend RVNGABWVec2<T> operator*(U scale, RVNGABWVec2<T> const &p1)
	{
		RVNGABWVec2<T> p(p1);
		return p *= scale;
	}

	//! comparison==
	bool operator==(RVNGABWVec2<T> const &p) const
	{
		return cmpY(p) == 0;
	}
	//! comparison!=
	bool operator!=(RVNGABWVec2<T> const &p) const
	{
		return cmpY(p) != 0;
	}
	//! comparison<: sort by y
	bool operator<(RVNGABWVec2<T> const &p) const
	{
		return cmpY(p) < 0;
	}
	//! a comparison function: which first compares x then y
	int cmp(RVNGABWVec2<T> const &p) const
	{
		if (m_x < p.m_x) return -1;
		if (m_x > p.m_x) return 1;
		if (m_y < p.m_y) return -1;
		if (m_y > p.m_y) return 1;
		return 0;
	}
	//! a comparison function: which first compares y then x
	int cmpY(RVNGABWVec2<T> const &p) const
	{
		if (m_y < p.m_y) return -1;
		if (m_y > p.m_y) return 1;
		if (m_x < p.m_x) return -1;
		if (m_x > p.m_x) return 1;
		return 0;
	}

	//! operator<<: prints data in form "XxY"
	friend std::ostream &operator<< (std::ostream &o, RVNGABWVec2<T> const &f)
	{
		o << f.m_x << "x" << f.m_y;
		return o;
	}

protected:
	T m_x/*! \brief first element */, m_y/*! \brief second element */;
};

typedef RVNGABWVec2<int> RVNGABWVec2i;

#endif
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
