#include "cdutils_types.h"
#include "piconfig.h"
#include "pifile.h"
#include "pievaluator.h"
#include "cdutils_core.h"

using namespace CDUtils;

//int cdtype_debug_cnt = 1;

const int cd_x_history_max_size = 4000;

CDType::CDType() {
	index_ = -1;
	value_d = 0.;
	value_i = 0;
	value_b = calculated = x_enabled = false;
	cd_type_ = cdNull;
	parent = 0;
	avg_size = 1;
	mode_ = rmode_ = X_Current;
//	debug_cnt = cdtype_debug_cnt;
//	cdtype_debug_cnt++;
//	piCout << "[CDType]" << "create Null" << debug_cnt;
}




CDType::CDType(int i, const PIString & n, const PIString & t, const PIString & v, const PIString & f, const PIString & c, cdT cd_t) {
	index_ = i;
	name_ = n.trimmed();
	type_ = t.trimmed();
	value_s = v.trimmed();
	formula_ = f.trimmed();
	comment_ = c.trimmed();
	value_d = v.toDouble();
	value_i = v.toInt();
	value_b = v.toBool();
	cd_type_ = cd_t;
	calculated = x_enabled = false;
	parent = 0;
	avg_size = 1;
	mode_ = rmode_ = X_Current;
	if (type_ == "e") {
		enum_values = parseEnumComment(comment_);
//		piCout << enum_values.size() << enum_values;
	}
//	piCout << type_.size() << type_.toUTF8();
//	piCout << formula_.size() << formula_.toUTF8();
//	piCout << comment_.size() << comment_.toUTF8();
//	debug_cnt = cdtype_debug_cnt;
//	cdtype_debug_cnt++;
//	piCout << "[CDType] create" << name_ << ":" << type_ << ":" << value_s << ":" << value_d << ":" << formula_ << ":" << comment_ << ":" << (cd_type_ == cdK);
}


CDType & CDType::operator =(double x) {
	value_d = x;
	value_i = x;
	value_b = x > 0.;
	if (mode_ == X_All_Avg) {
		avg_h << x;
		double val = 0;
		if (avg_h.size_s() >= avg_size) {
			for (int i = 0; i < avg_h.size_s(); i++)
				val += avg_h[i];
			val /= avg_h.size();
			avg_h.clear();
			if (history.size() < cd_x_history_max_size)
				history << val;
		}
	}
	return *this;
}


PIString CDType::type() const {
	if (type_.trimmed().isEmpty()) return "f";
	//	piCout << "type =" << type_.trimmed() << ";" << type_ << "#";
	return type_;
}


PIString CDType::value() const {
	if (type_ == "b") return PIString::fromBool(value_b);
	return value_s;
}


PIVariant CDType::variantValue() const {
	if (type_.isEmpty()) return PIVariant(value());
	switch (type_[0].toAscii()) {
	case 'b': return PIVariant(toBool()); break;
	case 'n': return PIVariant(toInt()); break;
	case 'f': return PIVariant(toDouble()); break;
	case 'c': return PIVariant(PIVariantTypes::Color(toInt())); break;
	case 'e': {
		PIVariantTypes::Enum e = enum_values;
		e.selectValue(toInt());
		return PIVariant(e);
		break;
		}
	default: break;
	}
	return PIVariant(value());
}


void CDType::setValue(const PIString & value_) {
	formula_ = value_;
	value_d = formula_.toDouble();
	value_i = formula_.toInt();
	value_b = formula_.toBool();
}


void CDType::setVariantValue(const PIVariant & value_) {
	setValue(PIString::fromNumber(value_.toDouble()));
}


void CDType::setFormula(const PIString & f) {
	formula_ = f;
	calculated = false;
	//PIEvaluator e;
	//calculate(&e);
}


PIStringList CDType::pathString() const {
	PIStringList ret;
	CDSection * ps = CDCore::instance()->root(cd_type_);
	if (!ps) return ret;
	for (int i = 0; i < path_.size_s() - 1; ++i) {
		ps = &(ps->section(path_[i]));
		if (!ps->alias.isEmpty()) ret << ps->alias;
		else ret << PIString::fromNumber(path_[i]);
	}
	if (!name_.isEmpty()) ret << name_;
	else ret << PIString::fromNumber(index_);
	return ret;
}


void CDType::readX(PIByteArray & ba) {
	if (ba.size() < 5) return;
	uchar t(0); ba >> t;
	rmode_ = (XMode)t;
	switch (rmode_) {
	case X_Current:
		ba >> value_d;
		break;
	case X_All_Avg: {
		PIVector<double> ah;
		ba >> ah;
		history << ah;
		if (!history.isEmpty())
			value_d = history.back();
		} break;
	default: break;
	}
	value_i = value_d;
	value_b = value_d > 0.;
}


void CDType::writeX(PIByteArray & ba) {
	ba << uchar(mode_);
	switch (mode_) {
	case X_Current:
		ba << value_d;
		break;
	case X_All_Avg:
		ba << history;
		history.clear();
		break;
	default: break;
	}
}


bool CDType::calculate(PIEvaluator * e, PIVector<const CDType * > stack) {
	if (stack.contains(this)) {
		error_ = "Circular dependencies: ";
		piForeachC (CDType * k, stack)
			error_ << k->name() << " -> ";
		error_ << name();
		//piCout << error_;
		return false;
	}
	stack << this;
	if (calculated) return true;
	calculated = true;
	error_.clear();
	if (!parent) return true;
	//piCout << "calc" << name_ << (parent ? parent->alias : "root");
	value_s = formula_.trimmed();
	for (;;) {
		int ki = value_s.find("K[");
		if (ki < 0) break;
		int ke = value_s.find("]", ki + 2);
		if (ke < 0) break;
		PIString kp = value_s.mid(ki + 2, ke - ki - 2);
		//piCout << kp;
		CDType & k((*parent)[kp]);
		k.calculate(e, stack);
		value_s.replace(ki, ke - ki + 1, PIString::fromNumber(k.value_d));
	}
	value_d = formula_.toDouble();
	value_i = formula_.toInt();
	value_b = formula_.toBool();
	double ev = 0.;
	if (!e->check(value_s) && value_d == 0. && value_i == 0 && !value_b) {
		PIString f = formula_.trimmed().toLowerCase();
		if (f != "off" && f != "false" && f != "no" && !value_b) {
			error_ = e->error();
			return false;
		}
	} else
		if (e->isCorrect())
			ev = e->evaluate().real();
	//piCout << value_s << value_i << value_d << ev;
	//if ((value_d == 0.) || (piAbsd(value_d) < piAbsd(ev))) value_d = ev;
	//if ((value_i == 0) || (piAbsd(value_i) < piAbsd(ev))) value_i = int(ev);
	if ((value_d == 0.) || (ev != 0.)) value_d = ev;
	if ((value_i == 0) || (ev != 0.)) value_i = int(ev);
	value_b = value_b || (ev > 0.);
	if (value_i != 0) {
		if (value_d == 0.) value_d = value_i;
		value_b = value_i > 0;
	}
	if (value_d != 0.) {
		if (value_i == 0) value_i = value_d;
		value_b = value_d > 0.;
	}
	if (value_b) {
		if (value_d == 0.) value_d = 1.;
		if (value_i == 0) value_i = 1;
	}
	value_s = PIString::fromNumber(value_d);
	return true;
}


PIVariantTypes::Enum CDType::parseEnumComment(PIString c) {
	PIVariantTypes::Enum ret;
	if (c.isEmpty()) return ret;
	if (type_ == "e") {
		PIStringList sl = c.inBrackets('{', '}').split(",");
		int cval = 0;
		piForeach (PIString & s, sl) {
			s.trim();
			if (s.isEmpty()) continue;
			if (s[0].isDigit()) {
				int ind = s.find("-");
				if (ind > 0) {
					cval = s.left(ind).toInt();
					s.cutLeft(ind + 1).trim();
				}
			}
			ret << PIVariantTypes::Enumerator(cval, s);
			++cval;
		}
	}
	//piCout << c << "=" << ret;
	return ret;
}


//CDType::CDType(const CDType &cdt) {
//	index_ = cdt.index_;
//	name_ = cdt.name_;
//	type_ = cdt.type_;
//	value_s = cdt.value_s;
//	formula_ = cdt.formula_;
//	comment_ = cdt.comment_;
//	value_d = cdt.value_d;
//	value_i = cdt.value_i;
//	value_b = cdt.value_b;
//	cd_type_ = cdt.cd_type_;
//	debug_cnt = cdtype_debug_cnt;
//	cdtype_debug_cnt++;
//	piCout << "[CDType] copy" << debug_cnt << "->" << cdt.debug_cnt << index_ << ":" << name_ << ":" << type_ << ":" << value_s << ":" << value_d << ":" << formula_ << ":" << comment_ << ":" << (cd_type_ == cdK);
//}


//CDType &CDType::operator =(const CDType &cdt) {
//	index_ = cdt.index_;
//	name_ = cdt.name_;
//	type_ = cdt.type_;
//	value_s = cdt.value_s;
//	formula_ = cdt.formula_;
//	comment_ = cdt.comment_;
//	value_d = cdt.value_d;
//	value_i = cdt.value_i;
//	value_b = cdt.value_b;
//	cd_type_ = cdt.cd_type_;
//	piCout << "[CDType] assign" << debug_cnt << "=" << cdt.debug_cnt << index_ << ":" << name_ << ":" << type_ << ":" << value_s << ":" << value_d << ":" << formula_ << ":" << comment_ << ":" << (cd_type_ == cdK);
//	//debug_cnt = cdt.debug_cnt;
//	return *this;
//}


//CDType::~CDType() {
//	piCout << "[CDType] delete" << debug_cnt << index_ << ":" << name_ << ":" << type_ << ":" << value_s << ":" << value_d << ":" << formula_ << ":" << comment_ << ":" << (cd_type_ == cdK);
//}



CDSection::CDSection(CDType::cdT type_) {
	cd_type_ = type_;
	null.cd_type_ = type_;
}


CDSection & CDSection::section(int v) {
	CDSection & ret(s[v]);
	ret.cd_type_ = cd_type_;
	return ret;
}


const CDSection CDSection::section(int v) const {
	CDSection & ret(s[v]);
	ret.cd_type_ = cd_type_;
	return s[v];
}


bool CDSection::exists(PIDeque<int> path) const {
	if (path.isEmpty()) return false;
	if (path.size_s() == 1) return cd.contains(path[0]);
	int si = path[0];
	if (!s.contains(si)) return false;
	path.remove(0, 1);
	return s[si].exists(path);
}


int CDSection::count(bool recursive) const {
	int ret = cd.size_s();
	if (recursive) {
		PIMap<int, CDSection>::const_iterator i;
		for (i = s.constBegin(); i != s.constEnd(); ++i)
			ret += i->second.count(recursive);
	}
	return ret;
}


int CDSection::sectionsCount() const {
	return s.size();
}


PIStringList CDSection::index_names() const {
	PIStringList ret;
	PIMap<int, CDType>::const_iterator i;
	for (i = cd.begin(); i != cd.end(); ++i)
		ret << i->second.name();
	return ret;
}


void CDSection::calculate() {
	prepareCalculate();
	if (cd_type_ != CDType::cdK) return;
	PIEvaluator e;
	calculateRecursive(&e);
}


CDType & CDSection::getByName(const PIString & name_) {
	PIStringList np = name_.split(".");
	if (np.isEmpty()) return null;
	//piCout << np;
	CDSection * cs = this, * ns = 0;
	if (np.front().isEmpty()) {
		if (np.size_s() < 2) return null;
		cs = CDCore::instance()->root(cd_type_);
		np.pop_front();
	}
	for (int i = 0; i < np.size_s() - 1; ++i) {
		if (np[i].isEmpty()) return null;
		bool isd = np[i][0].isDigit() || (np[i][0] == '-');
		int dv = 0;
		if (isd) dv = np[i].toInt();
		ns = 0;
		PIMap<int, CDSection>::iterator it;
		//piCout << np[i] << isd << dv;
		for (it = cs->s.begin(); it != cs->s.end(); ++it) {
			bool f = false;
			if (isd) f = (dv == it.key());
			else f = (np[i] == it.value().alias);
			//piCout << "s..." << it.key() << it.value().alias << f;
			if (f) {
				ns = &(it.value());
				break;
			}
		}
		//piCout << ns;
		if (!ns) return null;
		cs = ns;
	}
	PIMap<int, CDType>::iterator it;
	if (np.back().isEmpty()) return null;
	bool isd = np.back()[0].isDigit() || (np.back()[0] == '-');
	int dv = 0;
	if (isd) dv = np.back().toInt();
	//piCout << np.back() << isd << dv;
	for (it = cs->cd.begin(); it != cs->cd.end(); ++it) {
		bool f = false;
		if (isd) f = (dv == it.key());
		else f = (np.back() == it.value().name());
		//piCout << "k..." << it.key() << it.value().name() << f;
		if (f)
			return cs->cd[it.key()];
	}
	return null;
}


CDType & CDSection::getByPath(const PIDeque<int> & path_) {
	if (path_.isEmpty()) return null;
	CDSection * s = this;
	for (int i = 0; i < path_.size_s() - 1; ++i)
		s = &(s->section(path_[i]));
	if (!s) return null;
	return (*s)[path_.back()];
}


void CDSection::write(PIIODevice * d, const PIString & prefix) {
	if (!d) return;
	if (cd.isEmpty() && s.isEmpty()) return;
//	piCout << "[CDSection] write start";
	PIString l;
	PIStringList cdtl;
	cdtl << "null" << "k" << "x" << "c" << "m";
	if (prefix.isEmpty()) l = "[" + cdtl[cd_type_] + "]";
	else l = "[" + prefix + "." + cdtl[cd_type_] + "]";
	l += "\n";
	d->write(l.toUTF8());
	l = "name = " + name + " \n";
	d->write(l.toUTF8());
	l = "alias = " + alias + " \n";
	d->write(l.toUTF8());
	PIMap<int, CDType>::iterator i;
	for (i = cd.begin(); i != cd.end(); ++i) {
		CDType & ck(i.value());
		if (ck.cd_type() != cd_type_) continue;
		switch (cd_type_) {
		case CDType::cdNull: break;
		case CDType::cdK:
			l.clear(); l << ck.index() << ".f = " << ck.formula() << " #s " << ck.comment() << " \n";
			d->write(l.toUTF8());
			l.clear(); l << ck.index() << ".v = " << ck.value() << " #" << ck.type() << " " << ck.name() << " \n";
			d->write(l.toUTF8());
			if (!ck.enumValues().enum_list.isEmpty()) {
				l.clear(); l << ck.index() << ".ev = {";
				//PIVector<CDType::Enumerator> el = ck.enumValues();
				piForeachC (PIVariantTypes::Enumerator & e, ck.enumValues().enum_list)
					l << e.value << " - " << e.name << ", ";
				l.cutRight(2);
				l << "} \n";
				d->write(l.toUTF8());
			}
			break;
		case CDType::cdX:
			l.clear(); l << ck.index() << ".name = " << ck.name() << " #s " << ck.comment() << " \n";
			d->write(l.toUTF8());
			l.clear(); l << ck.index() << ".mode = " << ck.xmode() << " #e (0 - cur, 1 - all_avg) " << "\n";
			d->write(l.toUTF8());
			l.clear(); l << ck.index() << ".avg = " << ck.avg() << " #n " << "\n";
			d->write(l.toUTF8());
			l.clear(); l << ck.index() << ".sel = " << (ck.isSelectedX() ? "1" : "0") << " #n " << "\n";
			d->write(l.toUTF8());
			break;
		case CDType::cdC:
		case CDType::cdM:
			l.clear(); l << ck.index() << ".name = " << ck.name() << " #s " << ck.comment() << " \n";
			d->write(l.toUTF8());
			break;
		}
	}
	if (!s.isEmpty()) {
		if (prefix.isEmpty()) l = "s";
		else l = prefix + ".s";
		PIMap<int, CDSection>::iterator j;
		for (j = s.begin(); j != s.end(); ++j) {
			j.value().write(d, l + "." + PIString::fromNumber(j.key()));
		}
	}
	if (prefix.isEmpty()) {
		l = "[]\n";
		d->write(l.toUTF8());
	}
//	piCout << "[CDSection] write end";
}


void CDSection::read(const void * ep) {
//	piCout << "[CDSection] read start";
	PIStringList cdtl;
	cdtl << "null" << "k" << "x" << "c" << "m";
	cd.clear();
	s.clear();
	PIConfig::Entry & e(*(PIConfig::Entry*)ep);
	name = e.getValue(cdtl[cd_type_] + ".name").value();
	alias = e.getValue(cdtl[cd_type_] + ".alias").value();
	PIConfig::Entry & cdl = e.getValue(cdtl[cd_type_]);
	for (int i = 0; i < cdl.childCount(); ++i) {
		const PIConfig::Entry * e(cdl.child(i));
		bool ok = false;
		int id = e->name().toInt(-1, &ok);
//		piCout << "[read]" << ke->name() << ke->value() << ok;
//		PIString n = ke->getValue("v").comment();
//		PIString t = n.takeLeft(1);
		if (ok) {
			CDType c;
			PIString ev;
			switch (cd_type_) {
			case CDType::cdNull: break;
			case CDType::cdK:
				c = CDType(id, e->getValue("v").comment(), e->getValue("v").type(), e->getValue("v").value(), e->getValue("f").value(), e->getValue("f").comment(), cd_type_);
				ev = e->getValue("ev", "");
				if (!ev.isEmpty())
					c.enum_values = c.parseEnumComment(ev);
				break;
			case CDType::cdX:
				c = CDType(id, e->getValue("name").value(), PIString(), PIString(), PIString() , e->getValue("name").comment(), cd_type_);
				c.setXMode((CDType::XMode)e->getValue("mode", int(CDType::X_Current)).value().toInt());
				c.setAvg((CDType::XMode)e->getValue("avg", 1).value().toInt());
				c.x_enabled = e->getValue("sel", false).value().toBool();
				break;
			case CDType::cdC:
			case CDType::cdM:
				c = CDType(id, e->getValue("name").value(), PIString(), PIString(), PIString() , e->getValue("name").comment(), cd_type_);
				break;
			}
			cd[id] = c;
		}
	}
	PIConfig::Entry & sl = e.getValue("s");
	for (int i = 0; i < sl.childCount(); ++i) {
		const PIConfig::Entry * se(sl.child(i));
		int sid = se->name().toInt();
		CDSection & rs(s[sid]);
		rs.cd_type_ = cd_type_;
		rs.read(se);
	}
//	piCout << "[CDSection] read end";
}


void CDSection::update(CDSection & v, UpdateModeFlags mode) {
	if (mode[SaveByIndex] && mode[SaveByName]) {
		piCout << "[CDSection] update error: SaveByIndex | SaveByName mode is denied!";
		return;
	}
	//piCout << "[CDSection] update start";
	//piCout << "before" << k.size() << v.k.size();

	PIMap<int, PIString> prev_cd_f_bi;
	PIMap<PIString, PIString> prev_cd_f_bn;
	PIMap<int, CDType>::iterator i;
	if (mode[SaveByIndex]) {
		for (i = cd.begin(); i != cd.end(); ++i)
			prev_cd_f_bi[i.key()] = i.value().formula();
	}
	if (mode[SaveByName]) {
		for (i = cd.begin(); i != cd.end(); ++i)
			prev_cd_f_bn[i.value().name_] = i.value().formula();
	}
	if (!mode[Merge])
		cd.clear();
	for (i = v.cd.begin(); i != v.cd.end(); ++i) {
		int id = i.key();
		PIString n = i.value().name();
		cd[id] = i.value();
		if (mode[SaveByIndex]) {
			if (prev_cd_f_bi.contains(id))
				cd[id].setFormula(prev_cd_f_bi[id]);
		}
		if (mode[SaveByName]) {
			if (prev_cd_f_bn.contains(n))
				cd[id].setFormula(prev_cd_f_bn[n]);
		}
	}

	PIMap<int, CDSection> prev_s_bi;
	PIMap<PIString, CDSection> prev_s_bn;
	PIMap<int, CDSection>::iterator j;
	if (mode[SaveByIndex]) {
		for (j = s.begin(); j != s.end(); ++j)
			prev_s_bi[j.key()] = j.value();
	}
	if (mode[SaveByName]) {
		for (j = s.begin(); j != s.end(); ++j)
			prev_s_bn[j.value().alias] = j.value();
	}
	if (!mode[Merge])
		s.clear();
	for (j = v.s.begin(); j != v.s.end(); ++j) {
		int id = j.key();
		PIString n = j.value().alias;
		s[id] = j.value();
		if (mode[SaveByIndex]) {
			if (prev_s_bi.contains(id))
				s[id] = prev_s_bi[id];
		}
		if (mode[SaveByName]) {
			if (prev_s_bn.contains(n))
				s[id] = prev_s_bn[n];
		}
		s[id].update(j.value(), mode);
	}

	/*PISet<int> used;
	for (i = k.begin(); i != k.end(); ++i) {
		if (v.k.contains(i.key())) {
			PIString f = k[i.key()].formula_;
			CDType & cdt = v.k[i.key()];
			cdt.formula_ = f;
			k[i.key()] = cdt;
			used << i.key();
		}
		if (mode) {
			CDType & ck(k[i.key()]);
			if (prev_k_f_bn.contains(ck.name_))
				ck.setFormula(prev_k_f_bn[ck.name_]);
		}
	}
	//piCout << " after" << k.size();
	for (i = v.k.begin(); i != v.k.end(); ++i) {
		if (!used.contains(i.key()))
			k[i.key()] = i.value();
		CDType & ck(k[i.key()]);
		ck.setFormula(prev_k_f_bn.value(ck.name_));
	}
	used.clear();
	PIMap<int, CDSection>::iterator j;
	for (j = s.begin(); j != s.end(); ++j) {
		if (v.s.contains(j.key()))
			j.value().update(v.s[j.key()], mode);
		used << j.key();
	}
	for (j = v.s.begin(); j != v.s.end(); ++j) {
		if (!used.contains(j.key()))
			s[j.key()] = j.value();
	}*/
//	piCout << "[CDSection] update end";
}


bool CDSection::isSameStructure(CDSection & v) {
	PIMap<PIString, int> cd_ids;
	PIMap<int, CDType>::iterator i;
	for (i = cd.begin(); i != cd.end(); ++i)
		cd_ids[i.value().name()] = i.key();
	for (i = v.cd.begin(); i != v.cd.end(); ++i) {
		if (!cd_ids.contains(i.value().name())) continue;
		//piCout << i.key() << k[i.key()].name() << i.value().name();
		if (cd[cd_ids[i.value().name()]].index() != i.key())
			return false;
	}
	PIMap<int, CDSection>::iterator j;
	for (j = v.s.begin(); j != v.s.end(); ++j) {
		if (!s.contains(j.key())) continue;
		if (!s[j.key()].isSameStructure(j.value()))
			return false;
	}
	return true;
}


void CDSection::prepareCalculate() {
	PIMap<int, CDType>::iterator i;
	for (i = cd.begin(); i != cd.end(); ++i) {
		i.value().parent = this;
		i.value().calculated = false;
	}
	PIMap<int, CDSection>::iterator j;
	for (j = s.begin(); j != s.end(); ++j)
		j.value().prepareCalculate();
}


void CDSection::calculateRecursive(PIEvaluator * e) {
	PIMap<int, CDType>::iterator i;
	for (i = cd.begin(); i != cd.end(); ++i)
		i.value().calculate(e);
	PIMap<int, CDSection>::iterator j;
	for (j = s.begin(); j != s.end(); ++j)
		j.value().calculateRecursive(e);
}


void CDSection::setSelectedX(bool yes) {
	PIMap<int, CDType>::iterator i;
	for (i = cd.begin(); i != cd.end(); ++i)
		i.value().x_enabled = yes;
	PIMap<int, CDSection>::iterator j;
	for (j = s.begin(); j != s.end(); ++j)
		j.value().setSelectedX(yes);
}


PIVector<PIDeque<int> > CDSection::collectX() const {
	PIVector<PIDeque<int> > ret;
	PIMap<int, CDType>::const_iterator i;
	for (i = cd.begin(); i != cd.end(); ++i) {
		if (i.value().x_enabled)
			ret << i.value().path();
	}
	PIMap<int, CDSection>::const_iterator j;
	for (j = s.constBegin(); j != s.constEnd(); ++j)
		ret << j.value().collectX();
	return ret;
}


void CDSection::makePath(PIDeque<int> p) {
	PIDeque<int> tp;
	PIMap<int, CDType>::iterator i;
	for (i = cd.begin(); i != cd.end(); ++i) {
		tp = p;
		tp << i.key();
		i.value().path_ = tp;
		//piCout << "path for" << i.value().name() << tp;
	}
	PIMap<int, CDSection>::iterator j;
	for (j = s.begin(); j != s.end(); ++j) {
		tp = p;
		tp << j.key();
		j.value().makePath(tp);
	}
}


PIVector<CDType * > CDSection::children(bool recursive) const {
	PIVector<CDType * > ret;
	PIMap<int, CDType>::const_iterator i;
	for (i = cd.begin(); i != cd.end(); ++i)
		ret << const_cast<CDType * >(&(i.value()));
	if (!recursive) return ret;
	PIMap<int, CDSection>::const_iterator j;
	for (j = s.constBegin(); j != s.constEnd(); ++j)
		ret << j.value().children(true);
	return ret;
}


PIVariantTypes::Enum CDSection::enumValues() const {
	PIVariantTypes::Enum ret;
	PIMap<int, CDType>::const_iterator i;
	for (i = cd.constBegin(); i != cd.constEnd(); ++i)
		ret << PIVariantTypes::Enumerator(i.key(), i.value().name());
	return ret;
}


