#ifndef CDUTILS_TYPES_H
#define CDUTILS_TYPES_H

#include "pistring.h"
#include "pimap.h"
#include "pivariant.h"

class PIIODevice;
class PIEvaluator;
class CD_Pult;
class CDItem;
class CDItemModel;

namespace CDUtils {

class CDSection;

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

enum MessageType {
	Log = 1,
	MessageBox,
};

typedef PIFlags<UpdateMode> UpdateModeFlags;

class CDType {
	friend class CDSection;
	friend class CDCore;
	friend class Interface;
	friend class XInterface;
public:
	enum cdT {cdNull, cdK, cdX, cdC, cdM};
	enum XMode {X_Current, X_All_Avg};

	CDType();
	CDType(int i, const PIString & n, const PIString & t, const PIString & v, const PIString & f, const PIString & c, cdT cd_t);

	CDType & operator =(double x);
	int index() const {return index_;}
	PIString name() const {return name_;}
	PIString type() const;
	PIString value() const;
	PIVariant variantValue() 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 setVariantValue(const PIVariant & 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_;}
	PIStringList pathString() const;

	void setXMode(XMode mode) {mode_ = mode;}
	void setAvg(int avg) {avg_size = avg;}
	XMode xmode() const {return mode_;}
	XMode xmode_rec() const {return rmode_;}
	int avg() const {return avg_size;}
	bool isSelectedX() const {return x_enabled;}
	void readX(PIByteArray & ba);
	void writeX(PIByteArray & ba);

	PIVector<double> history;

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, x_enabled;
	PIVector<double> avg_h;
	int avg_size;
	XMode mode_, rmode_;
};


class CDSection {
	friend class CDCore;
	friend class Interface;
	friend class XInterface;
	friend class ::CD_Pult;
	friend class ::CDItem;
	friend class ::CDItemModel;
public:

	CDSection(CDType::cdT type_ = CDType::cdNull);

	bool test(int v) {return cd.value(v).toBool();}
//	CDType & operator [](int v) {if (!k.contains(v)) k[v].index_ = v; return k[v];}
	CDType & operator [](int v) {return cd[v];}
	const CDType operator [](int v) const {return cd[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);
	const CDSection section(int v) const;

	bool isEmpty() const {return cd.isEmpty() && s.isEmpty();}
	bool exists(PIDeque<int> path) const;
	int count(bool recursive = true) const;
	int sectionsCount() const;
	PIVector<int> indexes() const {return cd.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_) {
		cd = 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);
	void setSelectedX(bool yes);
	PIVector<PIDeque<int> > collectX() const;

	PIMap<int, CDType> cd;
	mutable PIMap<int, CDSection> s;
	CDType null;
	CDType::cdT cd_type_;
};

}


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;
	case CDUtils::CDType::cdM : s << "M["; break;
	default : s << "Null["; break;
	}
	s << v.name() << "(" << v.index() << ")] = " << v.value();
	s.restoreControl();
	return s;
}


#endif // CDUTILS_TYPES_H
