package io.openems.edge.bridge.modbus;

import io.openems.edge.bridge.modbus.api.task.hooks.TaskHook;
import org.osgi.framework.Constants;

import io.openems.common.exceptions.OpenemsException;
import io.openems.common.test.DummyConfigurationAdmin;
import io.openems.common.test.DummyConfigurationAdmin.DummyConfiguration;
import io.openems.common.utils.ConfigUtils;
import io.openems.edge.bridge.modbus.api.AbstractModbusBridge;
import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent;
import io.openems.edge.bridge.modbus.api.ModbusComponent;
import io.openems.edge.bridge.modbus.api.ModbusProtocol;
import io.openems.edge.bridge.modbus.test.DummyModbusBridge;
import io.openems.edge.common.channel.Channel;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.test.DummyComponentContext;

import java.util.ArrayList;
import java.util.List;

public class DummyModbusComponent extends AbstractOpenemsModbusComponent implements ModbusComponent {

	public static final String DEFAULT_COMPONENT_ID = "device0";
	public static final String DEFAULT_BRIDGE_ID = "modbus0";
	public static final int DEFAULT_UNIT_ID = 1;

	private List<TaskHook> taskHooks = new ArrayList<>();

	public DummyModbusComponent() throws OpenemsException {
		this(DEFAULT_COMPONENT_ID, DEFAULT_BRIDGE_ID);
	}

	public DummyModbusComponent(String id, String bridgeId) throws OpenemsException {
		this(id, new DummyModbusBridge(bridgeId), DEFAULT_UNIT_ID, new io.openems.edge.common.channel.ChannelId[0]);
	}

	public DummyModbusComponent(String id, AbstractModbusBridge bridge, int unitId,
			io.openems.edge.common.channel.ChannelId[] additionalChannelIds) throws OpenemsException {
		super(//
				OpenemsComponent.ChannelId.values(), //
				ModbusComponent.ChannelId.values(), //
				additionalChannelIds //
		);
		for (Channel<?> channel : this.channels()) {
			channel.nextProcessImage();
		}
		this.setModbus(bridge);
		var context = new DummyComponentContext();
		context.addProperty(Constants.SERVICE_PID, Constants.SERVICE_PID);
		var cm = new DummyConfigurationAdmin();
		var dummyConfiguration = new DummyConfiguration();
		dummyConfiguration.addProperty("Modbus.target",
				ConfigUtils.generateReferenceTargetFilter(Constants.SERVICE_PID, bridge.id()));
		cm.addConfiguration(Constants.SERVICE_PID, dummyConfiguration);
		super.activate(context, id, "", true, unitId, cm, "Modbus", bridge.id());
	}

	protected ModbusProtocol defineModbusProtocol() {
		return new ModbusProtocol(this);
	}

	@Override
	public ModbusProtocol getModbusProtocol() {
		return super.getModbusProtocol();
	}

	@Override
	public Channel<?> addChannel(io.openems.edge.common.channel.ChannelId channelId) {
		return super.addChannel(channelId);
	}

	@Override
	public List<TaskHook> getModbusTaskHooks() {
		return this.taskHooks;
	}

	/**
	 * Adds a hook that is executed for all modbus tasks.
	 *
	 * @param hook Hook to add
	 */
	public void addModbusTaskHook(TaskHook hook) {
		this.taskHooks.add(hook);
	}
}
