/*! \file pivarianttypes.h
 * \ingroup Types
 * \brief
 * \~english Types for PIVariant
 * \~russian Типы для PIVariant
*/
/*
	PIP - Platform Independent Primitives
	Variant types
	Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@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 PIVARIANTYPES_H
#define PIVARIANTYPES_H

#include "pistringlist.h"


class PIPropertyStorage;


//! \ingroup Types
//! \relatesalso PIVariant
//! \~english Namespace contains several types for PIVariant
//! \~russian Пространство имен содержит некоторые типы для PIVariant
namespace PIVariantTypes {


//! \addtogroup Types
//! \{
//! \~\struct Enumerator pivarianttypes.h
//! \~\brief
//! \~english Name-value pair.
//! \~russian Пара имя-значение.
//! \}
struct PIP_EXPORT Enumerator {
	Enumerator(int v = 0, const PIString & n = PIString()): value(v), name(n) {}

	//! \~english Value.
	//! \~russian Значение.
	int value;

	//! \~english Name.
	//! \~russian Имя.
	PIString name;
};


//! \addtogroup Types
//! \{
//! \~\struct Enum pivarianttypes.h
//! \~\brief
//! \~english Collection of PIVariantTypes::Enumerator.
//! \~russian Набор PIVariantTypes::Enumerator.
//! \~\details
//! \~english
//! This class represents classic c-style enum.
//! Contains elements with unique names and not uniqueue values, also
//! name of enum and selected member.
//!
//! \~russian
//! Этот класс представляет классический c-style enum.
//! Содержит элементы с уникальными именами и неуникальными значениями,
//! а также имя перечисления и выбранного элемента.
//!
//! \}
struct PIP_EXPORT Enum {
	Enum(const PIString & n = PIString()): enum_name(n) {}

	//! \~english Returns selected value, or 0 if there is no name in members.
	//! \~russian Возвращает выбранное значение, или 0, если выбранного имени нет в элементах.
	int selectedValue() const;

	//! \~english Returns selected name.
	//! \~russian Возвращает выбранное имя.
	PIString selectedName() const {return selected;}

	//! \~\brief
	//! \~english Select value if exists in Enum.
	//! \~russian Выбирает значение, если оно существует в Enum.
	//!
	//! \~\details
	//! \~english
	//! If Enum contains several PIVariantTypes::Enumerator with same values,
	//! first PIVariantTypes::Enumerator will selected.
	//! Returns if value exists in Enum.
	//!
	//! \~russian
	//! Если Enum содержит несколько PIVariantTypes::Enumerator с этим значением,
	//! то будет выбран первый.
	//! Возвращает существовал ли такой Enum.
	//!
	bool selectValue(int v);

	//! \~\brief
	//! \~english Select name if exists in Enum.
	//! \~russian Выбирает имя, если оно существует в Enum.
	//!
	//! \~\details
	//! \~english
	//! Returns if name exists in Enum.
	//!
	//! \~russian
	//! Возвращает существовал ли такой Enum.
	//!
	bool selectName(const PIString & n);

	//! \~english Find PIVariantTypes::Enumerator with name "n" and return it value, otherwise 0.
	//! \~russian Ищет PIVariantTypes::Enumerator с именем "n" и возвращает его значение, иначе 0.
	int value(const PIString & n) const;

	//! \~english Find PIVariantTypes::Enumerator with value "v" and return it name, otherwise empty string.
	//! \~russian Ищет PIVariantTypes::Enumerator со значением "v" и возвращает его имя, иначе пустую строку.
	PIString name(int v) const;

	//! \~english Returns all members values.
	//! \~russian Возвращает все значения членов.
	PIVector<int> values() const;

	//! \~english Returns all members names.
	//! \~russian Возвращает все имена членов.
	PIStringList names() const;

	//! \~english Add PIVariantTypes::Enumerator to Enum.
	//! \~russian Добавляет в Enum PIVariantTypes::Enumerator.
	Enum & operator <<(const Enumerator & v);

	//! \~english Add PIVariantTypes::Enumerator with name "v" and value of last element + 1, otherwise 0.
	//! \~russian Добавляет PIVariantTypes::Enumerator с именем "v" и значением последнего элемента + 1, иначе 0.
	Enum & operator <<(const PIString & v);

	//! \~english Add PIVariantTypes::Enumerator element for each name of vector.
	//! \~russian Добавляет PIVariantTypes::Enumerator для каждой строки из массива.
	Enum & operator <<(const PIStringList & v);

	//! \~english Returns if Enum is empty.
	//! \~russian Возвращает пустой ли Enum.
	bool isEmpty() const {return enum_list.isEmpty();}


	//! \~english Name of Enum.
	//! \~russian Имя Enum.
	PIString enum_name;

	//! \~english Name of selected element.
	//! \~russian Имя выбранного элемента.
	PIString selected;

	//! \~english Members.
	//! \~russian Элементы.
	PIVector<Enumerator> enum_list;
};


//! \addtogroup Types
//! \{
//! \~\struct File pivarianttypes.h
//! \~\brief
//! \~english File location description.
//! \~russian Описание положения файла.
//! \}
struct PIP_EXPORT File {
	File(const PIString & p = PIString(), const PIString & f = PIString(), bool abs = false, bool save_mode = false):
		file(p), filter(f), is_abs(abs), is_save(save_mode) {}

	//! \~english Returns path.
	//! \~russian Возвращает путь.
	PIString toString() const {return file;}

	//! \~english Path.
	//! \~russian Путь.
	PIString file;

	//! \~english Name filter.
	//! \~russian Фильтр имени.
	PIString filter;

	//! \~english If path is absolute.
	//! \~russian Абсолютный ли путь.
	bool is_abs;

	//! \~english If save is available.
	//! \~russian Доступно ли сохранение.
	bool is_save;
};


//! \addtogroup Types
//! \{
//! \~\struct Dir pivarianttypes.h
//! \~\brief
//! \~english Directory description.
//! \~russian Описание директории.
//! \}
struct PIP_EXPORT Dir {
	Dir(const PIString & d = PIString(), bool abs = false):
		dir(d), is_abs(abs) {}

	//! \~english Returns path.
	//! \~russian Возвращает путь.
	PIString toString() const {return dir;}

	//! \~english Path.
	//! \~russian Путь.
	PIString dir;

	//! \~english If path is absolute.
	//! \~russian Абсолютный ли путь.
	bool is_abs;
};


//! \addtogroup Types
//! \{
//! \~\struct Color pivarianttypes.h
//! \~\brief
//! \~english 32-bits color.
//! \~russian 32-битный цвет.
//! \}
struct PIP_EXPORT Color {
	Color(uint v = 0) {rgba = v;}

	//! \~english Returns color from #HEX, 0xHEX or name.
	//! \~russian Возвращает цвет от #HEX, 0xHEX или имени.
	static Color fromString(const PIString & str);

	//! \~english Returns color as #HEX, or as name if "find_name".
	//! \~russian Возвращает цвет как #HEX, либо как имя если "find_name".
	PIString toString(bool find_name = false) const;

	//! \~english Integer color.
	//! \~russian Целочисленный цвет.
	uint rgba;
};

inline bool operator < (const Color c0, const Color c1) {return c0.rgba <  c1.rgba;}
inline bool operator > (const Color c0, const Color c1) {return c0.rgba >  c1.rgba;}
inline bool operator ==(const Color c0, const Color c1) {return c0.rgba == c1.rgba;}
inline bool operator !=(const Color c0, const Color c1) {return c0.rgba != c1.rgba;}


//! \addtogroup Types
//! \{
//! \~\struct IODevice pivarianttypes.h
//! \~\brief
//! \~english Input/output device description.
//! \~russian Описание устройства ввода/вывода.
//! \}
struct PIP_EXPORT IODevice {
	IODevice();

	//! \~english Serialize "ps" and set it to "props".
	//! \~russian Сериализует "ps" и устанавливает "props".
	void set(const PIPropertyStorage & ps);

	//! \~english Deserialize "props" and returns it.
	//! \~russian Десериализует "props" и возвращает свойства.
	PIPropertyStorage get() const;

	//! \~english Returns string for PICout.
	//! \~russian Возвращает строку для PICout.
	PIString toPICout() const;

	//! \~english PIIODevice prefix, see \ref PIIODevice_sec7.
	//! \~russian Префикс PIIODevice, см. \ref PIIODevice_sec7.
	PIString prefix;

	//! PIIODevice::DeviceMode.
	int mode;

	//! PIIODevice::DeviceOptions.
	int options;

	//! \~english Serialized properties.
	//! \~russian Сериализованные свойства.
	PIByteArray props;
};

}


//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIVariantTypes::Enumerator & v) {s << v.name << "(" << v.value << ")"; return s;}

//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIVariantTypes::Enum & v) {s << "Enum(" << v.selectedValue() << "=" << v.selectedName() << ")"; return s;}

//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIVariantTypes::File & v) {s << "File(\"" << v.file << "\")"; return s;}

//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIVariantTypes::Dir & v) {s << "Dir(\"" << v.dir << "\")"; return s;}

//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIVariantTypes::Color & v) {s.saveControls(); s << PICoutManipulators::Hex << "Color(#" << v.rgba << ")"; s.restoreControls(); return s;}

//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIVariantTypes::IODevice & v) {s << v.toPICout(); return s;}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariantTypes::Enumerator) {s << v.value << v.name; return s;}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIVariantTypes::Enumerator) {s >> v.value >> v.name; return s;}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariantTypes::Enum) {s << v.enum_name << v.selected << v.enum_list; return s;}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIVariantTypes::Enum) {s >> v.enum_name >> v.selected >> v.enum_list; return s;}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariantTypes::File) {s << v.file << v.filter << uchar((v.is_abs ? 1 : 0) + (v.is_save ? 2 : 0)); return s;}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIVariantTypes::File) {uchar f(0); s >> v.file >> v.filter >> f; v.is_abs = ((f & 1) == 1); v.is_save = ((f & 2) == 2); return s;}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariantTypes::Dir) {s << v.dir << v.is_abs; return s;}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIVariantTypes::Dir) {s >> v.dir >> v.is_abs; return s;}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariantTypes::Color) {s << v.rgba; return s;}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIVariantTypes::Color) {s >> v.rgba; return s;}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariantTypes::IODevice) {s << v.prefix << v.mode << v.options << v.props; return s;}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIVariantTypes::IODevice) {s >> v.prefix >> v.mode >> v.options >> v.props; return s;}


#endif // PIVARIANTYPES_H
