#ifndef BRICK_COMPOSITE_H
#define BRICK_COMPOSITE_H

#include "brick_emits.h"
#include "brick_math.h"
#include "brick_logic.h"
#include "brick_digital.h"
#include "brick_link.h"
#include "brick_interface.h"
#include "brick_statistic.h"

void buildTree(PIVector<BrickBase * > & bricks, PIVector<PIVector<BrickBase * > > & tree);
PIVector<PIVector<BrickBase * > > buildSubtree(PIVector<BrickBase * > & bricks, PIVector<PIVector<BrickBase * > > & tree);
void sumTrees(PIVector<PIVector<BrickBase * > > & ft, PIVector<PIVector<BrickBase * > > & st);


class BrickCompositeBase: public BrickBase {
	public: BrickCompositeBase(int inputs_num = 0, int outputs_num = 0, int parameters_num = 1): BrickBase(inputs_num, outputs_num, parameters_num) {lib = "Composite";}
};


class BrickCompositeInput;
class BrickCompositeOutput;
class BrickCompositeParameters;
class BrickCompositeInformation;


class BrickComposite: public BrickCompositeBase {
	MBRICK(BrickComposite)
	BrickComposite();
	virtual bool tick_body(double time);
	Mode mode() const {return mode_;}
	void setMode(Mode m) {mode_ = m;}
	void buildBrickTree() {buildTree(bricks, tree);}
	void clear();
	void loadScheme(const PIString & file) {setParameterValue(0, file);}
	static BrickBase * findBaseBrick(const PIString & code_name);
	
protected:
	virtual void parameterChanged(int index);
	virtual void started() {parameterChanged(0); for (uint i = 0; i < bricks.size(); ++i) {bricks[i]->setManager(manager_); bricks[i]->started();}}
	virtual void finished() {for (uint i = 0; i < bricks.size(); ++i) bricks[i]->finished();}
	virtual void saveInputsToDefault() {defInputs = inputs; for (uint i = 0; i < bricks.size(); ++i) bricks[i]->saveInputsToDefault();}
	virtual void resetOutputs() {for (uint i = 0; i < bricks.size(); ++i) bricks[i]->resetOutputs();}
	virtual void reset_specified() {for (uint i = 0; i < bricks.size(); ++i) bricks[i]->reset_specified();}
	virtual void reset() {BrickBase::reset(); for (uint i = 0; i < bricks.size(); ++i) bricks[i]->reset();}
	virtual void proceedConnections(bool compositeToo = false);

	BrickBase * findBrick(const PIString & name);
	static void loadBrick(PIConfig & sr, const PIString & prefix, BrickBase * b, BrickManager * m = 0);
	static void fillBaseBricks();
	
	static PIVector<BrickBase * > baseBricks;
	PIVector<BrickBase * > bricks;
	PIVector<PIVector<BrickBase * > > tree;
	PIVector<BrickBase * > * tl;
	BrickCompositeInput * bi;
	BrickCompositeOutput * bo;
	BrickCompositeParameters * bp;
	BrickCompositeInformation * inf;
	Mode mode_;
	int header_;
	
};
ADD_NEW_TO_COLLECTION(Composite, BrickComposite)


class BrickCompositeInput: public BrickCompositeBase {
	MBRICK(BrickCompositeInput)
	BrickCompositeInput(int inputs_num = 1);
	virtual bool tick_body(double time) {return true;}
	virtual void parameterChanged(int index) {if (outNames.size_s() > index) outNames[index] = parameters[index].toString();}
	virtual void outputsCountChanged(int count) {setParametersCount(count, "");}
};
ADD_NEW_TO_COLLECTION(Composite, BrickCompositeInput)


class BrickCompositeOutput: public BrickCompositeBase {
	MBRICK(BrickCompositeOutput)
	BrickCompositeOutput(int outputs_num = 1);
	virtual bool tick_body(double time) {return true;}
	virtual void parameterChanged(int index) {if (inNames.size_s() > index) inNames[index] = parameters[index].toString();}
	virtual void inputsCountChanged(int count) {setParametersCount(count, "");}
};
ADD_NEW_TO_COLLECTION(Composite, BrickCompositeOutput)


class BrickCompositeParameters: public BrickCompositeBase {
	MBRICK(BrickCompositeParameters)
	BrickCompositeParameters();
	virtual void outputsCountChanged(int count) {setParametersCount(count, "p");}
	virtual void parameterChanged(int index);
};
ADD_NEW_TO_COLLECTION(Composite, BrickCompositeParameters)


class BrickCompositeInformation: public BrickCompositeBase {
	MBRICK(BrickCompositeInformation)
	BrickCompositeInformation();
};
ADD_NEW_TO_COLLECTION(Composite, BrickCompositeInformation)

#endif // BRICK_COMPOSITE_H
