#include "brick_base.h"

/*
double randomn(double dv, double sv) {
	double s = 2., v0, v1;
	while (s > 1. || s == 0.) {
		v0 = randomd();
		v1 = randomd();
		s = v0*v0 + v1*v1;
	}
	v0 = v0 * sqrt(-2 * log(s) / s);
	return v0 * sv + dv;
}
*/

void BrickBase::Parameter::setValue(const PIVariant & v, bool withType) {
	value = v;
	if (withType) {
		PIString tn = v.typeName();
		if (tn == "bool") {type = BrickBase::Bool; return;}
		if (tn == "char") {type = BrickBase::Integer; return;}
		if (tn == "uchar") {type = BrickBase::Integer; return;}
		if (tn == "short") {type = BrickBase::Integer; return;}
		if (tn == "ushort") {type = BrickBase::Integer; return;}
		if (tn == "int") {type = BrickBase::Integer; return;}
		if (tn == "uint") {type = BrickBase::Integer; return;}
		if (tn == "llong") {type = BrickBase::Integer; return;}
		if (tn == "ullong") {type = BrickBase::Integer; return;}
		if (tn == "float") {type = BrickBase::Float; return;}
		if (tn == "double") {type = BrickBase::Float; return;}
		if (tn == "ldouble") {type = BrickBase::Float; return;}
		if (tn == "PIString") {type = BrickBase::String; return;}
		if (tn == "PIStringList") {type = BrickBase::String; return;}
	}/* else {
		switch (v.type()) {
		case PIVariant::Bool: value.vBool = v.vBool; return;
		case PIVariant::Char: value.vInt = v.vChar; return;
		case PIVariant::Short: value.vInt = v.vShort; return;
		case PIVariant::Int: value.vInt = v.vInt; return;
		case PIVariant::Long: value.vInt = v.vLong; return;
		case PIVariant::LLong: value.vInt = v.vLLong; return;
		case PIVariant::UChar: value.vInt = v.vUChar; return;
		case PIVariant::UShort: value.vInt = v.vUShort; return;
		case PIVariant::UInt: value.vInt = v.vUInt; return;
		case PIVariant::ULong: value.vInt = v.vULong; return;
		case PIVariant::ULLong: value.vInt = v.vULLong; return;
		case PIVariant::Float: value.vDouble = v.vFloat; return;
		case PIVariant::Double: value.vDouble = v.vDouble; return;
		case PIVariant::LDouble: value.vDouble = v.vLDouble; return;
		case PIVariant::String: value.vString = v.vString; return;
		case PIVariant::StringList: value.vString = v.vStringList.join(", "); return;
		};
	}*/
}


BrickBase::BrickBase(int inputs_num, int outputs_num, int parameters_num) {
	inputs_count = inputs_num;
	outputs_count = outputs_num;
	parameters_count = parameters_num;
	inputs.resize(inputs_num, 0.);
	outputs.resize(outputs_num, 0.);
	defInputs.resize(inputs_num, 0.);
	parameters.resize(parameters_num, 0.);
	inNames.resize(inputs_num);
	outNames.resize(outputs_num);
	paramNames.resize(parameters_num);
	if (inputs_num > 0) inNames[0] = "Input";
	if (outputs_num > 0) outNames[0] = "Output";
	parametersName_ = "Parameters";
	pt = dt = 0;
	freqDivider_ = freqCurrent_ = 1;
	time_ = 0.;
	level_ = -666;
	io_Type = Fixed;
	initial = composite = buffered = interactive = rtOnly = false;
}


bool BrickBase::tick(double time) {
	if (freqDivider_ > 1) {
		if (freqCurrent_ < freqDivider_) {
			++freqCurrent_;
			lastTick = false;
			return false;
		}
		freqCurrent_ = 1;
	}
	time_ = time;
	dt = time - pt;
	lastTick = tick_body(time);
	pt = time;
	return lastTick;
}


void BrickBase::proceedConnections(bool) {
	for (uint i = 0; i < connections.size(); ++i)
		connections[i].brick_to->setInputValue(connections[i].in_num, output(connections[i].out_num));
}


bool BrickBase::connect(BrickBase * b_from, int out_num, BrickBase * b_to, int in_num) {
	if (out_num < 0 || out_num >= b_from->outputsCount()) {
		piCout << "Connect error: no such output" << out_num << "in \"" << b_from->name() << "\"!";
		return false;
	}
	if (in_num < 0 || in_num >= b_to->inputsCount()) {
		piCout << "Connect error: no such input" << in_num << "in \"" << b_to->name() << "\"!";
		return false;
	}
	b_from->addConnection(BrickBase::Connection(out_num, b_to, in_num));
	//string fn = b_from->name().stdString(), tn = b_to->name().stdString();
	//cout << "Connect    \"" << fn << "\": " << out_num << "  to  \"" << tn << "\": " << in_num << endl;
	return true;
}


bool BrickBase::disconnect(BrickBase * b_from, int out_num, BrickBase * b_to, int in_num) {
	/*if (out_num < 0 || out_num >= b_from->outCount()) {
		cout << "Disconnect error: no such output " << out_num << " in \"" << b_from->name() << "\"!" << endl;
		return false;
	}
	if (in_num < 0 || in_num >= b_to->inCount()) {
		cout << "Disconnect error: no such input " << in_num << " in \"" << b_to->name() << "\"!" << endl;
		return false;
	}*/
	BrickBase::Connection conn;
	for (int i = 0; i < b_from->connectionsCount(); ++i) {
		conn = b_from->connection(i);
		if (out_num != conn.out_num || b_to != conn.brick_to || in_num != conn.in_num)
			continue;
		b_from->removeConnection(i);
		//string fn = b_from->name().stdString(), tn = b_to->name().stdString();
		//cout << "Disconnect \"" << fn << "\": " << out_num << " from \"" << tn << "\": " << in_num << endl;
		return true;
	}
	return false;
}

