//! \~\file pivariant.h
//! \~\ingroup Types
//! \~\brief
//! \~english Variant type
//! \~russian Вариативный тип
/*
    PIP - Platform Independent Primitives
    Variant type
    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 PIVARIANT_H
#define PIVARIANT_H

#include "piconstchars.h"
#include "pidatetime.h"
#include "pigeoposition.h"
#include "piline.h"
#include "pimathmatrix.h"
#include "pinetworkaddress.h"
#include "pipoint.h"
#include "pirect.h"
#include "pivarianttypes.h"


#ifdef DOXYGEN

//! \relatesalso PIVariant
//! \~\brief
//! \~english Macro to register type for using in %PIVariant
//! \~russian Макрос для регистрации типа для использования в %PIVariant
#  define REGISTER_VARIANT(Typename)

//! \relatesalso PIVariant
//! \~\brief
//! \~english Macro to register type with namespace for using in %PIVariant
//! \~russian Макрос для регистрации типа с пространством имен для использования в %PIVariant
#  define REGISTER_NS_VARIANT(Namespace, Typename)

#endif


#ifndef QNX
#  define CUSTOM_PIVARIANT
#endif

#ifdef CUSTOM_PIVARIANT


template<typename T>
class __PIVariantFunctions__ {
public:
	static PIString typeNameHelper() { return PIStringAscii(""); }
	static uint typeIDHelper() { return 0; }

	static bool isSimpleHelper() { return false; }
	template<typename C>
	static PIByteArray castHelper(PIByteArray ba) {
		return PIByteArray();
	}
	template<typename C>
	static C castVariant(const T & v) {
		return C();
	}
};

struct PIP_EXPORT __PIVariantInfo__ {
	__PIVariantInfo__(const PIString & n, const PIByteArray & e) {
		typeName = n;
		typeID   = n.hash();
		empty    = e;
	}
	typedef PIByteArray (*castHelperFunc)(PIByteArray);
	PIMap<uint, castHelperFunc> cast;
	PIByteArray empty;
	PIString typeName;
	uint typeID = 0;
	bool simple = false;
};

template<typename T>
struct __PIVariantTypeInfo__ {
	typedef T PureType;
	typedef const T ConstPureType;
	typedef T * PointerType;
	typedef const T * ConstPointerType;
	typedef T & ReferenceType;
	typedef const T & ConstReferenceType;
};

#  define __TYPEINFO_SINGLE(PT, T)           \
	template<>                               \
	struct __PIVariantTypeInfo__<T> {        \
	  typedef PT PureType;                   \
	  typedef const PT ConstPureType;        \
	  typedef PT * PointerType;              \
	  typedef const PT * ConstPointerType;   \
	  typedef PT & ReferenceType;            \
	  typedef const PT & ConstReferenceType; \
	};

#  define REGISTER_VARIANT_TYPEINFO(T) \
	__TYPEINFO_SINGLE(T, T &)          \
	__TYPEINFO_SINGLE(T, const T)      \
	__TYPEINFO_SINGLE(T, const T &)


class PIP_EXPORT __PIVariantInfoStorage__ {
public:
	static PIMap<uint, __PIVariantInfo__ *> & get();
};


#  define REGISTER_VARIANT(classname)                                                     \
	template<>                                                                            \
	inline PIString __PIVariantFunctions__<classname>::typeNameHelper() {                 \
	  static PIString tn = PIStringAscii(#classname);                                     \
	  return tn;                                                                          \
	}                                                                                     \
	template<>                                                                            \
	inline uint __PIVariantFunctions__<classname>::typeIDHelper() {                       \
	  static uint ret = PIStringAscii(#classname).hash();                                 \
	  return ret;                                                                         \
	}                                                                                     \
	REGISTER_VARIANT_TYPEINFO(classname)                                                  \
	STATIC_INITIALIZER_BEGIN                                                              \
	  uint type_id       = __PIVariantFunctions__<classname>::typeIDHelper();             \
	  PIString type_name = __PIVariantFunctions__<classname>::typeNameHelper();           \
	  if (__PIVariantInfoStorage__::get().contains(type_id)) return;                      \
	  PIByteArray empty;                                                                  \
	  empty << classname();                                                               \
	  __PIVariantInfoStorage__::get()[type_id] = new __PIVariantInfo__(type_name, empty); \
	STATIC_INITIALIZER_END


#  define REGISTER_VARIANT_CAST_H(classname_from, classname_to) \
	template<>                                                  \
	template<>                                                  \
	inline classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v);

#  define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)                                                                         \
	template<>                                                                                                                            \
	template<>                                                                                                                            \
	inline PIByteArray __PIVariantFunctions__<classname_from>::castHelper<classname_to>(PIByteArray v) {                                  \
	  classname_from f;                                                                                                                   \
	  v >> f;                                                                                                                             \
	  classname_to t = __PIVariantFunctions__<classname_from>::castVariant<classname_to>(f);                                              \
	  PIByteArray ret;                                                                                                                    \
	  ret << t;                                                                                                                           \
	  return ret;                                                                                                                         \
	}                                                                                                                                     \
	STATIC_INITIALIZER_BEGIN                                                                                                              \
	  __PIVariantInfo__ * vi(__PIVariantInfoStorage__::get().value(__PIVariantFunctions__<classname_from>::typeIDHelper(), nullptr));     \
	  if (!vi) {                                                                                                                          \
		piCout << "Warning! Using REGISTER_VARIANT_CAST(" #classname_from ", " #classname_to ") before REGISTER_VARIANT(" #classname_from \
				  "), ignore.";                                                                                                           \
		return;                                                                                                                           \
	  }                                                                                                                                   \
	  vi->cast[__PIVariantFunctions__<classname_to>::typeIDHelper()] = __PIVariantFunctions__<classname_from>::castHelper<classname_to>;  \
	STATIC_INITIALIZER_END                                                                                                                \
	template<>                                                                                                                            \
	template<>                                                                                                                            \
	classname_to __PIVariantFunctions__<classname_from>::castVariant<classname_to>(const classname_from & v)

#  define REGISTER_VARIANT_CAST(classname_from, classname_to) \
	REGISTER_VARIANT_CAST_H(classname_from, classname_to)     \
	REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)


#  define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to) \
	REGISTER_VARIANT_CAST(classname_from, classname_to) { return classname_to(v); }
#  define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to) REGISTER_VARIANT_CAST_H(classname_from, classname_to)
#  define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to) \
	REGISTER_VARIANT_CAST_CPP(classname_from, classname_to) { return classname_to(v); }

#else

#  define REGISTER_VARIANT_TYPEINFO(classname)
#  define REGISTER_VARIANT_H(classname)
#  define REGISTER_VARIANT_CPP(classname)
#  define INIT_VARIANT(classname)
#  define REGISTER_VARIANT(classname)
#  define REGISTER_NS_VARIANT_H(ns, classname)
#  define REGISTER_NS_VARIANT_CPP(ns, classname)
#  define INIT_NS_VARIANT(ns, classname)
#  define REGISTER_NS_VARIANT(ns, classname)
#  define REGISTER_VARIANT_CAST_H(classname_from, classname_to)
#  define REGISTER_VARIANT_CAST_CPP(classname_from, classname_to)
#  define REGISTER_VARIANT_CAST(classname_from, classname_to)
#  define REGISTER_VARIANT_CAST_SIMPLE(classname_from, classname_to)
#  define REGISTER_VARIANT_CAST_SIMPLE_H(classname_from, classname_to)
#  define REGISTER_VARIANT_CAST_SIMPLE_CPP(classname_from, classname_to)

#endif

//! \~\ingroup Types
//! \~\brief
//! \~english Variant type.
//! \~russian Вариантный тип.
//! \~\details
//! \~english The %PIVariant class provides a variant type that can store values of various types.
//! \~russian Класс %PIVariant предоставляет вариативный тип, который может хранить значения различных типов.
class PIP_EXPORT PIVariant {
	friend PICout operator<<(PICout s, const PIVariant & v);
	BINARY_STREAM_FRIEND(PIVariant);

public:
	//! \~english Type of %PIVariant content
	//! \~russian Тип содержимого %PIVariant
	enum Type {
		pivInvalid /** \~english Invalid type, default type of empty constructor \~russian Недействительный тип, также конструированный по
		              умолчанию */
			= 0,
		pivBool /** bool */,
		pivChar /** char */,
		pivUChar /** uchar */,
		pivShort /** short */,
		pivUShort /** ushort */,
		pivInt /** int */,
		pivUInt /** uint */,
		pivLLong /** llong */,
		pivULLong /** ullong */,
		pivFloat /** float */,
		pivDouble /** double */,
		pivLDouble /** ldouble */,
		pivComplexd /** complexd */,
		pivComplexld /** complexld */,
		pivBitArray /** PIBitArray */,
		pivByteArray /** PIByteArray */,
		pivString /** PIString */,
		pivStringList /** PIStringList */,
		pivTime /** PITime */,
		pivDate /** PIDate */,
		pivDateTime /** PIDateTime */,
		pivSystemTime /** PISystemTime */,
		pivEnum /** PIVariantTypes::Enum */,
		pivFile /** PIVariantTypes::File */,
		pivDir /** PIVariantTypes::Dir */,
		pivColor /** PIVariantTypes::Color */,
		pivPoint /** PIPoint<double> */,
		pivRect /** PIRect<double> */,
		pivIODevice /** PIVariantTypes::IODevice */,
		pivMathVector /** PIMathVector<double> */,
		pivMathMatrix /** PIMathMatrix<double> */,
		pivLine /** PILine<double> */,
		pivNetworkAddress /** PINetworkAddress */,
		pivComplexf /** complexf */,
		pivCustom /** \~english Custom \~russian Свой тип */ = 0xFF
	};

	//! \~english Construct \a pivInvalid %PIVariant
	//! \~russian Создает \a pivInvalid %PIVariant
	PIVariant();

	//! \~english Contructs a copy of %PIVariant.
	//! \~russian Создает копию %PIVariant.
	PIVariant(const PIVariant & v);

	//! \~english Move constructor.
	//! \~russian Перемещающий конструктор.
	PIVariant(PIVariant && v);

	//! \~english Constructs %PIVariant from string.
	//! \~russian Создает %PIVariant из строки.
	PIVariant(const char * v) { initType(PIString(v)); }

	//! \~english Constructs %PIVariant from boolean.
	//! \~russian Создает %PIVariant из логического значения.
	PIVariant(const bool v) { initType(v); }

	//! \~english Constructs %PIVariant from char.
	//! \~russian Создает %PIVariant из символа.
	PIVariant(const char v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const uchar v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const short v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const ushort v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const int & v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const uint & v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const llong & v) { initType(v); }

	//! \~english Constructs %PIVariant from integer.
	//! \~russian Создает %PIVariant из целого числа.
	PIVariant(const ullong & v) { initType(v); }

	//! \~english Constructs %PIVariant from float.
	//! \~russian Создает %PIVariant из вещественного числа.
	PIVariant(const float & v) { initType(v); }

	//! \~english Constructs %PIVariant from double.
	//! \~russian Создает %PIVariant из вещественного числа.
	PIVariant(const double & v) { initType(v); }

	//! \~english Constructs %PIVariant from long double.
	//! \~russian Создает %PIVariant из вещественного числа.
	PIVariant(const ldouble & v) { initType(v); }

	//! \~english Constructs %PIVariant from complex number.
	//! \~russian Создает %PIVariant из комплексного числа.
	PIVariant(const complexf & v) { initType(v); }

	//! \~english Constructs %PIVariant from complex number.
	//! \~russian Создает %PIVariant из комплексного числа.
	PIVariant(const complexd & v) { initType(v); }

	//! \~english Constructs %PIVariant from complex number.
	//! \~russian Создает %PIVariant из комплексного числа.
	PIVariant(const complexld & v) { initType(v); }

	//! \~english Constructs %PIVariant from bit array.
	//! \~russian Создает %PIVariant из массива битов.
	PIVariant(const PIBitArray & v) { initType(v); }

	//! \~english Constructs %PIVariant from byte array.
	//! \~russian Создает %PIVariant из массива байтов.
	PIVariant(const PIByteArray & v) { initType(v); }

	//! \~english Constructs %PIVariant from string.
	//! \~russian Создает %PIVariant из строки.
	PIVariant(const PIString & v) { initType(v); }

	//! \~english Constructs %PIVariant from strings list.
	//! \~russian Создает %PIVariant из массива строк.
	PIVariant(const PIStringList & v) { initType(v); }

	//! \~english Constructs %PIVariant from time.
	//! \~russian Создает %PIVariant из времени.
	PIVariant(const PITime & v) { initType(v); }

	//! \~english Constructs %PIVariant from date.
	//! \~russian Создает %PIVariant из даты.
	PIVariant(const PIDate & v) { initType(v); }

	//! \~english Constructs %PIVariant from date and time.
	//! \~russian Создает %PIVariant из даты и времени.
	PIVariant(const PIDateTime & v) { initType(v); }

	//! \~english Constructs %PIVariant from system time.
	//! \~russian Создает %PIVariant из системного времени.
	PIVariant(const PISystemTime & v) { initType(v); }

	//! \~english Constructs %PIVariant from enum.
	//! \~russian Создает %PIVariant из перечисления.
	PIVariant(const PIVariantTypes::Enum & v) { initType(v); }

	//! \~english Constructs %PIVariant from file.
	//! \~russian Создает %PIVariant из файла.
	PIVariant(const PIVariantTypes::File & v) { initType(v); }

	//! \~english Constructs %PIVariant from dir.
	//! \~russian Создает %PIVariant из директории.
	PIVariant(const PIVariantTypes::Dir & v) { initType(v); }

	//! \~english Constructs %PIVariant from color.
	//! \~russian Создает %PIVariant из цвета.
	PIVariant(const PIVariantTypes::Color & v) { initType(v); }

	//! \~english Constructs %PIVariant from IODevice.
	//! \~russian Создает %PIVariant из IODevice.
	PIVariant(const PIVariantTypes::IODevice & v) { initType(v); }

	//! \~english Constructs %PIVariant from point.
	//! \~russian Создает %PIVariant из точки.
	PIVariant(const PIPointd & v) { initType(v); }

	//! \~english Constructs %PIVariant from rect.
	//! \~russian Создает %PIVariant из прямоугольника.
	PIVariant(const PIRectd & v) { initType(v); }

	//! \~english Constructs %PIVariant from line.
	//! \~russian Создает %PIVariant из линии.
	PIVariant(const PILined & v) { initType(v); }

	//! \~english Constructs %PIVariant from PINetworkAddress.
	//! \~russian Создает %PIVariant из PINetworkAddress.
	PIVariant(const PINetworkAddress & v) { initType(v); }

	//! \~english Constructs %PIVariant from MathVector.
	//! \~russian Создает %PIVariant из MathVector.
	PIVariant(const PIMathVectord & v) { initType(v); }

	//! \~english Constructs %PIVariant from MathMatrix.
	//! \~russian Создает %PIVariant из MathMatrix.
	PIVariant(const PIMathMatrixd & v) { initType(v); }


	//! \~english Set variant content and type to string
	//! \~russian Устанавливает значение и тип из строки
	void setValue(const char * v) { setValue(PIString(v)); }

	//! \~english Set variant content and type to boolean
	//! \~russian Устанавливает значение и тип из логического значения
	void setValue(const bool v) { initType(v); }

	//! \~english Set variant content and type to char
	//! \~russian Устанавливает значение и тип из символа
	void setValue(const char v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const uchar v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const short v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const ushort v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const int & v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const uint & v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const llong & v) { initType(v); }

	//! \~english Set variant content and type to integer
	//! \~russian Устанавливает значение и тип из целого числа
	void setValue(const ullong & v) { initType(v); }

	//! \~english Set variant content and type to float
	//! \~russian Устанавливает значение и тип из вещественного числа
	void setValue(const float & v) { initType(v); }

	//! \~english Set variant content and type to double
	//! \~russian Устанавливает значение и тип из вещественного числа
	void setValue(const double & v) { initType(v); }

	//! \~english Set variant content and type to long double
	//! \~russian Устанавливает значение и тип из вещественного числа
	void setValue(const ldouble & v) { initType(v); }

	//! \~english Set variant content and type to complex
	//! \~russian Устанавливает значение и тип из комплексного числа
	void setValue(const complexf & v) { initType(v); }

	//! \~english Set variant content and type to complex
	//! \~russian Устанавливает значение и тип из комплексного числа
	void setValue(const complexd & v) { initType(v); }

	//! \~english Set variant content and type to complex
	//! \~russian Устанавливает значение и тип из комплексного числа
	void setValue(const complexld & v) { initType(v); }

	//! \~english Set variant content and type to bit array
	//! \~russian Устанавливает значение и тип из массива битов
	void setValue(const PIBitArray & v) { initType(v); }

	//! \~english Set variant content and type to byte array
	//! \~russian Устанавливает значение и тип из массива байтов
	void setValue(const PIByteArray & v) { initType(v); }

	//! \~english Set variant content and type to string
	//! \~russian Устанавливает значение и тип из строки
	void setValue(const PIString & v) { initType(v); }

	//! \~english Set variant content and type to strings list
	//! \~russian Устанавливает значение и тип из массива строк
	void setValue(const PIStringList & v) { initType(v); }

	//! \~english Set variant content and type to time
	//! \~russian Устанавливает значение и тип из времени
	void setValue(const PITime & v) { initType(v); }

	//! \~english Set variant content and type to date
	//! \~russian Устанавливает значение и тип из даты
	void setValue(const PIDate & v) { initType(v); }

	//!
	//! \~english Set variant content and type to date and time
	//! \~russian Устанавливает значение и тип из даты и времени
	void setValue(const PIDateTime & v) { initType(v); }

	//! \~english Set variant content and type to system time
	//! \~russian Устанавливает значение и тип из системного времени
	void setValue(const PISystemTime & v) { initType(v); }

	//! \~english Set variant content and type to enum
	//! \~russian Устанавливает значение и тип из перечисления
	void setValue(const PIVariantTypes::Enum & v) { initType(v); }

	//! \~english Set variant content and type to file
	//! \~russian Устанавливает значение и тип из файла
	void setValue(const PIVariantTypes::File & v) { initType(v); }

	//! \~english Set variant content and type to dir
	//! \~russian Устанавливает значение и тип из директории
	void setValue(const PIVariantTypes::Dir & v) { initType(v); }

	//! \~english Set variant content and type to color
	//! \~russian Устанавливает значение и тип из цвета
	void setValue(const PIVariantTypes::Color & v) { initType(v); }

	//! \~english Set variant content and type to IODevice
	//! \~russian Устанавливает значение и тип из IODevice
	void setValue(const PIVariantTypes::IODevice & v) { initType(v); }

	//! \~english Set variant content and type to point
	//! \~russian Устанавливает значение и тип из точки
	void setValue(const PIPointd & v) { initType(v); }

	//! \~english Set variant content and type to rect
	//! \~russian Устанавливает значение и тип из прямоугольника
	void setValue(const PIRectd & v) { initType(v); }

	//! \~english Set variant content and type to line
	//! \~russian Устанавливает значение и тип из линии
	void setValue(const PILined & v) { initType(v); }

	//! \~english Set variant content and type to math vector
	//! \~russian Устанавливает значение и тип из вектора
	void setValue(const PIMathVectord & v) { initType(v); }

	//! \~english Set variant content and type to PINetworkAddress
	//! \~russian Устанавливает значение и тип из PINetworkAddress
	void setValue(const PINetworkAddress & v) { initType(v); }

	//! \~english Set variant content and type to math matrix
	//! \~russian Устанавливает значение и тип из матрицы
	void setValue(const PIMathMatrixd & v) { initType(v); }


	//! \~english Set current value from string without change type
	//! \~russian Устанавливает текущее значение из строки без изменения типа
	void setValueFromString(const PIString & v);


	//! \~english Returns value as boolean.
	//! \~russian Возвращает значение как логическое значение.
	bool toBool() const;

	//! \~english Returns value as integer.
	//! \~russian Возвращает значение как целое число.
	int toInt() const;

	//! \~english Returns value as long long integer.
	//! \~russian Возвращает значение как длинное длинное целое число.
	llong toLLong() const;

	//! \~english Returns value as float.
	//! \~russian Возвращает значение как float.
	float toFloat() const;

	//! \~english Returns value as double.
	//! \~russian Возвращает значение как double.
	double toDouble() const;

	//! \~english Returns value as long double.
	//! \~russian Возвращает значение как long double.
	ldouble toLDouble() const;

	//! \~english Returns value as complex float.
	//! \~russian Возвращает значение как комплексное float.
	complexf toComplexF() const;

	//! \~english Returns value as complex double.
	//! \~russian Возвращает значение как комплексное double.
	complexd toComplexD() const;

	//! \~english Returns value as complex long double.
	//! \~russian Возвращает значение как комплексное long double.
	complexld toComplexLD() const;

	//! \~english Returns value as time.
	//! \~russian Возвращает значение как время.
	PITime toTime() const;

	//! \~english Returns value as date.
	//! \~russian Возвращает значение как дату.
	PIDate toDate() const;

	//! \~english Returns value as date and time.
	//! \~russian Возвращает значение как дату и время.
	PIDateTime toDateTime() const;

	//! \~english Returns value as system time.
	//! \~russian Возвращает значение как системное время.
	PISystemTime toSystemTime() const;

	//! \~english Returns value as string.
	//! \~russian Возвращает значение как строку.
	PIString toString() const;

	//! \~english Returns value as string list.
	//! \~russian Возвращает значение как массив строк.
	PIStringList toStringList() const;

	//! \~english Returns value as bit array.
	//! \~russian Возвращает значение как массив битов.
	PIBitArray toBitArray() const;

	//! \~english Returns value as byte array.
	//! \~russian Возвращает значение как массив байтов.
	PIByteArray toByteArray() const;

	//! \~english Returns value as enum.
	//! \~russian Возвращает значение как перечисление.
	PIVariantTypes::Enum toEnum() const;

	//! \~english Returns value as file.
	//! \~russian Возвращает значение как файл.
	PIVariantTypes::File toFile() const;

	//! \~english Returns value as directory.
	//! \~russian Возвращает значение как директорию.
	PIVariantTypes::Dir toDir() const;

	//! \~english Returns value as color.
	//! \~russian Возвращает значение как цвет.
	PIVariantTypes::Color toColor() const;

	//! \~english Returns value as IO device.
	//! \~russian Возвращает значение как устройство ввода/вывода.
	PIVariantTypes::IODevice toIODevice() const;

	//! \~english Returns value as point.
	//! \~russian Возвращает значение как точку.
	PIPointd toPoint() const;

	//! \~english Returns value as rect.
	//! \~russian Возвращает значение как прямоугольник.
	PIRectd toRect() const;

	//! \~english Returns value as line.
	//! \~russian Возвращает значение как линию.
	PILined toLine() const;

	//! \~english Returns value as network address.
	//! \~russian Возвращает значение как сетевой адрес.
	PINetworkAddress toNetworkAddress() const;

	//! \~english Returns value as math vector.
	//! \~russian Возвращает значение как математический вектор.
	PIMathVectord toMathVector() const;

	//! \~english Returns value as math matrix.
	//! \~russian Возвращает значение как математическую матрицу.
	PIMathMatrixd toMathMatrix() const;


	//! \~\brief
	//! \~english Returns variant content as custom type
	//! \~russian Возвращает содержимое в качестве своего типа
	//! \~\details
	//! \~english
	//! In case of known types this function equivalent \a to<Type> function. \n
	//! Otherwise returns content as type T only if this type was set earlier.
	//! \~russian
	//! Для стандартных типов эквивалентно методу \a to<Type>. \n
	//! Для других возвращает тип T только если он был установлен ранее.
	template<typename T>
	T value() const {
		return getAsValue<T>(*this);
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIVariant & v);

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(PIVariant && v);

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const char * v) {
		setValue(PIString(v));
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const bool v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const char v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const uchar v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const short v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const ushort v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const int & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const uint & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const llong & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const ullong & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const float & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const double & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const ldouble & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const complexf & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const complexd & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const complexld & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIBitArray & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIByteArray & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIString & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIStringList & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PITime & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIDate & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIDateTime & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PISystemTime & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIVariantTypes::Enum & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIVariantTypes::File & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIVariantTypes::Dir & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIVariantTypes::Color & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIVariantTypes::IODevice & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIPointd & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIRectd & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PILined & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PINetworkAddress & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIMathVectord & v) {
		setValue(v);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	PIVariant & operator=(const PIMathMatrixd & v) {
		setValue(v);
		return *this;
	}


	//! \~english Compare operator. Check type and content.
	//! \~russian Оператор сравнения. Сравнивает тип и содержимое.
	bool operator==(const PIVariant & v) const;

	//! \~english Compare operator. Check type and content.
	//! \~russian Оператор сравнения. Сравнивает тип и содержимое.
	bool operator!=(const PIVariant & v) const { return !(*this == v); }


	//! \~english Returns type of variant content.
	//! \~russian Возвращает тип значения.
	PIVariant::Type type() const { return _type; }

	//! \~english Returns type ID of variant content.
	//! \~russian Возвращает ID типа значения.
	uint typeID() const { return _typeID; }

	//! \~english Returns type name of variant content.
	//! \~russian Возвращает имя типа значения.
	PIString typeName() const;


	//! \~english Returns if type is not \a pivInvalid.
	//! \~russian Возвращает не является ли тип \a pivInvalid.
	bool isValid() const { return _type != PIVariant::pivInvalid; }

	//! \~english Swaps with other %PIVariant.
	//! \~russian Меняет с другим %PIVariant.
	void swap(PIVariant & v);


	//! \~\brief
	//! \~english Returns new %PIVariant from custom type value.
	//! \~russian Возвращает новый %PIVariant из значения своего типа.
	//! \~\details
	//! \~english
	//! In case of known types this function equivalent \a PIVariant() constructors. \n
	//! Otherwise returns variant with content "v" and type \a pivCustom.
	//! \~russian
	//! Для стандартных типов эквивалентно конструктору \a PIVariant(). \n
	//! Для других устанавливает содержимое из "v" и тип \a pivCustom.
	template<typename T>
	static PIVariant fromValue(const T & v) {
		PIVariant ret;
		ret.initType<T>(v);
		return ret;
	}

	//! \~english Returns new %PIVariant from byte array with type ID.
	//! \~russian Возвращает новый %PIVariant из массива байтов с ID типа.
	static PIVariant fromValue(const PIByteArray & c, uint type_id);
	//! \~english Returns new %PIVariant from byte array with type name.
	//! \~russian Возвращает новый %PIVariant из массива байтов с именем типа.
	static PIVariant fromValue(const PIByteArray & c, const PIString & type);

	//! \~english Returns new %PIVariant from default-constructed type with name "type".
	//! \~russian Возвращает новый %PIVariant из пустого конструктора типа "type".
	static PIVariant fromType(const PIString & type) { return fromType(typeIDFromName(type)); }

	//! \~english Returns new %PIVariant from default-constructed type with type ID "type_id".
	//! \~russian Возвращает новый %PIVariant из пустого конструктора типа c ID "type_id".
	static PIVariant fromType(uint type_id);


	//! \~english Returns type from its name.
	//! \~russian Возвращает тип из его названия.
	static PIVariant::Type typeFromName(const PIString & tname);

	//! \~english Returns type from its ID.
	//! \~russian Возвращает тип из его ID.
	static PIVariant::Type typeFromID(uint type_id);

	//! \~english Returns type from its name.
	//! \~russian Возвращает тип из его названия.
	static uint typeIDFromName(const PIString & tname);

	//! \~english Returns type ID from standard type.
	//! \~russian Возвращает ID типа от стандатного типа.
	static uint typeIDFromType(PIVariant::Type type);

	//! \~english Returns type name.
	//! \~russian Возвращает имя типа.
	static PIString typeName(PIVariant::Type type);

	//! \~english Returns type name.
	//! \~russian Возвращает имя типа.
	template<typename T>
	static PIString typeName() {
#ifdef CUSTOM_PIVARIANT
		return __PIVariantFunctions__<T>::typeNameHelper();
#else
		return PIString();
#endif
	}

	//! \~english Returns type name from its ID.
	//! \~russian Возвращает имя типа из его ID.
	static PIString typeNameFromID(uint type_id);

	template<typename T>
	static uint typeID() {
#ifdef CUSTOM_PIVARIANT
		return __PIVariantFunctions__<T>::typeIDHelper();
#else
		return 0;
#endif
	}

	//! \~english Returns all registered type ID.
	//! \~russian Возвращает все зарегистрированные ID типов.
	static PIVector<uint> knownTypeIDs();

	//! \~english Returns count of registered types.
	//! \~russian Возвращает количество зарегистрированных типов.
	static int knownTypeIDsCount();

private:
	void destroy() { _content.clear(); }
	template<typename T>
	inline static Type getType() {
		return pivCustom;
	}
	template<typename T>
	inline void initType(const T & v) {
		_content.clear();
		_content << v;
		_type = getType<T>();
#ifdef CUSTOM_PIVARIANT
		_typeID = typeID<T>();
		if (_type == pivCustom) {
			_info = __PIVariantInfoStorage__::get().value(_typeID, 0);
			if (!_info) {
				_type = pivInvalid;
				piCout << "Can`t initialize PIVariant from unregistered type!";
			}
		} else
			_info = 0;
#endif
	}
	template<typename T>
	inline static T getAsValue(const PIVariant & v) {
#ifdef CUSTOM_PIVARIANT
		if (v._content.isEmpty() || !v._info) return T();
		uint cnid = __PIVariantFunctions__<T>::typeIDHelper();
		// piCout << "gav" << cn;
		PIByteArray ba;
		if (cnid == v._info->typeID) {
			ba = v._content;
		} else {
			__PIVariantInfo__::castHelperFunc cf = v._info->cast.value(cnid);
			// piCout << "gav cast" << cf;
			if (!cf) return T();
			ba = cf(v._content);
		}
		T ret;
		ba >> ret;
		return ret;
#else
		return T();
#endif
	}

	PIByteArray _content;
	PIVariant::Type _type = PIVariant::pivInvalid;
#ifdef CUSTOM_PIVARIANT
	__PIVariantInfo__ * _info = nullptr;
#endif
	uint _typeID = 0;
};

typedef PIMap<PIString, PIVariant> PIVariantMap;
typedef PIVector<PIVariant> PIVariantVector;

// clang-format off
template<> inline bool PIVariant::value() const {return toBool();}
template<> inline char PIVariant::value() const {return (char)toInt();}
template<> inline uchar PIVariant::value() const {return (uchar)toInt();}
template<> inline short PIVariant::value() const {return (short)toInt();}
template<> inline ushort PIVariant::value() const {return (ushort)toInt();}
template<> inline int PIVariant::value() const {return toInt();}
template<> inline uint PIVariant::value() const {return (uint)toInt();}
template<> inline llong PIVariant::value() const {return toLLong();}
template<> inline ullong PIVariant::value() const {return (ullong)toLLong();}
template<> inline float PIVariant::value() const {return toFloat();}
template<> inline double PIVariant::value() const {return toDouble();}
template<> inline ldouble PIVariant::value() const {return toLDouble();}
template<> inline complexf PIVariant::value() const {return  toComplexF();}
template<> inline complexd PIVariant::value() const {return  toComplexD();}
template<> inline complexld PIVariant::value() const {return toComplexLD();}
template<> inline void* PIVariant::value() const {return (void*)toLLong();}
template<> inline const char* PIVariant::value() const {return toString().data();}
template<> inline PITime PIVariant::value() const {return toTime();}
template<> inline PIDate PIVariant::value() const {return toDate();}
template<> inline PIDateTime PIVariant::value() const {return toDateTime();}
template<> inline PISystemTime PIVariant::value() const {return toSystemTime();}
template<> inline PIString PIVariant::value() const {return toString();}
template<> inline PIStringList PIVariant::value() const {return toStringList();}
template<> inline PIBitArray PIVariant::value() const {return toBitArray();}
template<> inline PIByteArray PIVariant::value() const {return toByteArray();}
template<> inline PIVariantTypes::Enum PIVariant::value() const {return toEnum();}
template<> inline PIVariantTypes::File PIVariant::value() const {return toFile();}
template<> inline PIVariantTypes::Dir PIVariant::value() const {return toDir();}
template<> inline PIVariantTypes::Color PIVariant::value() const {return toColor();}
template<> inline PIVariantTypes::IODevice PIVariant::value() const {return toIODevice();}
template<> inline PIPointd PIVariant::value() const {return toPoint();}
template<> inline PIRectd PIVariant::value() const {return toRect();}
template<> inline PILined PIVariant::value() const {return toLine();}
template<> inline PINetworkAddress PIVariant::value() const {return toNetworkAddress();}
template<> inline PIVariant PIVariant::value() const {return *this;}

template<> inline PIVariant PIVariant::fromValue(const bool & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const char & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const uchar & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const short & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const ushort & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const int & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const uint & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const llong & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const ullong & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const float & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const double & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const ldouble & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const complexf & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const complexd & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const complexld & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIBitArray & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIByteArray & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIString & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIStringList & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PITime & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIDate & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIDateTime & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PISystemTime & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Enum & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::File & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Dir & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::Color & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariantTypes::IODevice & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIPointd & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIRectd & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PILined & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PINetworkAddress & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIMathVectord & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIMathMatrixd & v) {return PIVariant(v);}
template<> inline PIVariant PIVariant::fromValue(const PIVariant & v) {return PIVariant(v);}

template<> inline PIVariant::Type PIVariant::getType<bool>() {return PIVariant::pivBool;}
template<> inline PIVariant::Type PIVariant::getType<char>() {return PIVariant::pivChar;}
template<> inline PIVariant::Type PIVariant::getType<uchar>() {return PIVariant::pivUChar;}
template<> inline PIVariant::Type PIVariant::getType<short>() {return PIVariant::pivShort;}
template<> inline PIVariant::Type PIVariant::getType<ushort>() {return PIVariant::pivUShort;}
template<> inline PIVariant::Type PIVariant::getType<int>() {return PIVariant::pivInt;}
template<> inline PIVariant::Type PIVariant::getType<uint>() {return PIVariant::pivUInt;}
template<> inline PIVariant::Type PIVariant::getType<llong>() {return PIVariant::pivLLong;}
template<> inline PIVariant::Type PIVariant::getType<ullong>() {return PIVariant::pivULLong;}
template<> inline PIVariant::Type PIVariant::getType<float>() {return PIVariant::pivFloat;}
template<> inline PIVariant::Type PIVariant::getType<double>() {return PIVariant::pivDouble;}
template<> inline PIVariant::Type PIVariant::getType<ldouble>() {return PIVariant::pivLDouble;}
template<> inline PIVariant::Type PIVariant::getType<complexf>() {return PIVariant:: pivComplexf;}
template<> inline PIVariant::Type PIVariant::getType<complexd>() {return PIVariant:: pivComplexd;}
template<> inline PIVariant::Type PIVariant::getType<complexld>() {return PIVariant::pivComplexld;}
template<> inline PIVariant::Type PIVariant::getType<PIBitArray>() {return PIVariant::pivBitArray;}
template<> inline PIVariant::Type PIVariant::getType<PIByteArray>() {return PIVariant::pivByteArray;}
template<> inline PIVariant::Type PIVariant::getType<PIString>() {return PIVariant::pivString;}
template<> inline PIVariant::Type PIVariant::getType<PIStringList>() {return PIVariant::pivStringList;}
template<> inline PIVariant::Type PIVariant::getType<PITime>() {return PIVariant::pivTime;}
template<> inline PIVariant::Type PIVariant::getType<PIDate>() {return PIVariant::pivDate;}
template<> inline PIVariant::Type PIVariant::getType<PIDateTime>() {return PIVariant::pivDateTime;}
template<> inline PIVariant::Type PIVariant::getType<PISystemTime>() {return PIVariant::pivSystemTime;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Enum>() {return PIVariant::pivEnum;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::File>() {return PIVariant::pivFile;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Dir>() {return PIVariant::pivDir;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::Color>() {return PIVariant::pivColor;}
template<> inline PIVariant::Type PIVariant::getType<PIVariantTypes::IODevice>() {return PIVariant::pivIODevice;}
template<> inline PIVariant::Type PIVariant::getType<PIPointd>() {return PIVariant::pivPoint;}
template<> inline PIVariant::Type PIVariant::getType<PIRectd>() {return PIVariant::pivRect;}
template<> inline PIVariant::Type PIVariant::getType<PILined>() {return PIVariant::pivLine;}
template<> inline PIVariant::Type PIVariant::getType<PINetworkAddress>() {return PIVariant::pivNetworkAddress;}
template<> inline PIVariant::Type PIVariant::getType<PIMathVectord>() {return PIVariant::pivMathVector;}
template<> inline PIVariant::Type PIVariant::getType<PIMathMatrixd>() {return PIVariant::pivMathMatrix;}
// clang-format on

REGISTER_VARIANT(bool)
REGISTER_VARIANT(char)
REGISTER_VARIANT(uchar)
REGISTER_VARIANT(short)
REGISTER_VARIANT(ushort)
REGISTER_VARIANT(int)
REGISTER_VARIANT(uint)
REGISTER_VARIANT(llong)
REGISTER_VARIANT(ullong)
REGISTER_VARIANT(float)
REGISTER_VARIANT(double)
REGISTER_VARIANT(ldouble)
REGISTER_VARIANT(complexf)
REGISTER_VARIANT(complexd)
REGISTER_VARIANT(complexld)
REGISTER_VARIANT(PIBitArray)
REGISTER_VARIANT(PIByteArray)
REGISTER_VARIANT(PIString)
REGISTER_VARIANT(PIStringList)
REGISTER_VARIANT(PITime)
REGISTER_VARIANT(PIDate)
REGISTER_VARIANT(PIDateTime)
REGISTER_VARIANT(PISystemTime)
REGISTER_VARIANT(PIVariantTypes::Enum)
REGISTER_VARIANT(PIVariantTypes::File)
REGISTER_VARIANT(PIVariantTypes::Dir)
REGISTER_VARIANT(PIVariantTypes::Color)
REGISTER_VARIANT(PIVariantTypes::IODevice)
REGISTER_VARIANT(PIPointd)
REGISTER_VARIANT(PIRectd)
REGISTER_VARIANT(PILined)
REGISTER_VARIANT(PINetworkAddress)
REGISTER_VARIANT(PIMathVectord)
REGISTER_VARIANT(PIMathMatrixd)
REGISTER_VARIANT(PIVariantMap);
REGISTER_VARIANT(PIVariantVector);

REGISTER_VARIANT(PIGeoPosition);
REGISTER_VARIANT_CAST(PIGeoPosition, PIString) {
	PIGeoPosition g(v);
	g.setEllipsoidModel(PIEllipsoidModel::WGS84Ellipsoid());
	g.transformTo(PIGeoPosition::Geodetic);
	return PIString::fromNumber(g.latitudeGeodetic(), 'f', 8) + ", " + PIString::fromNumber(g.longitude(), 'f', 8) + ", " +
	       PIString::fromNumber(g.height(), 'f', 2);
};

REGISTER_VARIANT_CAST(PIString, PIGeoPosition) {
	PIStringList sl = v.split(",");
	if (sl.size() == 2) sl << "0";
	if (sl.size() >= 3) {
		return PIGeoPosition({sl[0].toDouble(), sl[1].toDouble(), sl[2].toDouble()}, PIGeoPosition::Geodetic);
	}
	sl = v.split(";");
	if (sl.size() == 2) sl << "0";
	if (sl.size() >= 3) {
		return PIGeoPosition({sl[0].toDouble(), sl[1].toDouble(), sl[2].toDouble()}, PIGeoPosition::Geodetic);
	}
	return PIGeoPosition({0., 0., 0.}, PIGeoPosition::Geodetic);
};


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIVariant) {
	s << v._content << v._type;
	if (v._type == PIVariant::pivCustom) {
#ifdef CUSTOM_PIVARIANT
		if (v._info) {
			s << v._info->typeName;
		} else {
			s << PIStringAscii("");
		}
#else
		s << PIStringAscii("");
#endif
	}
	return s;
}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ(PIVariant) {
	s >> v._content >> v._type;
	if (v._type == PIVariant::pivCustom) {
		PIString tn;
		s >> tn;
#ifdef CUSTOM_PIVARIANT
		PIByteArray vc = v._content;
		v              = PIVariant::fromValue(vc, tn);
#endif
	} else {
		v._typeID = PIVariant::typeIDFromType(v._type);
	}
	return s;
}

//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator<<(PICout s, const PIVariant & v) {
	s.space();
	s.saveAndSetControls(0);
	s << "PIVariant(" << v.typeName();
	if (v.isValid()) s << ", " << v.toString();
	s << ")";
	s.restoreControls();
	return s;
}


#endif // PIVARIANT_H
