#include "blockbase.h"
#include "alignedtextitem.h"
#include "qvariantedit.h"


QVariant::Type typeFromLetter(const QString & l) {
	if (l.isEmpty()) return QVariant::String;
	QString ft = l.left(1);
	if (ft == "l") return QVariant::StringList;
	if (ft == "b") return QVariant::Bool;
	if (ft == "n") return QVariant::Int;
	if (ft == "f") return QVariant::Double;
	if (ft == "c") return QVariant::Color;
	if (ft == "r") return QVariant::Rect;
	if (ft == "a") return QVariant::RectF;
	if (ft == "p") return QVariant::Point;
	if (ft == "v") return QVariant::PointF;
	if (ft == "e") return (QVariant::Type)qMetaTypeId<QVariantEdit::EnumType>();
	if (ft == "F") return (QVariant::Type)qMetaTypeId<QVariantEdit::FileType>();
	if (ft == "D") return (QVariant::Type)qMetaTypeId<QVariantEdit::DirType>();
	return QVariant::String;
}


QString uniqueName(QString n, const QStringList & names) {
	if (!names.contains(n))
		return n;
	QString num;
	while (!n.isEmpty()) {
		if (n.right(1)[0].isDigit()) {
			num.push_front(n.right(1));
			n.chop(1);
		} else break;
	}
	if (!n.endsWith('_')) n += '_';
	int in = num.toInt() + 1;
	QString nn = n + QString::number(in).rightJustified(3, '0');
	while (names.contains(nn))
		nn = n + QString::number(++in).rightJustified(3, '0');
	return nn;
}


QDataStream & operator <<(QDataStream & s, const QGraphicsItem * item) {
	if (!item) {
		s << int(-1);
		return s;
	}
	const QGraphicsRectItem * irect = qgraphicsitem_cast<const QGraphicsRectItem*>(item);
	const QGraphicsEllipseItem * iell = qgraphicsitem_cast<const QGraphicsEllipseItem*>(item);
	const QGraphicsSimpleTextItem * itext = qgraphicsitem_cast<const QGraphicsSimpleTextItem*>(item);
	const AlignedTextItem * iatext = qgraphicsitem_cast<const AlignedTextItem*>(item);
	const QGraphicsLineItem * iline = qgraphicsitem_cast<const QGraphicsLineItem*>(item);
	const QGraphicsPathItem * ipath = qgraphicsitem_cast<const QGraphicsPathItem*>(item);
	const QGraphicsPixmapItem * ipixmap = qgraphicsitem_cast<const QGraphicsPixmapItem*>(item);
	if (irect) {
		s << int(0) << (irect->pen()) << (irect->brush()) << (irect->rect());
	} else if (iell) {
		s << int(1) << (iell->pen()) << (iell->brush()) << (iell->rect());
	} else if (itext) {
		s << int(2) << (itext->pen()) << (itext->brush()) << (itext->font()) << (itext->text());
	} else if (iatext) {
		s << int(6) << (iatext->pen()) << (iatext->brush()) << (iatext->font()) << (iatext->text()) << int(iatext->alignment());
	} else if (iline) {
		s << int(3) << (iline->pen()) << (iline->line());
	} else if (ipath) {
		s << int(4) << (ipath->pen()) << (ipath->path());
	} else if (ipixmap) {
		s << int(5) << (ipixmap->pixmap());
	} else {
		s << int(-1);
	}
	s << (item->pos()) << (item->rotation()) << int(item->flags());
	return s;
}


QDataStream & operator >>(QDataStream & s, QGraphicsItem *& item) {
	int type_; s >> type_;
	if (type_ < 0) {
		item = 0;
		return s;
	}
	QGraphicsRectItem * nrect = 0;
	QGraphicsEllipseItem * nell = 0;
	QGraphicsSimpleTextItem * ntext = 0;
	AlignedTextItem * natext = 0;
	QGraphicsLineItem * nline = 0;
	QGraphicsPathItem * npath = 0;
	QGraphicsPixmapItem * npixmap = 0;
	item = 0;
	switch (type_) {
	case 0:
		nrect = new QGraphicsRectItem(); item = nrect;
		{QPen _v; s >> _v; nrect->setPen(_v);}
		{QBrush _v; s >> _v; nrect->setBrush(_v);}
		{QRectF _v; s >> _v; nrect->setRect(_v);}
		break;
	case 1:
		nell = new QGraphicsEllipseItem(); item = nell;
		{QPen _v; s >> _v; nell->setPen(_v);}
		{QBrush _v; s >> _v; nell->setBrush(_v);}
		{QRectF _v; s >> _v; nell->setRect(_v);}
		break;
	case 2:
		ntext = new QGraphicsSimpleTextItem(); item = ntext;
		{QPen _v; s >> _v; ntext->setPen(_v);}
		{QBrush _v; s >> _v; ntext->setBrush(_v);}
		{QFont _v; s >> _v; ntext->setFont(_v);}
		{QString _v; s >> _v; ntext->setText(_v);}
		break;
	case 6:
		natext = new AlignedTextItem(); item = natext;
		{QPen _v; s >> _v; natext->setPen(_v);}
		{QBrush _v; s >> _v; natext->setBrush(_v);}
		{QFont _v; s >> _v; natext->setFont(_v);}
		{QString _v; s >> _v; natext->setText(_v);}
		{int _v; s >> _v; natext->setAlignment((Qt::AlignmentFlag)_v);}
		break;
	case 3:
		nline = new QGraphicsLineItem(); item = nline;
		{QPen _v; s >> _v; nline->setPen(_v);}
		{QLineF _v; s >> _v; nline->setLine(_v);}
		break;
	case 4:
		npath = new QGraphicsPathItem(); item = npath;
		{QPen _v; s >> _v; npath->setPen(_v);}
		{QPainterPath _v; s >> _v; npath->setPath(_v);}
		break;
	case 5:
		npixmap = new QGraphicsPixmapItem(); item = npixmap;
		{QPixmap _v; s >> _v; npixmap->setPixmap(_v);}
		break;
	}
	if (item) {
		{QPointF _v; s >> _v; item->setPos(_v);}
		{qreal _v; s >> _v; item->setRotation(_v);}
		{int _v; s >> _v; item->setFlags((QGraphicsItem::GraphicsItemFlags)_v);}
	}
	return s;
}




bool PropertyStorage::isPropertyExists(const QString & _name) const {
	for (int i = 0; i < props.size(); ++i)
		if (props[i].name == _name)
			return true;
	return false;
}


void PropertyStorage::addProperty(const PropertyStorage::Property & p) {
	for (int i = 0; i < props.size(); ++i)
		if (props[i].name == p.name) {
			props[i] = p;
			return;
		}
	props << p;
}


void PropertyStorage::removeProperty(const QString & _name) {
	for (int i = 0; i < props.size(); ++i)
		if (props[i].name == _name) {
			props.removeAt(i);
			return;
		}
}


void PropertyStorage::removePropertiesByFlag(int flag) {
	for (int i = 0; i < props.size(); ++i)
		if ((props[i].flags & flag) == flag) {
			props.removeAt(i);
			--i;
		}
}


void PropertyStorage::updateProperties(const QList<PropertyStorage::Property> & properties_, int flag_ignore) {
	QVariantMap values;
	foreach (const PropertyStorage::Property & p, props)
		if (((p.flags & flag_ignore) != flag_ignore) || (flag_ignore == 0))
			values[p.name] = p.value;
	props = properties_;
	for (int i = 0; i < props.size(); ++i) {
		PropertyStorage::Property & p(props[i]);
		if (values.contains(p.name)) {
			QVariant pv = values[p.name];
			if (pv.userType() == p.value.userType())
				p.value = pv;
		}
	}
}


PropertyStorage::Property PropertyStorage::propertyByName(const QString & name) const {
	foreach (const Property & p, props)
		if (p.name == name)
			return p;
	return Property();
}


QVariant PropertyStorage::propertyValueByName(const QString & name) const {
	foreach (const Property & p, props)
		if (p.name == name)
			return p.value;
	return QVariant();
}


void PropertyStorage::setPropertyValue(const QString & name, const QVariant & value) {
	for (int i = 0; i < props.size(); ++i)
		if (props[i].name == name) {
			props[i].value = value;
			return;
		}
}


void PropertyStorage::setPropertyComment(const QString & name, const QString & comment) {
	for (int i = 0; i < props.size(); ++i)
		if (props[i].name == name) {
			props[i].comment = comment;
			return;
		}
}


void PropertyStorage::setPropertyFlags(const QString & name, int flags) {
	for (int i = 0; i < props.size(); ++i)
		if (props[i].name == name) {
			props[i].flags = flags;
			return;
		}
}


PropertyStorage::Property PropertyStorage::parsePropertyLine(QString l) {
	PropertyStorage::Property ret;
	QString pn, pc, pt("s"), pv;
	if (l.contains('#')) {
		int i = l.indexOf('#');
		pn = l.left(i).trimmed();
		pc = l.right(l.length() - i - 1).trimmed();
	} else {
		if (l.contains('(')) {
			int bs = l.indexOf('('), be = l.indexOf(')');
			if (be > 0) {
				pc = l.mid(bs + 1, be - bs - 1).trimmed();
				l.remove(bs, be - bs + 1);
			} else {
				pc = l.right(l.length() - bs - 1).trimmed();
				l = l.left(bs);
			}
		}
		pn = l.trimmed();
	}
	if (!pc.isEmpty()) {
		pt = pc.left(1);
		pc = pc.remove(0, 1).trimmed();
	}
	if (pn.contains('=')) {
		int i = pn.indexOf('=');
		pv = pn.right(pn.length() - i - 1).trimmed();
		pn.truncate(i);
		pn = pn.trimmed();
	}
	ret.name = pn;
	ret.comment = pc;
	ret.value = QVariant(typeFromLetter(pt));
	if (!pv.isEmpty()) {
		//qDebug() << "set value !" << pv;
		switch (ret.value.type()) {
			case QVariant::Bool: pv = pv.toLower(); ret.value = (pv == "on" || pv == "true" || pv == "enable" || pv == "enabled" || pv.toInt() > 0 ? true : false); break;
			case QVariant::Int: ret.value = pv.toInt(); break;
			case QVariant::UInt: ret.value = pv.toUInt(); break;
			case QVariant::LongLong: ret.value = pv.toLongLong(); break;
			case QVariant::ULongLong: ret.value = pv.toULongLong(); break;
			case QVariant::Double: ret.value = pv.toDouble(); break;
			case QVariant::Color: ret.value = QColor(pv); break;
			default: ret.value = pv; break;
		};
	}
	return ret;
}
