#ifndef CDUTILS_TYPES_H
#define CDUTILS_TYPES_H

#include "pistring.h"
#include "pimap.h"
#include "pivarianttypes.h"

class PIIODevice;
class PIEvaluator;
class CD_Pult;
class CDKItem;
class CDKItemModel;

namespace CDUtils {

class CDSection;

enum UpdateMode {
	SaveByIndex = 0x01,
	SaveByName  = 0x02,
	Merge       = 0x04
};

typedef PIFlags<UpdateMode> UpdateModeFlags;

class CDType {
	friend class CDSection;
public:
	enum cdT {cdNull, cdK, cdX, cdC};
	CDType();
	CDType(int i, const PIString & n, const PIString & t, const PIString & v, const PIString & f, const PIString & c, cdT cd_t);
	int index() const {return index_;}
	PIString name() const {return name_;}
	PIString type() const;
	PIString value() const;
	PIString formula() const {return formula_;}
	PIString comment() const {return comment_;}
	double toDouble() const {return value_d;}
	int toInt() const {return value_i;}
	bool toBool() const {return value_b;}
	cdT cd_type() const {return cd_type_;}
	void setValue(const PIString & value_);
	void setFormula(const PIString & formula);
	void setComment(const PIString & comment) {comment_ = comment;}
	operator double() const {return value_d;}
	const PIVariantTypes::Enum & enumValues() const {return enum_values;}
	void setEnumValues(const PIVariantTypes::Enum & ev) {enum_values = ev;}
	const PIString & errorString() const {return error_;}
	PIDeque<int> path() const {return path_;}

protected:
	bool calculate(PIEvaluator * e, PIVector<const CDType * > stack = PIVector<const CDType * >());
	PIVariantTypes::Enum parseEnumComment(PIString c);
	cdT cd_type_;
	int index_;
	PIString name_, type_;
	PIString value_s, formula_, comment_, error_;
	PIVariantTypes::Enum enum_values;
	CDSection * parent;
	PIDeque<int> path_;
	double value_d;
	int value_i;
	bool value_b, calculated;

};


class CDSection {
	friend class CDCore;
	friend class ::CD_Pult;
	friend class ::CDKItem;
	friend class ::CDKItemModel;
public:

	CDSection() {}

	bool test(int v) {return k.value(v).toBool();}
//	CDType & operator [](int v) {if (!k.contains(v)) k[v].index_ = v; return k[v];}
	CDType & operator [](int v) {return k[v];}
	const CDType operator [](int v) const {return k[v];}
	CDType & operator [](const PIString & name_) {return getByName(name_);}
	const CDType operator [](const PIString & name_) const {return const_cast<CDSection*>(this)->getByName(name_);}
	CDType & operator [](const PIDeque<int> & path_) {return getByPath(path_);}
	const CDType operator [](const PIDeque<int> & path_) const {return const_cast<CDSection*>(this)->getByPath(path_);}
	CDSection & section(int v) {return s[v];}
	const CDSection section(int v) const {return s[v];}

	bool isEmpty() const {return k.isEmpty() && s.isEmpty();}
	int count(bool recursive = true) const;
	int sectionsCount() const;
	PIVector<int> indexes() const {return k.keys();}
	PIStringList index_names() const;
	void calculate();
	void makePath(PIDeque<int> p = PIDeque<int>());
	PIVector<CDType * > children(bool recursive = true) const;
	PIVariantTypes::Enum enumValues() const;

	PIString name;
	PIString alias;

protected:
	CDSection(PIMap<int, CDType> k_, PIMap<int, CDSection> s_) {
		k = k_;
		s = s_;
	}
	CDType & getByName(const PIString & name_);
	CDType & getByPath(const PIDeque<int> & path_);
	void write(PIIODevice * d, const PIString & prefix = PIString());
	void read(const void * ep);
	void update(CDSection & v, UpdateModeFlags mode = SaveByName);
	bool isSameStructure(CDSection & v);
	void prepareCalculate();
	void calculateRecursive(PIEvaluator * e);

	PIMap<int, CDType> k;
	PIMap<int, CDSection> s;
	CDType null;

};

}

inline PICout operator <<(PICout s, const CDUtils::CDType & v) {
	s.space();
	s.setControl(0, true);
	switch (v.cd_type()) {
		case CDUtils::CDType::cdK : s << "K["; break;
		case CDUtils::CDType::cdX : s << "X["; break;
		case CDUtils::CDType::cdC : s << "C["; break;
		default : s << "Null["; break;
	}
	s << v.name() << "(" << v.index() << ")] = " << v.value();
	s.restoreControl();
	return s;
}

#endif // CDUTILS_TYPES_H
