
#include "FlipFlop.hpp"

void FlipFlop::reset() {
	for (int i = 0; i < maxChannels; ++i) {
		_flipped1[i] = false;
		_trigger1[i].reset();
		_resetTrigger1[i].reset();

		_flipped2[i] = false;
		_trigger2[i].reset();
		_resetTrigger2[i].reset();
	}
}

void FlipFlop::processAll(const ProcessArgs& args) {
	for (int i = 0, n = std::max(1, inputs[IN1_INPUT].getChannels()); i < n; ++i) {
		channelStep(
			i,
			n,
			inputs[IN1_INPUT],
			inputs[RESET1_INPUT],
			outputs[A1_OUTPUT],
			outputs[B1_OUTPUT],
			_trigger1,
			_resetTrigger1,
			_flipped1
		);
	}

	for (int i = 0, n = std::max(1, inputs[IN2_INPUT].getChannels()); i < n; ++i) {
		channelStep(
			i,
			n,
			inputs[IN2_INPUT],
			inputs[RESET2_INPUT],
			outputs[A2_OUTPUT],
			outputs[B2_OUTPUT],
			_trigger2,
			_resetTrigger2,
			_flipped2
		);
	}
}

void FlipFlop::channelStep(
	int c,
	int channels,
	Input& triggerInput,
	Input& resetInput,
	Output& aOutput,
	Output& bOutput,
	PositiveZeroCrossing* trigger,
	Trigger* resetTrigger,
	bool* flipped
) {
	bool triggered = trigger[c].next(triggerInput.getVoltage(c));
	resetTrigger[c].process(resetInput.getPolyVoltage(c));
	if (resetTrigger[c].isHigh()) {
		flipped[c] = false;
	}
	else if (triggered) {
		flipped[c] = !flipped[c];
	}

	if (flipped[c]) {
		aOutput.setChannels(channels);
		aOutput.setVoltage(0.0f, c);
		bOutput.setChannels(channels);
		bOutput.setVoltage(5.0f, c);
	}
	else {
		aOutput.setChannels(channels);
		aOutput.setVoltage(5.0f, c);
		bOutput.setChannels(channels);
		bOutput.setVoltage(0.0f, c);
	}
}

struct FlipFlopWidget : BGModuleWidget {
	static constexpr int hp = 3;

	FlipFlopWidget(FlipFlop* module) {
		setModule(module);
		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
		setPanel(box.size, "FlipFlop");
		createScrews();

		// generated by svg_widgets.rb
		auto in1InputPosition = Vec(10.5, 21.0);
		auto reset1InputPosition = Vec(10.5, 56.0);
		auto in2InputPosition = Vec(10.5, 172.0);
		auto reset2InputPosition = Vec(10.5, 207.0);

		auto a1OutputPosition = Vec(10.5, 94.0);
		auto b1OutputPosition = Vec(10.5, 129.0);
		auto a2OutputPosition = Vec(10.5, 245.0);
		auto b2OutputPosition = Vec(10.5, 280.0);
		// end generated by svg_widgets.rb

		addInput(createInput<Port24>(in1InputPosition, module, FlipFlop::IN1_INPUT));
		addInput(createInput<Port24>(reset1InputPosition, module, FlipFlop::RESET1_INPUT));
		addInput(createInput<Port24>(in2InputPosition, module, FlipFlop::IN2_INPUT));
		addInput(createInput<Port24>(reset2InputPosition, module, FlipFlop::RESET2_INPUT));

		addOutput(createOutput<Port24>(a1OutputPosition, module, FlipFlop::A1_OUTPUT));
		addOutput(createOutput<Port24>(b1OutputPosition, module, FlipFlop::B1_OUTPUT));
		addOutput(createOutput<Port24>(a2OutputPosition, module, FlipFlop::A2_OUTPUT));
		addOutput(createOutput<Port24>(b2OutputPosition, module, FlipFlop::B2_OUTPUT));
	}
};

Model* modelFlipFlop = bogaudio::createModel<FlipFlop, FlipFlopWidget>("Bogaudio-FlipFlop", "FLIPFLOP", "Dual flipflop", "Logic", "Dual", "Polyphonic");
