/*
    PIQt - PIP <-> Qt convertions

    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 PIQT_H
#define PIQT_H

#include "pimathmatrix.h"
#include "pipropertystorage.h"
#include "piqt_macros.h"
#include "qad_types.h"

#include <QColor>
#include <QDateTime>
#include <QGenericMatrix>
#include <QImage>
#include <QMatrix4x4>
#include <QPolygonF>
#include <QVector2D>
#include <QVector3D>
#if QT_VERSION_MAJOR == 5
#  if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
#	define PIQT_HAS_GEOPOSITION
#  endif
#endif
#if QT_VERSION_MAJOR == 6
#  if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
#	define PIQT_HAS_GEOPOSITION
#  endif
#endif
#ifdef PIQT_HAS_GEOPOSITION
class QGeoCoordinate;
class PIGeoPosition;
#endif
#include "qad_piqt_export.h"


QAD_PIQT_EXPORT QVariant PI2QVariant(const PIVariant & v);
QAD_PIQT_EXPORT PIVariant Q2PIVariant(const QVariant & v);

// inline QString PI2QString(const PIString & v) {return QString::fromLocal8Bit(v.data());}
inline QString PI2QString(const PIString & v) {
	if (v.isEmpty()) return QString();
	return QString::fromUtf8(v.dataUTF8());
}
#if PIP_VERSION >= PIP_MAKE_VERSION(2, 38, 0)
inline QString PI2QString(const PIConstChars & v) {
	if (v.isEmpty()) return QString();
	return QString::fromLatin1(v.data(), v.length());
}
#endif

// inline PIString Q2PIString(const QString & v) {return PIString(v.toLocal8Bit().data());}
inline PIString Q2PIString(const QString & v) {
	if (v.isEmpty()) return PIString();
	auto qba = v.toUtf8();
	return PIString::fromUTF8(qba.constData(), qba.size());
}


inline QStringList PI2QStringList(const PIStringList & v) {
	if (v.isEmpty()) return QStringList();
	QStringList ret;
	for (const auto & s: v)
		ret << PI2QString(s);
	return ret;
}

inline PIStringList Q2PIStringList(const QStringList & v) {
	if (v.isEmpty()) return PIStringList();
	PIStringList ret;
	ret.reserve(v.size());
	for (const auto & s: v)
		ret << Q2PIString(s);
	return ret;
}


inline QByteArray PI2QByteArray(const PIByteArray & v) {
	if (v.isEmpty()) return QByteArray();
	return QByteArray((const char *)(v.data()), v.size_s());
}

inline PIByteArray Q2PIByteArray(const QByteArray & v) {
	if (v.isEmpty()) return PIByteArray();
	return PIByteArray(v.constData(), v.size());
}


inline QPointF PI2QVector2(const PIMathVectorT2d & v) {
	return QPointF(v[0], v[1]);
}
inline QVector3D PI2QVector3(const PIMathVectorT3d & v) {
	return QVector3D(v[0], v[1], v[2]);
}

inline PIMathVectorT2d Q2PIVector2(const QPointF & v) {
	return PIMathVectorT2d({double(v.x()), double(v.y())});
}
inline PIMathVectorT3d Q2PIVector3(const QVector3D & v) {
	return PIMathVectorT3d({double(v.x()), double(v.y()), double(v.z())});
}

template<uint Rows, uint Cols = Rows, typename Type = double>
inline QGenericMatrix<Cols, Rows, Type> PI2QMathMatrixT(const PIMathMatrixT<Rows, Cols, Type> & v) {
	QGenericMatrix<Cols, Rows, Type> ret;
	for (int r = 0; r < Rows; ++r)
		for (int c = 0; c < Cols; ++c)
			ret(r, c) = v[r][c];
	return ret;
}

template<int Rows, int Cols = Rows, typename Type = double>
inline PIMathMatrixT<Rows, Cols, Type> Q2PIMathMatrixT(const QGenericMatrix<Cols, Rows, Type> & v) {
	PIMathMatrixT<Rows, Cols, Type> ret;
	for (int r = 0; r < Rows; ++r)
		for (int c = 0; c < Cols; ++c)
			ret[r][c] = v(r, c);
	return ret;
}
inline PIMathMatrixT<4, 4, float> Q2PIMathMatrixT(const QMatrix4x4 & v) {
	PIMathMatrixT<4, 4, float> ret;
	for (int r = 0; r < 4; ++r)
		for (int c = 0; c < 4; ++c)
			ret[r][c] = v(r, c);
	return ret;
}


inline PIMathVectorT2d Q2PIMathVectorT(const QVector2D & v) {
	return PIMathVectorT2d({v[0], v[1]});
}
inline PIMathVectorT2d Q2PIMathVectorT(const QPointF & v) {
	return PIMathVectorT2d({v.x(), v.y()});
}
inline PIMathVectorT3d Q2PIMathVectorT(const QVector3D & v) {
	return PIMathVectorT3d({v[0], v[1], v[2]});
}
inline PIMathVectorT4d Q2PIMathVectorT(const QVector4D & v) {
	return PIMathVectorT4d({v[0], v[1], v[2], v[3]});
}
template<int Size, typename Type = double>
inline PIMathVectorT<Size, double> Q2PIMathVectorT(const QGenericMatrix<1, Size, Type> & v) {
	PIMathVectorT<Size, double> ret;
	for (int i = 0; i < Size; ++i)
		ret[i] = v(i, 0);
	return ret;
}
template<int Size, typename Type = double>
inline PIMathVectorT<Size, double> Q2PIMathVectorT(const QGenericMatrix<Size, 1, Type> & v) {
	PIMathVectorT<Size, double> ret;
	for (int i = 0; i < Size; ++i)
		ret[i] = v(0, i);
	return ret;
}


inline QPointF PI2QPoint(const PIPointd & v) {
	return QPointF(v.x, v.y);
}
inline PIPointd Q2PIPoint(const QPointF & v) {
	return PIPointd(v.x(), v.y());
}

inline QRectF PI2QRect(const PIRectd & v) {
	return QRectF(v.left(), v.bottom(), v.width(), v.height());
}
inline PIRectd Q2PIRect(const QRectF & v) {
	return PIRectd(v.left(), v.top(), v.width(), v.height());
}

inline QLineF PI2QLine(const PILined & v) {
	return QLineF(PI2QPoint(v.p0), PI2QPoint(v.p1));
}
inline PILined Q2PILine(const QLineF & v) {
	return PILined(Q2PIPoint(v.p1()), Q2PIPoint(v.p2()));
}

inline QAD::MathVector PI2QMathVector(const PIMathVectord & v) {
	QVector<double> q = QVector<double>(v.size());
	memcpy(q.data(), v.data(), q.size() * sizeof(double));
	return QAD::MathVector(q);
}
inline PIMathVectord Q2PIMathVector(const QAD::MathVector & v) {
	PIMathVectord p = PIMathVectord(v.v.size());
	memcpy(p.data(), v.v.data(), p.size() * sizeof(double));
	return p;
}

inline QAD::MathMatrix PI2QMathMatrix(const PIMathMatrixd & v) {
	PIVector<PIVector<double>> p = v.toVectors();
	QVector<QVector<double>> q   = QVector<QVector<double>>(p.size());
	for (int i = 0; i < q.size(); ++i) {
		q[i].resize(p[i].size());
		memcpy(q[i].data(), p[i].data(), q[i].size() * sizeof(double));
	}
	return QAD::MathMatrix(q);
}
inline PIMathMatrixd Q2PIMathMatrix(const QAD::MathMatrix & v) {
	PIVector<PIVector<double>> p = PIVector<PIVector<double>>(v.m.size());
	for (int i = 0; i < v.m.size(); ++i) {
		p[i].resize(v.m[i].size());
		memcpy(p[i].data(), v.m[i].data(), p[i].size() * sizeof(double));
	}
	return PIMathMatrixd(p);
}


inline QDate PI2QDate(const PIDate & v) {
	return QDate(v.year, v.month, v.day);
}
inline QTime PI2QTime(const PITime & v) {
	return QTime(v.hours, v.minutes, v.seconds, v.milliseconds);
}
inline QDateTime PI2QDateTime(const PIDateTime & v) {
	return QDateTime(PI2QDate(v.date()), PI2QTime(v.time()));
}

inline PIDate Q2PIDate(const QDate & v) {
	return PIDate(v.year(), v.month(), v.day());
}
inline PITime Q2PITime(const QTime & v) {
	return PITime(v.hour(), v.minute(), v.second(), v.msec());
}
inline PIDateTime Q2PIDateTime(const QDateTime & v) {
	return PIDateTime(Q2PIDate(v.date()), Q2PITime(v.time()));
}


inline QColor PI2QColor(const PIVariantTypes::Color & v) {
	return QColor::fromRgba(v.rgba);
}
inline PIVariantTypes::Color Q2PIColor(const QColor & v) {
	return PIVariantTypes::Color(v.rgba());
}


template<typename T>
inline QVector<T> PI2QVector(const PIVector<T> & v) {
	QVector<T> ret;
	ret.reserve(v.size_s());
	for (int i = 0; i < v.size_s(); ++i)
		ret << v[i];
	return ret;
}
#if QT_VERSION_MAJOR == 5
template<typename T>
inline PIVector<T> Q2PIVector(const QVector<T> & v) {
	if (v.isEmpty()) return PIVector<T>();
	return PIVector<T>(v.constData(), (size_t)v.size());
}
#endif
template<typename T>
inline PIVector<T> Q2PIVector(const QList<T> & v) {
	if (v.isEmpty()) return PIVector<T>();
	PIVector<T> ret;
	ret.reserve(v.size());
	for (const auto & i: v)
		ret << i;
	return ret;
}

template<typename K, typename T>
inline QMap<K, T> PI2QMap(const PIMap<K, T> & v) {
	QMap<K, T> ret;
	auto it = v.makeIterator();
	while (it.hasNext()) {
		it.next();
		ret[it.key()] = it.value();
	}
	return ret;
}
template<typename K, typename T>
inline PIMap<K, T> Q2PIMap(const QMap<K, T> & v) {
	PIMap<K, T> ret;
	ret.reserve((size_t)v.size());
	QMapIterator<K, T> it(v);
	while (it.hasNext()) {
		it.next();
		ret[it.key()] = it.value();
	}
	return ret;
}


inline PIPropertyStorage Q2PIPropertyStorage(const PropertyStorage & props) {
	PIPropertyStorage ret;
	for (const auto & p: props)
		ret.addProperty(Q2PIString(p.name), Q2PIVariant(p.value), Q2PIString(p.comment), p.flags);
	return ret;
}

inline PropertyStorage PI2QPropertyStorage(const PIPropertyStorage & props) {
	PropertyStorage ret;
	for (const auto & p: props)
		ret.addProperty(PI2QString(p.name), PI2QVariant(p.value), PI2QString(p.comment), p.flags);
	return ret;
}


QAD_PIQT_EXPORT QAD::Enum PI2QADEnum(const PIVariantTypes::Enum & el);
QAD_PIQT_EXPORT QAD::File PI2QADFile(const PIVariantTypes::File & v);
QAD_PIQT_EXPORT QAD::Dir PI2QADDir(const PIVariantTypes::Dir & v);
QAD_PIQT_EXPORT QAD::IODevice PI2QADIODevice(const PIVariantTypes::IODevice & v);
QAD_PIQT_EXPORT PIVariantTypes::Enum QAD2PIEnum(const QAD::Enum & el);
QAD_PIQT_EXPORT PIVariantTypes::File QAD2PIFile(const QAD::File & v);
QAD_PIQT_EXPORT PIVariantTypes::Dir QAD2PIDir(const QAD::Dir & v);
QAD_PIQT_EXPORT PIVariantTypes::IODevice QAD2PIIODevice(const QAD::IODevice & v);

// inline PIVariant QString2PIVariant(const QString & v) {return PIVariant::readFromString(QString2PIString(v));}

#ifdef PIQT_HAS_GEOPOSITION
QAD_PIQT_EXPORT QGeoCoordinate PI2QGeoPosition(const PIGeoPosition & v);
QAD_PIQT_EXPORT PIGeoPosition Q2PIGeoPosition(const QGeoCoordinate & v);
#endif

template<typename From>
class __PIQtConverter {
public:
	__PIQtConverter(const From & v): val(v) {}
	template<typename To>
	operator To() {
		return To();
	}
	From val;
};
template<typename From>
inline __PIQtConverter<From> __PIQtConvert(const From & f) {
	return __PIQtConverter<From>(f);
}

#define _PIQt_CONVERT(ft, tt, ftc, tfc)         \
	template<>                                  \
	template<>                                  \
	inline __PIQtConverter<ft>::operator tt() { \
		return ftc(val);                        \
	}                                           \
	template<>                                  \
	template<>                                  \
	inline __PIQtConverter<tt>::operator ft() { \
		return tfc(val);                        \
	}
#define _PIQt_CONVERT_S(t) _PIQt_CONVERT(PI##t, Q##t, PI2Q##t, Q2PI##t)

_PIQt_CONVERT_S(String) _PIQt_CONVERT_S(ByteArray) _PIQt_CONVERT_S(Time) _PIQt_CONVERT_S(Date) _PIQt_CONVERT_S(DateTime)
	_PIQt_CONVERT(PIMathVectorT2d, QPointF, PI2QVector2, Q2PIVector2) _PIQt_CONVERT(PIMathVectorT3d, QVector3D, PI2QVector3, Q2PIVector3)
#define piqt __PIQtConvert
#define qtpi __PIQtConvert


#ifndef PIP_BINARY_STREAM

		inline PIByteArray &
		operator<<(PIByteArray & s, const QString & v) {
	s << Q2PIString(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QString & v) {
	PIString t;
	s >> t;
	v = PI2QString(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QStringList & v) {
	s << Q2PIStringList(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QStringList & v) {
	PIStringList t;
	s >> t;
	v = PI2QStringList(t);
	return s;
}
template<typename T>
inline PIByteArray & operator<<(PIByteArray & s, const QVector<T> & v) {
	s << PIVector<T>(v.constData(), (size_t)v.size());
	return s;
}
template<typename T>
inline PIByteArray & operator>>(PIByteArray & s, QVector<T> & v) {
	PIVector<T> t;
	s >> t;
	v.resize(t.size_s());
	for (int i = 0; i < t.size_s(); ++i)
		v[i] = t[i];
	return s;
}
template<typename K, typename T>
inline PIByteArray & operator<<(PIByteArray & s, const QMap<K, T> & v) {
	PIMap<K, T> t;
	t.reserve(v.size());
	QMapIterator<K, T> it(v);
	while (it.hasNext()) {
		it.next();
		t[it.key()] = it.value();
	}
	s << t;
	return s;
}
template<typename K, typename T>
inline PIByteArray & operator>>(PIByteArray & s, QMap<K, T> & v) {
	v.clear();
	PIMap<K, T> t;
	s >> t;
	auto it = t.makeIterator();
	while (it.hasNext()) {
		it.next();
		v[it.key()] = it.value();
	}
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QPolygonF & v) {
	s << (QVector<QPointF>)v;
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QPolygonF & v) {
	QVector<QPointF> t;
	s >> t;
	v = t;
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QByteArray & v) {
	s << Q2PIByteArray(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QByteArray & v) {
	PIByteArray t;
	s >> t;
	v = PI2QByteArray(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QDate & v) {
	s << Q2PIDate(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QDate & v) {
	PIDate t;
	s >> t;
	v = PI2QDate(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QTime & v) {
	s << Q2PITime(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QTime & v) {
	PITime t;
	s >> t;
	v = PI2QTime(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QDateTime & v) {
	s << Q2PIDateTime(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QDateTime & v) {
	PIDateTime t;
	s >> t;
	v = PI2QDateTime(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QVariant & v) {
	s << Q2PIVariant(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QVariant & v) {
	PIVariant t;
	s >> t;
	v = PI2QVariant(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const PropertyStorage & v) {
	s << Q2PIPropertyStorage(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, PropertyStorage & v) {
	PIPropertyStorage t;
	s >> t;
	v = PI2QPropertyStorage(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QColor & v) {
	s << Q2PIColor(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QColor & v) {
	PIVariantTypes::Color t;
	s >> t;
	v = PI2QColor(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QAD::Enum & v) {
	s << QAD2PIEnum(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QAD::Enum & v) {
	PIVariantTypes::Enum t;
	s >> t;
	v = PI2QADEnum(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QAD::File & v) {
	s << QAD2PIFile(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QAD::File & v) {
	PIVariantTypes::File t;
	s >> t;
	v = PI2QADFile(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QAD::Dir & v) {
	s << QAD2PIDir(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QAD::Dir & v) {
	PIVariantTypes::Dir t;
	s >> t;
	v = PI2QADDir(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QAD::IODevice & v) {
	s << QAD2PIIODevice(v);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QAD::IODevice & v) {
	PIVariantTypes::IODevice t;
	s >> t;
	v = PI2QADIODevice(t);
	return s;
}
inline PIByteArray & operator<<(PIByteArray & s, const QImage & v) {
	QByteArray ba;
	QBuffer buf(&ba);
	v.save(&buf, "png");
	s << Q2PIByteArray(ba);
	return s;
}
inline PIByteArray & operator>>(PIByteArray & s, QImage & v) {
	PIByteArray pba;
	s >> pba;
	QByteArray ba = PI2QByteArray(pba);
	if (!v.loadFromData(ba, "png")) v = QImage();
	return s;
}

#else

		template<typename P, typename T>
		inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const QVector<T> & v) {
	s << PIVector<T>(v.constData(), (size_t)v.size());
	return s;
}
template<typename P, typename T>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, QVector<T> & v) {
	PIVector<T> t;
	s >> t;
	v.resize(t.size_s());
	for (int i = 0; i < t.size_s(); ++i)
		v[i] = t[i];
	return s;
}

template<typename P, typename K, typename T>
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const QMap<K, T> & v) {
	PIMap<K, T> t;
	t.reserve(v.size());
	QMapIterator<K, T> it(v);
	while (it.hasNext()) {
		it.next();
		t[it.key()] = it.value();
	}
	s << t;
	return s;
}
template<typename P, typename K, typename T>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, QMap<K, T> & v) {
	v.clear();
	PIMap<K, T> t;
	s >> t;
	auto it = t.makeIterator();
	while (it.hasNext()) {
		it.next();
		v[it.key()] = it.value();
	}
	return s;
}

BINARY_STREAM_WRITE(QString) {
	s << Q2PIString(v);
	return s;
}
BINARY_STREAM_READ(QString) {
	PIString t;
	s >> t;
	v = PI2QString(t);
	return s;
}

BINARY_STREAM_WRITE(QStringList) {
	s << Q2PIStringList(v);
	return s;
}
BINARY_STREAM_READ(QStringList) {
	PIStringList t;
	s >> t;
	v = PI2QStringList(t);
	return s;
}

BINARY_STREAM_WRITE(QPolygonF) {
	s << (QVector<QPointF>)v;
	return s;
}
BINARY_STREAM_READ(QPolygonF) {
	QVector<QPointF> t;
	s >> t;
	v = t;
	return s;
}

BINARY_STREAM_WRITE(QByteArray) {
	s << Q2PIByteArray(v);
	return s;
}
BINARY_STREAM_READ(QByteArray) {
	PIByteArray t;
	s >> t;
	v = PI2QByteArray(t);
	return s;
}

BINARY_STREAM_WRITE(QDate) {
	s << Q2PIDate(v);
	return s;
}
BINARY_STREAM_READ(QDate) {
	PIDate t;
	s >> t;
	v = PI2QDate(t);
	return s;
}

BINARY_STREAM_WRITE(QTime) {
	s << Q2PITime(v);
	return s;
}
BINARY_STREAM_READ(QTime) {
	PITime t;
	s >> t;
	v = PI2QTime(t);
	return s;
}

BINARY_STREAM_WRITE(QDateTime) {
	s << Q2PIDateTime(v);
	return s;
}
BINARY_STREAM_READ(QDateTime) {
	PIDateTime t;
	s >> t;
	v = PI2QDateTime(t);
	return s;
}

BINARY_STREAM_WRITE(QVariant) {
	s << Q2PIVariant(v);
	return s;
}
BINARY_STREAM_READ(QVariant) {
	PIVariant t;
	s >> t;
	v = PI2QVariant(t);
	return s;
}

BINARY_STREAM_WRITE(PropertyStorage) {
	s << Q2PIPropertyStorage(v);
	return s;
}
BINARY_STREAM_READ(PropertyStorage) {
	PIPropertyStorage t;
	s >> t;
	v = PI2QPropertyStorage(t);
	return s;
}

BINARY_STREAM_WRITE(QColor) {
	s << Q2PIColor(v);
	return s;
}
BINARY_STREAM_READ(QColor) {
	PIVariantTypes::Color t;
	s >> t;
	v = PI2QColor(t);
	return s;
}

BINARY_STREAM_WRITE(QAD::Enum) {
	s << QAD2PIEnum(v);
	return s;
}
BINARY_STREAM_READ(QAD::Enum) {
	PIVariantTypes::Enum t;
	s >> t;
	v = PI2QADEnum(t);
	return s;
}

BINARY_STREAM_WRITE(QAD::File) {
	s << QAD2PIFile(v);
	return s;
}
BINARY_STREAM_READ(QAD::File) {
	PIVariantTypes::File t;
	s >> t;
	v = PI2QADFile(t);
	return s;
}

BINARY_STREAM_WRITE(QAD::Dir) {
	s << QAD2PIDir(v);
	return s;
}
BINARY_STREAM_READ(QAD::Dir) {
	PIVariantTypes::Dir t;
	s >> t;
	v = PI2QADDir(t);
	return s;
}

BINARY_STREAM_WRITE(QAD::IODevice) {
	s << QAD2PIIODevice(v);
	return s;
}
BINARY_STREAM_READ(QAD::IODevice) {
	PIVariantTypes::IODevice t;
	s >> t;
	v = PI2QADIODevice(t);
	return s;
}

BINARY_STREAM_WRITE(QImage) {
	QByteArray ba;
	QBuffer buf(&ba);
	v.save(&buf, "png");
	s << Q2PIByteArray(ba);
	return s;
}
BINARY_STREAM_READ(QImage) {
	PIByteArray pba;
	s >> pba;
	QByteArray ba = PI2QByteArray(pba);
	if (!v.loadFromData(ba, "png")) v = QImage();
	return s;
}

#endif


/// PIP with QByteArray


template<typename T>
QByteArray piqSerialize(const T & value) {
	PIByteArray ret;
	ret << value;
	return PI2QByteArray(ret);
}

template<typename T>
T piqDeserialize(const QByteArray & data) {
	T ret;
	if (!data.isEmpty()) {
		PIByteArray ba = Q2PIByteArray(data);
		ba >> ret;
	}
	return ret;
}


/// PICout with Qt


inline PICout operator<<(PICout s, const QVariant & v) {
	s << Q2PIVariant(v);
	return s;
}

inline PICout operator<<(PICout s, const QByteArray & v) {
	s << Q2PIByteArray(v);
	return s;
}

inline PICout operator<<(PICout s, const QString & v) {
	s << Q2PIString(v);
	return s;
}

inline PICout operator<<(PICout s, const QStringList & v) {
	s << Q2PIStringList(v);
	return s;
}

#if QT_VERSION_MAJOR == 5
template<typename T>
inline PICout operator<<(PICout s, const QVector<T> & v) {
	s << Q2PIVector(v);
	return s;
}
#endif

template<typename T>
inline PICout operator<<(PICout s, const QList<T> & v) {
	s << Q2PIVector(v);
	return s;
}

template<typename K, typename T>
inline PICout operator<<(PICout s, const QMap<K, T> & v) {
	s << Q2PIMap(v);
	return s;
}

inline PICout operator<<(PICout s, const QTime & v) {
	s << Q2PITime(v);
	return s;
}

inline PICout operator<<(PICout s, const QDate & v) {
	s << Q2PIDate(v);
	return s;
}

inline PICout operator<<(PICout s, const QDateTime & v) {
	s << Q2PIDateTime(v);
	return s;
}

inline PICout operator<<(PICout s, const QPoint & v) {
	s << Q2PIPoint(v);
	return s;
}

inline PICout operator<<(PICout s, const QPointF & v) {
	s << Q2PIPoint(v);
	return s;
}

inline PICout operator<<(PICout s, const QLine & v) {
	s << Q2PILine(v);
	return s;
}

inline PICout operator<<(PICout s, const QLineF & v) {
	s << Q2PILine(v);
	return s;
}

inline PICout operator<<(PICout s, const QRect & v) {
	s << Q2PIRect(v);
	return s;
}

inline PICout operator<<(PICout s, const QRectF & v) {
	s << Q2PIRect(v);
	return s;
}

inline PICout operator<<(PICout s, const QColor & v) {
	s << Q2PIColor(v);
	return s;
}

inline PICout operator<<(PICout s, const QVector2D & v) {
	s << PIMathVectorT2d({v[0], v[1]});
	return s;
}

inline PICout operator<<(PICout s, const QVector3D & v) {
	s << PIMathVectorT3d({v[0], v[1], v[2]});
	return s;
}

inline PICout operator<<(PICout s, const QVector4D & v) {
	s << PIMathVectorT4d({v[0], v[1], v[2], v[3]});
	return s;
}

template<int N, int M, typename T>
inline PICout operator<<(PICout s, const QGenericMatrix<N, M, T> & v) {
	s << Q2PIMathMatrixT(v);
	return s;
}

inline PICout operator<<(PICout s, const QMatrix4x4 & v) {
	s << Q2PIMathMatrixT(v);
	return s;
}

#ifdef PIQT_HAS_GEOPOSITION
inline PICout operator<<(PICout s, const QGeoCoordinate & v) {
	s << Q2PIGeoPosition(v);
	return s;
}
#endif

#endif // PIQT_H
