
#include "OneEight.hpp"

void OneEight::processAlways(const ProcessArgs& args) {
	std::fill(_lightSums, _lightSums + 8, 0.0f);
}

void OneEight::processChannel(const ProcessArgs& args, int c) {
	int step = nextStep(
		c,
		&inputs[RESET_INPUT],
		inputs[CLOCK_INPUT],
		&params[STEPS_PARAM],
		params[DIRECTION_PARAM],
		&params[SELECT_PARAM],
		inputs[SELECT_INPUT]
	);

	if (_channels > 1) {
		float in = inputs[IN_INPUT].getPolyVoltage(c) + !inputs[IN_INPUT].isConnected() * 10.0f;
		for (int i = 0; i < 8; ++i) {
			outputs[OUT1_OUTPUT + i].setChannels(_channels);
			outputs[OUT1_OUTPUT + i].setVoltage((step == i) * in, c);
			_lightSums[i] += step == i;
		}
	}
	else if (!inputs[IN_INPUT].isConnected()) {
		for (int i = 0; i < 8; ++i) {
			outputs[OUT1_OUTPUT + i].setChannels(1);
			outputs[OUT1_OUTPUT + i].setVoltage((step == i) * 10.0f);
			_lightSums[i] += step == i;
		}
	}
	else {
		float* in = inputs[IN_INPUT].getVoltages();
		static float zeroes[maxChannels] {};
		for (int i = 0; i < 8; ++i) {
			outputs[OUT1_OUTPUT + i].setChannels(inputs[IN_INPUT].getChannels());
			outputs[OUT1_OUTPUT + i].writeVoltages((step == i) ? in : zeroes);
			_lightSums[i] += step == i;
		}
	}
}

void OneEight::postProcessAlways(const ProcessArgs& args) {
	for (int i = 0; i < 8; ++i) {
		lights[OUT1_LIGHT + i].value = _lightSums[i] * _inverseChannels;
	}
}

struct OneEightWidget : AddressableSequenceModuleWidget {
	static constexpr int hp = 6;

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

		// generated by svg_widgets.rb
		auto stepsParamPosition = Vec(15.5, 131.5);
		auto directionParamPosition = Vec(16.0, 167.5);
		auto selectParamPosition = Vec(9.0, 230.0);

		auto clockInputPosition = Vec(11.5, 35.0);
		auto resetInputPosition = Vec(11.5, 72.0);
		auto selectInputPosition = Vec(11.5, 270.0);
		auto inInputPosition = Vec(11.5, 324.0);

		auto out1OutputPosition = Vec(54.5, 35.0);
		auto out2OutputPosition = Vec(54.5, 76.3);
		auto out3OutputPosition = Vec(54.5, 118.6);
		auto out4OutputPosition = Vec(54.5, 158.9);
		auto out5OutputPosition = Vec(54.5, 200.1);
		auto out6OutputPosition = Vec(54.5, 241.4);
		auto out7OutputPosition = Vec(54.5, 282.7);
		auto out8OutputPosition = Vec(54.5, 324.0);

		auto out1LightPosition = Vec(66.5, 61.5);
		auto out2LightPosition = Vec(66.5, 102.8);
		auto out3LightPosition = Vec(66.5, 145.1);
		auto out4LightPosition = Vec(66.5, 185.4);
		auto out5LightPosition = Vec(66.5, 226.6);
		auto out6LightPosition = Vec(66.5, 267.9);
		auto out7LightPosition = Vec(66.5, 309.2);
		auto out8LightPosition = Vec(66.5, 350.5);
		// end generated by svg_widgets.rb

		addParam(createParam<Knob16>(stepsParamPosition, module, OneEight::STEPS_PARAM));
		addParam(createParam<SliderSwitch2State14>(directionParamPosition, module, OneEight::DIRECTION_PARAM));
		addParam(createParam<Knob29>(selectParamPosition, module, OneEight::SELECT_PARAM));

		addInput(createInput<Port24>(clockInputPosition, module, OneEight::CLOCK_INPUT));
		addInput(createInput<Port24>(resetInputPosition, module, OneEight::RESET_INPUT));
		addInput(createInput<Port24>(selectInputPosition, module, OneEight::SELECT_INPUT));
		addInput(createInput<Port24>(inInputPosition, module, OneEight::IN_INPUT));

		addOutput(createOutput<Port24>(out1OutputPosition, module, OneEight::OUT1_OUTPUT));
		addOutput(createOutput<Port24>(out2OutputPosition, module, OneEight::OUT2_OUTPUT));
		addOutput(createOutput<Port24>(out3OutputPosition, module, OneEight::OUT3_OUTPUT));
		addOutput(createOutput<Port24>(out4OutputPosition, module, OneEight::OUT4_OUTPUT));
		addOutput(createOutput<Port24>(out5OutputPosition, module, OneEight::OUT5_OUTPUT));
		addOutput(createOutput<Port24>(out6OutputPosition, module, OneEight::OUT6_OUTPUT));
		addOutput(createOutput<Port24>(out7OutputPosition, module, OneEight::OUT7_OUTPUT));
		addOutput(createOutput<Port24>(out8OutputPosition, module, OneEight::OUT8_OUTPUT));

		addChild(createLight<BGSmallLight<GreenLight>>(out1LightPosition, module, OneEight::OUT1_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out2LightPosition, module, OneEight::OUT2_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out3LightPosition, module, OneEight::OUT3_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out4LightPosition, module, OneEight::OUT4_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out5LightPosition, module, OneEight::OUT5_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out6LightPosition, module, OneEight::OUT6_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out7LightPosition, module, OneEight::OUT7_LIGHT));
		addChild(createLight<BGSmallLight<GreenLight>>(out8LightPosition, module, OneEight::OUT8_LIGHT));
	}
};

Model* modelOneEight = bogaudio::createModel<OneEight, OneEightWidget>("Bogaudio-OneEight", "1:8", "8-channel multiplexer & sequential switch", "Switch", "Polyphonic");
