/*
	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/>.
*/

#include "pivaluetree.h"


//! \class PIValueTree pivaluetree.h
//! \details
//! \~english \section PIValueTree_sec0 Synopsis
//! \~russian \section PIValueTree_sec0 Краткий обзор
//! \~english
//!
//! \~russian
//!
//!
const char PIValueTree::attributeHidden       [] = "hidden"       ;
const char PIValueTree::attributeReadOnly     [] = "readOnly"     ;
const char PIValueTree::attributeIsLabel      [] = "label"        ;

const char PIValueTree::attributeArrayType    [] = "arrayType"    ;
const char PIValueTree::attributeArrayMinCount[] = "arrayMinCount";
const char PIValueTree::attributeArrayMaxCount[] = "arrayMaxCount";
const char PIValueTree::attributeArrayReorder [] = "arrayReorder" ;
const char PIValueTree::attributeArrayResize  [] = "arrayResize"  ;

const char PIValueTree::attributeMinimum      [] = "minimum"      ;
const char PIValueTree::attributeMaximum      [] = "maximum"      ;
const char PIValueTree::attributeSingleStep   [] = "singleStep"   ;
const char PIValueTree::attributeDecimals     [] = "decimals"     ;
const char PIValueTree::attributePrefix       [] = "prefix"       ;
const char PIValueTree::attributeSuffix       [] = "suffix"       ;


PIValueTree::PIValueTree() {
}


PIValueTree::PIValueTree(const PIVariant & v) {
	setValue(v);
}


PIValueTree::PIValueTree(const PIString & n, const PIVariant & v, const PIVariantMap & a) {
	setName(n);
	setValue(v);
	_attributes = a;
}


void PIValueTree::setName(const PIString & n) {
	if (_is_null) return;
	_name = n;
}


void PIValueTree::setComment(const PIString & c) {
	if (_is_null) return;
	_comment = c;
}


void PIValueTree::setValue(const PIVariant & v) {
	if (_is_null) return;
	_value = v;
}


void PIValueTree::setAttribute(const PIString & n, const PIVariant & a) {
	if (_is_null) return;
	_attributes[n] = a;
}


void PIValueTree::mergeAttributes(const PIVariantMap & a) {
	if (_is_null) return;
	auto it = a.makeIterator();
	while (it.next()) {
		if (!_attributes.contains(it.key()))
			_attributes.insert(it.key(), it.value());
	}
}


bool PIValueTree::contains(const PIString & name) const {
	if (_is_null) return true;
	for (const auto & c: _children)
		if (c.name() == name)
			return true;
	return false;
}


bool PIValueTree::contains(const PIStringList & path) const {
	if (_is_null || path.isEmpty()) return false;
	const PIValueTree * ret = &(child(path[0]));
	for (int i = 1; i < path.size_s(); ++i)
		ret = &(ret->child(path[i]));
	return !ret->isNull();
}


const PIValueTree & PIValueTree::child(const PIString & name) const {
	if (_is_null) return *this;
	for (const auto & c: _children)
		if (c.name() == name)
			return c;
	return nullValue();
}


PIValueTree & PIValueTree::child(const PIString & name) {
	if (_is_null) return *this;
	for (auto & c: _children)
		if (c.name() == name)
			return c;
	return nullValue();
}


PIValueTree & PIValueTree::addChild(const PIValueTree & n) {
	if (_is_null) return *this;
	for (auto & c: _children)
		if (c.name() == n.name()) {
			c = n;
			return *this;
		}
	_children << n;
	return *this;
}


PIValueTree & PIValueTree::addChildren(const PIVector<PIValueTree> & n) {
	if (_is_null) return *this;
	for (const auto & c: n)
		addChild(c);
	return *this;
}


PIValueTree & PIValueTree::remove(const PIString & name) {
	if (_is_null) return *this;
	_children.removeWhere([name](const PIValueTree & i){return i.name() == name;});
	return *this;
}


PIValueTree & PIValueTree::operator[](const PIString & name) {
	if (_is_null) return *this;
	for (auto & c: _children)
		if (c.name() == name)
			return c;
	_children << PIValueTree(name, PIVariant());
	return _children.back();
}


PIValueTree & PIValueTree::operator[](const PIStringList & path) {
	if (_is_null || path.isEmpty()) return *this;
	PIValueTree * ret = &((*this)[path[0]]);
	for (int i = 1; i < path.size_s(); ++i)
		ret = &((*ret)[path[i]]);
	return *ret;
}


void PIValueTree::print(PIString & s, const PIValueTree & v, PIString tab) {
	PIString ntab = tab + "  ", nntab = ntab + "  ";
	s += tab + v.name() + " {\n";
	if (v.value().isValid())
		s += ntab + "value: " + v.value().toString() + "\n";
	if (v.comment().isNotEmpty())
		s += ntab + "comment: " + v.comment() + "\n";
	if (v.attributes().isNotEmpty()) {
		s += ntab + "attributes: [\n";
		auto ait = v.attributes().makeIterator();
		while (ait.next())
			s += nntab + ait.key() + ": " + ait.value().toString() + "\n";
		s += ntab + "]\n";
	}
	if (v.hasChildren()) {
		s += ntab + "children: [\n";
		for (const auto & c: v.children()) {
			print(s, c, nntab);
		}
		s += ntab + "]\n";
	}
	s += tab + "}\n";
}


PIValueTree & PIValueTree::nullValue() {
	static PIValueTree ret;
	ret._is_null = true;
	return ret;
}
