/*! \file pivaluetree.h
 * \ingroup Types
 * \brief
 * \~english Attributed values tree
 * \~russian Дерево атрибутированных значений
*/
/*
	PIP - Platform Independent Primitives
	Attributed values tree
	Ivan Pelipenko peri4ko@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 PIVALUETREE_H
#define PIVALUETREE_H

#include "pivariant.h"
#include "pichunkstream.h"


class PIP_EXPORT PIValueTree {
	BINARY_STREAM_FRIEND(PIValueTree);
	friend PICout operator <<(PICout s, const PIValueTree & v);
public:
	PIValueTree();
	PIValueTree(const PIVariant & v);
	PIValueTree(const PIString & n, const PIVariant & v, const PIVariantMap & a = PIVariantMap());

	static const char attributeHidden       [];
	static const char attributeReadOnly     [];
	static const char attributeIsLabel      [];

	static const char attributeArrayType    [];
	static const char attributeArrayMinCount[];
	static const char attributeArrayMaxCount[];
	static const char attributeArrayReorder [];
	static const char attributeArrayResize  [];

	static const char attributeMinimum      [];
	static const char attributeMaximum      [];
	static const char attributeSingleStep   [];
	static const char attributeDecimals     [];
	static const char attributePrefix       [];
	static const char attributeSuffix       [];
	//static constexpr char attribute[] = "";

	bool isNull() const {return _is_null;}
	bool isValid() const {return _value.isValid();}
	bool isArray() const {return _attributes.contains(attributeArrayType);}
	bool hasChildren() const {return _children.isNotEmpty();}

	const PIString & name() const {return _name;}
	void setName(const PIString & n);

	const PIString & comment() const {return _comment;}
	void setComment(const PIString & c);

	const PIVariant & value() const {return _value;}
	void setValue(const PIVariant & v);

	const PIVariantMap & attributes() const {return _attributes;}
	PIVariantMap & attributes() {return _attributes;}
	PIVariant attribute(const PIString & an, const PIVariant & def = PIVariant()) const {return _attributes.value(an, def);}
	void setAttribute(const PIString & n, const PIVariant & a);
	void mergeAttributes(const PIVariantMap & a);

	const PIVector<PIValueTree> & children() const {return _children;}
	void clearChildren() {_children.clear();}

	bool contains(const PIString & name) const;
	bool contains(const PIStringList & path) const;
	const PIValueTree & child(const PIString & name) const;
	PIValueTree & child(const PIString & name);
	PIValueTree & addChild(const PIValueTree & n);
	PIValueTree & addChildren(const PIVector<PIValueTree> & n);
	PIValueTree & remove(const PIString & name);

	PIValueTree & operator[](const PIString & name);
	PIValueTree & operator[](const PIStringList & path);
	const PIValueTree & operator[](const PIString & name) const {return child(name);}

private:
	static void print(PIString & s, const PIValueTree & v, PIString tab);
	static PIValueTree & nullValue();

	PIString _name;
	PIString _comment;
	PIVariantMap _attributes;
	PIVariant _value;
	PIVector<PIValueTree> _children;
	bool _is_null = false;

};


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIValueTree) {
	PIChunkStream cs;
	cs.add(1, v._name)
	  .add(2, v._comment)
	  .add(3, v._attributes)
	  .add(4, v._value)
	  .add(5, v._children);
	s << cs.data();
	return s;
}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ (PIValueTree) {
	PIByteArray csba; s >> csba;
	PIChunkStream cs(csba);
	while (!cs.atEnd()) {
		switch (cs.read()) {
		case 1: cs.get(v._name);
		case 2: cs.get(v._comment);
		case 3: cs.get(v._attributes);
		case 4: cs.get(v._value);
		case 5: cs.get(v._children);
		}
	}
	return s;
}

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


#endif // PIVALUETREE_H
