//! \~\addtogroup Types
//! \~\{
//! \~\file piflags.h
//! \~\brief
//! \~english General flags class
//! \~russian Универсальные флаги
/*
    PIP - Platform Independent Primitives
    General flags class
    Ivan Pelipenko peri4ko@yandex.ru

    This program 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 3 of the License, or
    (at your option) any later version.

    This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PIFLAGS_H
#define PIFLAGS_H

#include "pip_export.h"

//! \addtogroup Types
//! \{
//! \~\class PIFlags piflags.h
//! \~\brief
//! \~english The %PIFlags class is a template container for bit flags with various bitwise operations and comparison operators.
//! \~russian Класс %PIFlags является шаблонным контейнером для битовых флагов с различными побитовыми операциями и операторами сравнения.
//! \~\details
//! \~english
//! %PIFlags is wrapper around \c "int". One can use it as native \c "int".
//! There are many bit-wise operators,
//! native conversion to "int" and function
//! to test flag. \n Example:
//!
//! \~russian
//! %PIFlags по сути обертка вокруг \c "int". Можно использовать его как обычный \c "int".
//! Имеет много побитовых операторов,
//! неявное преобразование в "int" и методы для проверки
//! флагов. \n Пример:
//!
//! \~\snippet piincludes.cpp flags
//!
//! \}
template<typename Enum>
class PIFlags {
public:
	//! \~english Constructor with flags = 0.
	//! \~russian Создает нулевые флаги.
	PIFlags(): flags(0) { ; }

	//! \~english Constructor with flags = Enum "e".
	//! \~russian Создает флаги со значением = Enum "e".
	PIFlags(Enum e): flags((int)e) { ; }

	//! \~english Constructor with flags = int "i".
	//! \~russian Создает флаги со значением = int "i".
	PIFlags(const int i): flags(i) { ; }

	//! \~english Set flags on positions "f" to value "on"
	//! \~russian Устанавливает флаги по позициям "f" в "on"
	PIFlags & setFlag(const PIFlags & f, bool on = true) {
		if (on)
			flags |= f.flags;
		else
			flags &= ~f.flags;
		return *this;
	}

	//! \~english Set flag "e" to value "on"
	//! \~russian Устанавливает флаг "e" в "on"
	PIFlags & setFlag(const Enum & e, bool on = true) {
		if (on)
			flags |= (int)e;
		else
			flags &= ~(int)e;
		return *this;
	}

	//! \~english Set flag "i" to value "on"
	//! \~russian Устанавливает флаг "i" в "on"
	PIFlags & setFlag(const int & i, bool on = true) {
		if (on)
			flags |= i;
		else
			flags &= ~i;
		return *this;
	}

	//! \~english Assign operator
	//! \~russian Оператор присваивания
	void operator=(const Enum & e) { flags = (int)e; }

	//! \~english Assign operator
	//! \~russian Оператор присваивания
	void operator=(const int & i) { flags = i; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator==(const PIFlags & f) { return flags == f.flags; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator==(const Enum & e) { return flags == (int)e; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator==(const int i) { return flags == i; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator!=(const PIFlags & f) { return flags != f.flags; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator!=(const Enum & e) { return flags != (int)e; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator!=(const int i) { return flags != i; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator>(const PIFlags & f) { return flags > f.flags; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator>(const Enum & e) { return flags > (int)e; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator>(const int i) { return flags > i; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator<(const PIFlags & f) { return flags < f.flags; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator<(const Enum & e) { return flags < (int)e; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator<(const int i) { return flags < i; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator>=(const PIFlags & f) { return flags >= f.flags; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator>=(const Enum & e) { return flags >= (int)e; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator>=(const int i) { return flags >= i; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator<=(const PIFlags & f) { return flags <= f.flags; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator<=(const Enum & e) { return flags <= (int)e; }

	//! \~english Compare operator
	//! \~russian Оператор сравнения
	bool operator<=(const int i) { return flags <= i; }

	//! \~english Bit-wise AND operator
	//! \~russian Оператор побитового И
	void operator&=(const PIFlags & f) { flags &= f.flags; }

	//! \~english Bit-wise AND operator
	//! \~russian Оператор побитового И
	void operator&=(const Enum & e) { flags &= (int)e; }

	//! \~english Bit-wise AND operator
	//! \~russian Оператор побитового И
	void operator&=(const int i) { flags &= i; }

	//! \~english Bit-wise OR operator
	//! \~russian Оператор побитового ИЛИ
	void operator|=(const PIFlags & f) { flags |= f.flags; }

	//! \~english Bit-wise OR operator
	//! \~russian Оператор побитового ИЛИ
	void operator|=(const Enum & e) { flags |= (int)e; }

	//! \~english Bit-wise OR operator
	//! \~russian Оператор побитового ИЛИ
	void operator|=(const int i) { flags |= i; }

	//! \~english Bit-wise XOR operator
	//! \~russian Оператор побитового исключающего ИЛИ
	void operator^=(const PIFlags & f) { flags ^= f.flags; }

	//! \~english Bit-wise XOR operator
	//! \~russian Оператор побитового исключающего ИЛИ
	void operator^=(const Enum & e) { flags ^= (int)e; }

	//! \~english Bit-wise XOR operator
	//! \~russian Оператор побитового исключающего ИЛИ
	void operator^=(const int i) { flags ^= i; }

	//! \~english Bit-wise AND operator
	//! \~russian Оператор побитового И
	PIFlags operator&(PIFlags f) const {
		PIFlags tf(flags & f.flags);
		return tf;
	}

	//! \~english Bit-wise AND operator
	//! \~russian Оператор побитового И
	PIFlags operator&(Enum e) const {
		PIFlags tf(flags & (int)e);
		return tf;
	}

	//! \~english Bit-wise AND operator
	//! \~russian Оператор побитового И
	PIFlags operator&(int i) const {
		PIFlags tf(flags & i);
		return tf;
	}

	//! \~english Bit-wise OR operator
	//! \~russian Оператор побитового ИЛИ
	PIFlags operator|(PIFlags f) const {
		PIFlags tf(flags | f.flags);
		return tf;
	}

	//! \~english Bit-wise OR operator
	//! \~russian Оператор побитового ИЛИ
	PIFlags operator|(Enum e) const {
		PIFlags tf(flags | (int)e);
		return tf;
	}

	//! \~english Bit-wise OR operator
	//! \~russian Оператор побитового ИЛИ
	PIFlags operator|(int i) const {
		PIFlags tf(flags | i);
		return tf;
	}

	//! \~english Bit-wise XOR operator
	//! \~russian Оператор побитового исключающего ИЛИ
	PIFlags operator^(PIFlags f) const {
		PIFlags tf(flags ^ f.flags);
		return tf;
	}

	//! \~english Bit-wise XOR operator
	//! \~russian Оператор побитового исключающего ИЛИ
	PIFlags operator^(Enum e) const {
		PIFlags tf(flags ^ (int)e);
		return tf;
	}

	//! \~english Bit-wise XOR operator
	//! \~russian Оператор побитового исключающего ИЛИ
	PIFlags operator^(int i) const {
		PIFlags tf(flags ^ i);
		return tf;
	}

	//! \~english Test flag operator
	//! \~russian Оператор проверки флага
	bool operator[](Enum e) const { return (flags & (int)e) == (int)e; }

	//! \~english Implicity conversion to \c int.
	//! \~russian Оператор неявного преобразования в \c int.
	operator int() const { return flags; }

private:
	int flags;
};

#endif // PIFLAGS_H
