#include "brick_digital.h"


bool BrickDigitalTriggerRS::tick_body(double time) {
	if (inputs[R] > 0.) outputs[T] = 0.;
	else if (inputs[S] > 0.) outputs[T] = 1.;
	outputs[To] = 1. - outputs[T];
	return true;
}


bool BrickDigitalTriggerD::tick_body(double time) {
	if (inputs[C] <= 0.) return true;
	outputs[T] = dbool(inputs[D]);
	outputs[To] = 1. - outputs[T];
	return true;
}


bool BrickDigitalTriggerJK::tick_body(double time) {
	if (inputs[C] - pc <= 0. || inputs[C] <= 0.) {
		pc = inputs[C];
		return true;
	}
	outputs[T] = dbool((1. - outputs[T]) * inputs[J] + outputs[T] * (1. - inputs[K]));
	outputs[To] = 1. - outputs[T];
	pc = inputs[C];
	return true;
}


bool BrickDigitalCounter2::tick_body(double time) {
	dv = inputs[C] - v;
	v = inputs[C];
	if (inputs[R] > 0) {
		outputs[0] = outputs[1] = 0.;
		return true;
	}
	if (dv > 0.) {
		outputs[0] = 1. - outputs[0];
		if (outputs[0] == 0.) {
			outputs[1] = 1. - outputs[1];
			if (outputs[1] == 0.)
				outputs[0] = 0.;
		}
	}
	return true;
}


bool BrickDigitalCounter4::tick_body(double time) {
	dv = inputs[C] - v;
	v = inputs[C];
	if (inputs[R] > 0) {
		outputs[0] = outputs[1] = outputs[2] = outputs[3] = 0.;
		return true;
	}
	if (dv > 0.) {
		outputs[0] = 1. - outputs[0];
		if (outputs[0] == 0.) {
			outputs[1] = 1. - outputs[1];
			if (outputs[1] == 0.) {
				outputs[2] = 1. - outputs[2];
				if (outputs[2] == 0.) {
					outputs[3] = 1. - outputs[3];
					if (outputs[3] == 0.)
						outputs[0] = outputs[1] = outputs[2] = 0.;
				}
			}
		}
	}
	return true;
}


bool BrickDigitalCounter8::tick_body(double time) {
	dv = inputs[C] - v;
	v = inputs[C];
	if (inputs[R] > 0) {
		for (int i = 0; i < 8; ++i)
			outputs[i] = 0.;
		return true;
	}
	if (dv > 0.) {
		outputs[0] = 1. - outputs[0];
		if (outputs[0] == 0.) {
			outputs[1] = 1. - outputs[1];
			if (outputs[1] == 0.) {
				outputs[2] = 1. - outputs[2];
				if (outputs[2] == 0.) {
					outputs[3] = 1. - outputs[3];
					if (outputs[3] == 0.) {
						outputs[4] = 1. - outputs[4];
						if (outputs[4] == 0.) {
							outputs[5] = 1. - outputs[5];
							if (outputs[5] == 0.) {
								outputs[6] = 1. - outputs[6];
								if (outputs[6] == 0.) {
									outputs[7] = 1. - outputs[7];
										if (outputs[7] == 0.)
											for (int i = 0; i < 7; ++i)
												outputs[i] = 0.;
								}
							}
						}
					}
				}
			}
		}
	}
	return true;
}


bool BrickDigitalCoder2::tick_body(double time) {
	int cv = 0;
	for (int i = 3; i >= 0; --i)
		if (inputs[i] > 0.) {cv = i; break;}
	outputs[1] = cv / 2;
	outputs[0] = cv % 2;
	return true;
}


bool BrickDigitalCoder3::tick_body(double time) {
	int cv = 0;
	for (int i = 7; i >= 0; --i)
		if (inputs[i] > 0.) {cv = i; break;}
	outputs[2] = cv / 4;
	outputs[1] = (cv % 4) / 2;
	outputs[0] = cv % 2;
	return true;
}


bool BrickDigitalCoder4::tick_body(double time) {
	int cv = 0;
	for (int i = 15; i >= 0; --i)
		if (inputs[i] > 0.) {cv = i; break;}
	outputs[3] = cv / 8;
	outputs[2] = (cv % 8) / 4;
	outputs[1] = (cv % 4) / 2;
	outputs[0] = cv % 2;
	return true;
}


bool BrickDigitalDecoder1::tick_body(double time) {
	outputs[0] = outputs[1] = 0.;
	if (inputs[0] > 0.)
		outputs[1] = 1.;
	else
		outputs[0] = 1.;
	return true;
}


bool BrickDigitalDecoder2::tick_body(double time) {
	int cv;
	for (int i = 0; i < 4; ++i)
		outputs[i] = 0.;
	cv = dbool(inputs[0]) + dbool(inputs[1]) * 2;
	outputs[cv] = 1.;
	return true;
}


bool BrickDigitalDecoder3::tick_body(double time) {
	int cv;
	for (int i = 0; i < 8; ++i)
		outputs[i] = 0.;
	cv = dbool(inputs[0]) + dbool(inputs[1]) * 2 + dbool(inputs[2]) * 4;
	outputs[cv] = 1.;
	return true;
}


bool BrickDigitalDecoder4::tick_body(double time) {
	int cv;
	for (int i = 0; i < 16; ++i)
		outputs[i] = 0.;
	cv = dbool(inputs[0]) + dbool(inputs[1]) * 2 + dbool(inputs[2]) * 4 + dbool(inputs[3]) * 8;
	outputs[cv] = 1.;
	return true;
}


bool BrickDigitalMux1::tick_body(double time) {
	int cv;
	cv = dbool(inputs[2]);
	outputs[0] = inputs[cv];
	return true;
}


bool BrickDigitalMux2::tick_body(double time) {
	int cv;
	cv = dbool(inputs[4]) + dbool(inputs[5]) * 2;
	outputs[0] = inputs[cv];
	return true;
}


bool BrickDigitalMux3::tick_body(double time) {
	int cv;
	cv = dbool(inputs[8]) + dbool(inputs[9]) * 2 + dbool(inputs[10]) * 4;
	outputs[0] = inputs[cv];
	return true;
}


bool BrickDigitalMux4::tick_body(double time) {
	int cv;
	cv = dbool(inputs[16]) + dbool(inputs[17]) * 2 + dbool(inputs[18]) * 4 + dbool(inputs[19]) * 8;
	outputs[0] = inputs[cv];
	return true;
}


bool BrickDigitalDemux1::tick_body(double time) {
	outputs[0] = outputs[1] = 0.;
	if (inputs[1] > 0.)
		outputs[1] = inputs[0];
	else
		outputs[0] = inputs[0];
	return true;
}


bool BrickDigitalDemux2::tick_body(double time) {
	int cv;
	for (int i = 0; i < 4; ++i)
		outputs[i] = 0.;
	cv = dbool(inputs[1]) + dbool(inputs[2]) * 2;
	outputs[cv] = inputs[0];
	return true;
}


bool BrickDigitalDemux3::tick_body(double time) {
	int cv;
	for (int i = 0; i < 8; ++i)
		outputs[i] = 0.;
	cv = dbool(inputs[1]) + dbool(inputs[2]) * 2 + dbool(inputs[3]) * 4;
	outputs[cv] = inputs[0];
	return true;
}


bool BrickDigitalDemux4::tick_body(double time) {
	int cv;
	for (int i = 0; i < 16; ++i)
		outputs[i] = 0.;
	cv = dbool(inputs[1]) + dbool(inputs[2]) * 2 + dbool(inputs[3]) * 4 + dbool(inputs[4]) * 8;
	outputs[cv] = inputs[0];
	return true;
}


bool BrickDigitalDigitalToAnalog4::tick_body(double time) {
	double v = 0;
	for (int i = 0; i < 4; ++i)
		v += pow2(i) * dbool(inputs[i]);
	outputs[0] = inputs[4] * v / 15.;
	return true;
}


bool BrickDigitalDigitalToAnalog8::tick_body(double time) {
	double v = 0;
	for (int i = 0; i < 8; ++i)
		v += pow2(i) * dbool(inputs[i]);
	outputs[0] = inputs[8] * v / 255.;
	return true;
}


bool BrickDigitalAnalogToDigital2::tick_body(double time) {
	double v = inputs[Input], t = inputs[Max] / 2.;
	outputs[1] = (v >= t ? 1. : 0.);
	if (outputs[1] > 0.) v -= t;
	t /= 2.;
	outputs[0] = (v >= t ? 1. : 0.);
	return true;
}


bool BrickDigitalAnalogToDigital4::tick_body(double time) {
	double v = inputs[Input], t = inputs[Max] / 2.;
	for (int i = 3; i >= 0; --i) {
		outputs[i] = (v >= t ? 1. : 0.);
		if (outputs[i] > 0.) v -= t;
		t /= 2.;
	}
	return true;
}


bool BrickDigitalAnalogToDigital8::tick_body(double time) {
	double v = inputs[Input], t = inputs[Max] / 2.;
	for (int i = 7; i >= 0; --i) {
		outputs[i] = (v >= t ? 1. : 0.);
		if (outputs[i] > 0.) v -= t;
		t /= 2.;
	}
	return true;
}
