//! \~\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 {


//! \~\ingroup Types
//! \~\struct Enumerator pivarianttypes.h
//! \~\brief
//! \~english Name-value pair.
//! \~russian Пара имя-значение.
struct PIP_EXPORT Enumerator {
	//! \~english Constructs an enumerator with the specified value and name.
	//! \~russian Конструирует перечислитель с указанным значением и именем.
	Enumerator(int v = 0, const PIString & n = PIString()): value(v), name(n) {}

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

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


//! \~\ingroup 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 {
	//! \~english Constructs an enum with the specified name.
	//! \~russian Конструирует перечисление с указанным именем.
	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 Returns string full representation.
	//! \~russian Возвращает полное строковое представление.
	PIString toString();

	//! \~english Returns Enum from string full representation.
	//! \~russian Возвращает Enum из полного строкового представления.
	static Enum fromString(PIString str);


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

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

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


//! \~\ingroup Types
//! \~\struct File pivarianttypes.h
//! \~\brief
//! \~english File location description.
//! \~russian Описание положения файла.
struct PIP_EXPORT File {
	//! \~english Constructs a file description with the specified parameters.
	//! \~russian Конструирует описание файла с указанными параметрами.
	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;
};


//! \~\ingroup Types
//! \~\struct Dir pivarianttypes.h
//! \~\brief
//! \~english Directory description.
//! \~russian Описание директории.
struct PIP_EXPORT Dir {
	//! \~english Constructs a directory description with the specified parameters.
	//! \~russian Конструирует описание директории с указанными параметрами.
	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;
};


//! \~\ingroup Types
//! \~\struct Color pivarianttypes.h
//! \~\brief
//! \~english 32-bits color.
//! \~russian 32-битный цвет.
struct PIP_EXPORT Color {
	//! \~english Constructs a color with the specified value.
	//! \~russian Конструирует цвет с указанным значением.
	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.
	//! \~russian Возвращает цвет как #HEX.
	PIString toString() const;

	//! \~english Returns name or #HEX if no suitable name.
	//! \~russian Возвращает имя, либо #HEX, если нет подходящего имени.
	PIString toName() 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;
}


//! \~\ingroup Types
//! \~\struct IODevice pivarianttypes.h
//! \~\brief
//! \~english Variant description used to create or configure %PIIODevice.
//! \~russian Variant-описание, используемое для создания или настройки %PIIODevice.
struct PIP_EXPORT IODevice {
	//! \~english Constructs an IO device.
	//! \~russian Конструирует устройство ввода/вывода.
	IODevice();

	//! \~english Serializes device-specific variant properties from "ps" into internal storage.
	//! \~russian Сериализует специфичные для устройства variant-свойства из "ps" во внутреннее хранилище.
	void set(const PIPropertyStorage & ps);

	//! \~english Restores device-specific variant properties from serialized storage.
	//! \~russian Восстанавливает специфичные для устройства variant-свойства из сериализованного хранилища.
	PIPropertyStorage get() const;

	//! \~english Returns PICout representation of this device description.
	//! \~russian Возвращает представление этого описания устройства для PICout.
	PIString toPICout() const;

	//! \~english Registered device prefix used in full-path notation, see \ref PIIODevice_sec7.
	//! \~russian Зарегистрированный префикс устройства, используемый в полной строке пути, см. \ref PIIODevice_sec7.
	PIString prefix;

	//! \~english Open mode from \a PIIODevice::DeviceMode.
	//! \~russian Режим открытия из \a PIIODevice::DeviceMode.
	int mode;

	//! \~english Device options bitmask from \a PIIODevice::DeviceOptions.
	//! \~russian Битовая маска опций из \a PIIODevice::DeviceOptions.
	int options;

	//! \~english Serialized device-specific variant properties.
	//! \~russian Сериализованные variant-свойства, специфичные для устройства.
	PIByteArray props;
};

} // namespace PIVariantTypes


//! \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
